2010-06-09 00:52:24 +08:00
|
|
|
//===-- ClangASTContext.cpp -------------------------------------*- C++ -*-===//
|
|
|
|
//
|
|
|
|
// The LLVM Compiler Infrastructure
|
|
|
|
//
|
|
|
|
// This file is distributed under the University of Illinois Open Source
|
|
|
|
// License. See LICENSE.TXT for details.
|
|
|
|
//
|
|
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
|
2010-06-14 03:06:42 +08:00
|
|
|
#include "lldb/Symbol/ClangASTContext.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
// C Includes
|
|
|
|
// C++ Includes
|
|
|
|
#include <string>
|
|
|
|
|
|
|
|
// Other libraries and framework includes
|
2010-07-09 02:16:16 +08:00
|
|
|
#define NDEBUG
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "clang/AST/ASTContext.h"
|
|
|
|
#include "clang/AST/ASTImporter.h"
|
|
|
|
#include "clang/AST/CXXInheritance.h"
|
2010-07-23 02:30:50 +08:00
|
|
|
#include "clang/AST/DeclObjC.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "clang/AST/RecordLayout.h"
|
|
|
|
#include "clang/AST/Type.h"
|
|
|
|
#include "clang/Basic/Builtins.h"
|
|
|
|
#include "clang/Basic/FileManager.h"
|
2010-11-18 10:56:27 +08:00
|
|
|
#include "clang/Basic/FileSystemOptions.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
#include "clang/Basic/SourceManager.h"
|
|
|
|
#include "clang/Basic/TargetInfo.h"
|
|
|
|
#include "clang/Basic/TargetOptions.h"
|
|
|
|
#include "clang/Frontend/FrontendOptions.h"
|
|
|
|
#include "clang/Frontend/LangStandard.h"
|
2010-07-09 02:16:16 +08:00
|
|
|
#undef NDEBUG
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
#include "lldb/Core/dwarf.h"
|
2010-10-27 11:32:59 +08:00
|
|
|
#include "lldb/Core/Flags.h"
|
2010-10-29 02:19:36 +08:00
|
|
|
#include "lldb/Core/Log.h"
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2010-06-14 03:06:42 +08:00
|
|
|
#include <stdio.h>
|
|
|
|
|
2010-08-05 09:57:25 +08:00
|
|
|
using namespace lldb;
|
2010-06-09 00:52:24 +08:00
|
|
|
using namespace lldb_private;
|
|
|
|
using namespace llvm;
|
|
|
|
using namespace clang;
|
|
|
|
|
2010-07-23 02:30:50 +08:00
|
|
|
static AccessSpecifier
|
2010-08-05 09:57:25 +08:00
|
|
|
ConvertAccessTypeToAccessSpecifier (AccessType access)
|
2010-07-23 02:30:50 +08:00
|
|
|
{
|
|
|
|
switch (access)
|
|
|
|
{
|
2010-08-05 09:57:25 +08:00
|
|
|
default: break;
|
|
|
|
case eAccessNone: return AS_none;
|
|
|
|
case eAccessPublic: return AS_public;
|
|
|
|
case eAccessPrivate: return AS_private;
|
|
|
|
case eAccessProtected: return AS_protected;
|
2010-07-23 02:30:50 +08:00
|
|
|
}
|
|
|
|
return AS_none;
|
|
|
|
}
|
|
|
|
|
|
|
|
static ObjCIvarDecl::AccessControl
|
2010-08-05 09:57:25 +08:00
|
|
|
ConvertAccessTypeToObjCIvarAccessControl (AccessType access)
|
2010-07-23 02:30:50 +08:00
|
|
|
{
|
|
|
|
switch (access)
|
|
|
|
{
|
2010-08-05 09:57:25 +08:00
|
|
|
default: break;
|
|
|
|
case eAccessNone: return ObjCIvarDecl::None;
|
|
|
|
case eAccessPublic: return ObjCIvarDecl::Public;
|
|
|
|
case eAccessPrivate: return ObjCIvarDecl::Private;
|
|
|
|
case eAccessProtected: return ObjCIvarDecl::Protected;
|
|
|
|
case eAccessPackage: return ObjCIvarDecl::Package;
|
2010-07-23 02:30:50 +08:00
|
|
|
}
|
|
|
|
return ObjCIvarDecl::None;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
static void
|
|
|
|
ParseLangArgs
|
|
|
|
(
|
|
|
|
LangOptions &Opts,
|
2010-06-14 01:34:29 +08:00
|
|
|
InputKind IK
|
2010-06-09 00:52:24 +08:00
|
|
|
)
|
|
|
|
{
|
|
|
|
// FIXME: Cleanup per-file based stuff.
|
|
|
|
|
|
|
|
// Set some properties which depend soley 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.
|
2010-06-14 01:34:29 +08:00
|
|
|
if (IK == IK_Asm) {
|
2010-06-09 00:52:24 +08:00
|
|
|
Opts.AsmPreprocessor = 1;
|
2010-06-14 01:34:29 +08:00
|
|
|
} else if (IK == IK_ObjC ||
|
|
|
|
IK == IK_ObjCXX ||
|
|
|
|
IK == IK_PreprocessedObjC ||
|
|
|
|
IK == IK_PreprocessedObjCXX) {
|
2010-06-09 00:52:24 +08:00
|
|
|
Opts.ObjC1 = Opts.ObjC2 = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
LangStandard::Kind LangStd = LangStandard::lang_unspecified;
|
|
|
|
|
|
|
|
if (LangStd == LangStandard::lang_unspecified) {
|
|
|
|
// Based on the base language, pick one.
|
|
|
|
switch (IK) {
|
2010-06-14 01:34:29 +08:00
|
|
|
case IK_None:
|
|
|
|
case IK_AST:
|
2010-06-09 00:52:24 +08:00
|
|
|
assert(0 && "Invalid input kind!");
|
2010-06-14 01:34:29 +08:00
|
|
|
case IK_OpenCL:
|
2010-06-09 00:52:24 +08:00
|
|
|
LangStd = LangStandard::lang_opencl;
|
|
|
|
break;
|
2010-06-14 01:34:29 +08:00
|
|
|
case IK_Asm:
|
|
|
|
case IK_C:
|
|
|
|
case IK_PreprocessedC:
|
|
|
|
case IK_ObjC:
|
|
|
|
case IK_PreprocessedObjC:
|
2010-06-09 00:52:24 +08:00
|
|
|
LangStd = LangStandard::lang_gnu99;
|
|
|
|
break;
|
2010-06-14 01:34:29 +08:00
|
|
|
case IK_CXX:
|
|
|
|
case IK_PreprocessedCXX:
|
|
|
|
case IK_ObjCXX:
|
|
|
|
case IK_PreprocessedObjCXX:
|
2010-06-09 00:52:24 +08:00
|
|
|
LangStd = LangStandard::lang_gnucxx98;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
const LangStandard &Std = LangStandard::getLangStandardForKind(LangStd);
|
|
|
|
Opts.BCPLComment = Std.hasBCPLComments();
|
|
|
|
Opts.C99 = Std.isC99();
|
|
|
|
Opts.CPlusPlus = Std.isCPlusPlus();
|
|
|
|
Opts.CPlusPlus0x = Std.isCPlusPlus0x();
|
|
|
|
Opts.Digraphs = Std.hasDigraphs();
|
|
|
|
Opts.GNUMode = Std.isGNUMode();
|
|
|
|
Opts.GNUInline = !Std.isC99();
|
|
|
|
Opts.HexFloats = Std.hasHexFloats();
|
|
|
|
Opts.ImplicitInt = Std.hasImplicitInt();
|
|
|
|
|
|
|
|
// OpenCL has some additional defaults.
|
|
|
|
if (LangStd == LangStandard::lang_opencl) {
|
|
|
|
Opts.OpenCL = 1;
|
|
|
|
Opts.AltiVec = 1;
|
|
|
|
Opts.CXXOperatorNames = 1;
|
|
|
|
Opts.LaxVectorConversions = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// OpenCL and C++ both have bool, true, false keywords.
|
|
|
|
Opts.Bool = Opts.OpenCL || Opts.CPlusPlus;
|
|
|
|
|
|
|
|
// if (Opts.CPlusPlus)
|
|
|
|
// Opts.CXXOperatorNames = !Args.hasArg(OPT_fno_operator_names);
|
|
|
|
//
|
|
|
|
// if (Args.hasArg(OPT_fobjc_gc_only))
|
|
|
|
// Opts.setGCMode(LangOptions::GCOnly);
|
|
|
|
// else if (Args.hasArg(OPT_fobjc_gc))
|
|
|
|
// Opts.setGCMode(LangOptions::HybridGC);
|
|
|
|
//
|
|
|
|
// if (Args.hasArg(OPT_print_ivar_layout))
|
|
|
|
// Opts.ObjCGCBitmapPrint = 1;
|
|
|
|
//
|
|
|
|
// if (Args.hasArg(OPT_faltivec))
|
|
|
|
// Opts.AltiVec = 1;
|
|
|
|
//
|
|
|
|
// if (Args.hasArg(OPT_pthread))
|
|
|
|
// Opts.POSIXThreads = 1;
|
|
|
|
//
|
|
|
|
// llvm::StringRef Vis = getLastArgValue(Args, OPT_fvisibility,
|
|
|
|
// "default");
|
|
|
|
// if (Vis == "default")
|
2010-10-30 02:38:40 +08:00
|
|
|
Opts.setVisibilityMode(DefaultVisibility);
|
2010-06-09 00:52:24 +08:00
|
|
|
// else if (Vis == "hidden")
|
|
|
|
// Opts.setVisibilityMode(LangOptions::Hidden);
|
|
|
|
// else if (Vis == "protected")
|
|
|
|
// Opts.setVisibilityMode(LangOptions::Protected);
|
|
|
|
// else
|
|
|
|
// Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
// << Args.getLastArg(OPT_fvisibility)->getAsString(Args) << Vis;
|
|
|
|
|
|
|
|
// Opts.OverflowChecking = Args.hasArg(OPT_ftrapv);
|
|
|
|
|
|
|
|
// Mimicing gcc's behavior, trigraphs are only enabled if -trigraphs
|
|
|
|
// is specified, or -std is set to a conforming mode.
|
|
|
|
Opts.Trigraphs = !Opts.GNUMode;
|
|
|
|
// if (Args.hasArg(OPT_trigraphs))
|
|
|
|
// Opts.Trigraphs = 1;
|
|
|
|
//
|
|
|
|
// Opts.DollarIdents = Args.hasFlag(OPT_fdollars_in_identifiers,
|
|
|
|
// OPT_fno_dollars_in_identifiers,
|
|
|
|
// !Opts.AsmPreprocessor);
|
|
|
|
// Opts.PascalStrings = Args.hasArg(OPT_fpascal_strings);
|
|
|
|
// Opts.Microsoft = Args.hasArg(OPT_fms_extensions);
|
|
|
|
// Opts.WritableStrings = Args.hasArg(OPT_fwritable_strings);
|
|
|
|
// if (Args.hasArg(OPT_fno_lax_vector_conversions))
|
|
|
|
// Opts.LaxVectorConversions = 0;
|
|
|
|
// Opts.Exceptions = Args.hasArg(OPT_fexceptions);
|
|
|
|
// Opts.RTTI = !Args.hasArg(OPT_fno_rtti);
|
|
|
|
// Opts.Blocks = Args.hasArg(OPT_fblocks);
|
|
|
|
// Opts.CharIsSigned = !Args.hasArg(OPT_fno_signed_char);
|
|
|
|
// Opts.ShortWChar = Args.hasArg(OPT_fshort_wchar);
|
|
|
|
// Opts.Freestanding = Args.hasArg(OPT_ffreestanding);
|
|
|
|
// Opts.NoBuiltin = Args.hasArg(OPT_fno_builtin) || Opts.Freestanding;
|
|
|
|
// Opts.AssumeSaneOperatorNew = !Args.hasArg(OPT_fno_assume_sane_operator_new);
|
|
|
|
// Opts.HeinousExtensions = Args.hasArg(OPT_fheinous_gnu_extensions);
|
|
|
|
// Opts.AccessControl = Args.hasArg(OPT_faccess_control);
|
|
|
|
// Opts.ElideConstructors = !Args.hasArg(OPT_fno_elide_constructors);
|
|
|
|
// Opts.MathErrno = !Args.hasArg(OPT_fno_math_errno);
|
|
|
|
// Opts.InstantiationDepth = getLastArgIntValue(Args, OPT_ftemplate_depth, 99,
|
|
|
|
// Diags);
|
|
|
|
// Opts.NeXTRuntime = !Args.hasArg(OPT_fgnu_runtime);
|
|
|
|
// Opts.ObjCConstantStringClass = getLastArgValue(Args,
|
|
|
|
// OPT_fconstant_string_class);
|
|
|
|
// Opts.ObjCNonFragileABI = Args.hasArg(OPT_fobjc_nonfragile_abi);
|
|
|
|
// Opts.CatchUndefined = Args.hasArg(OPT_fcatch_undefined_behavior);
|
|
|
|
// Opts.EmitAllDecls = Args.hasArg(OPT_femit_all_decls);
|
|
|
|
// Opts.PICLevel = getLastArgIntValue(Args, OPT_pic_level, 0, Diags);
|
|
|
|
// Opts.Static = Args.hasArg(OPT_static_define);
|
|
|
|
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.NoInline = !Opt;
|
|
|
|
|
|
|
|
// unsigned SSP = getLastArgIntValue(Args, OPT_stack_protector, 0, Diags);
|
|
|
|
// switch (SSP) {
|
|
|
|
// default:
|
|
|
|
// Diags.Report(diag::err_drv_invalid_value)
|
|
|
|
// << Args.getLastArg(OPT_stack_protector)->getAsString(Args) << SSP;
|
|
|
|
// break;
|
|
|
|
// case 0: Opts.setStackProtectorMode(LangOptions::SSPOff); break;
|
|
|
|
// case 1: Opts.setStackProtectorMode(LangOptions::SSPOn); break;
|
|
|
|
// case 2: Opts.setStackProtectorMode(LangOptions::SSPReq); break;
|
|
|
|
// }
|
|
|
|
}
|
|
|
|
|
2010-07-02 09:29:13 +08:00
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
ClangASTContext::ClangASTContext(const char *target_triple) :
|
|
|
|
m_target_triple(),
|
|
|
|
m_ast_context_ap(),
|
|
|
|
m_language_options_ap(),
|
|
|
|
m_source_manager_ap(),
|
|
|
|
m_diagnostic_ap(),
|
|
|
|
m_target_options_ap(),
|
|
|
|
m_target_info_ap(),
|
|
|
|
m_identifier_table_ap(),
|
|
|
|
m_selector_table_ap(),
|
|
|
|
m_builtins_ap()
|
|
|
|
{
|
|
|
|
if (target_triple && target_triple[0])
|
|
|
|
m_target_triple.assign (target_triple);
|
|
|
|
}
|
|
|
|
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
// Destructor
|
|
|
|
//----------------------------------------------------------------------
|
|
|
|
ClangASTContext::~ClangASTContext()
|
|
|
|
{
|
|
|
|
m_builtins_ap.reset();
|
|
|
|
m_selector_table_ap.reset();
|
|
|
|
m_identifier_table_ap.reset();
|
|
|
|
m_target_info_ap.reset();
|
|
|
|
m_target_options_ap.reset();
|
|
|
|
m_diagnostic_ap.reset();
|
|
|
|
m_source_manager_ap.reset();
|
|
|
|
m_language_options_ap.reset();
|
|
|
|
m_ast_context_ap.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void
|
|
|
|
ClangASTContext::Clear()
|
|
|
|
{
|
|
|
|
m_ast_context_ap.reset();
|
|
|
|
m_language_options_ap.reset();
|
|
|
|
m_source_manager_ap.reset();
|
|
|
|
m_diagnostic_ap.reset();
|
|
|
|
m_target_options_ap.reset();
|
|
|
|
m_target_info_ap.reset();
|
|
|
|
m_identifier_table_ap.reset();
|
|
|
|
m_selector_table_ap.reset();
|
|
|
|
m_builtins_ap.reset();
|
|
|
|
}
|
|
|
|
|
|
|
|
const char *
|
|
|
|
ClangASTContext::GetTargetTriple ()
|
|
|
|
{
|
|
|
|
return m_target_triple.c_str();
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ClangASTContext::SetTargetTriple (const char *target_triple)
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
m_target_triple.assign(target_triple);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
ASTContext *
|
|
|
|
ClangASTContext::getASTContext()
|
|
|
|
{
|
|
|
|
if (m_ast_context_ap.get() == NULL)
|
|
|
|
{
|
|
|
|
m_ast_context_ap.reset(
|
|
|
|
new ASTContext(
|
|
|
|
*getLanguageOptions(),
|
|
|
|
*getSourceManager(),
|
|
|
|
*getTargetInfo(),
|
|
|
|
*getIdentifierTable(),
|
|
|
|
*getSelectorTable(),
|
2010-07-31 04:30:44 +08:00
|
|
|
*getBuiltinContext(),
|
|
|
|
0));
|
2010-12-11 08:08:56 +08:00
|
|
|
|
|
|
|
m_ast_context_ap->getDiagnostics().setClient(getDiagnosticClient(), false);
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
return m_ast_context_ap.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
Builtin::Context *
|
|
|
|
ClangASTContext::getBuiltinContext()
|
|
|
|
{
|
|
|
|
if (m_builtins_ap.get() == NULL)
|
|
|
|
m_builtins_ap.reset (new Builtin::Context(*getTargetInfo()));
|
|
|
|
return m_builtins_ap.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
IdentifierTable *
|
|
|
|
ClangASTContext::getIdentifierTable()
|
|
|
|
{
|
|
|
|
if (m_identifier_table_ap.get() == NULL)
|
|
|
|
m_identifier_table_ap.reset(new IdentifierTable (*ClangASTContext::getLanguageOptions(), NULL));
|
|
|
|
return m_identifier_table_ap.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
LangOptions *
|
|
|
|
ClangASTContext::getLanguageOptions()
|
|
|
|
{
|
|
|
|
if (m_language_options_ap.get() == NULL)
|
|
|
|
{
|
|
|
|
m_language_options_ap.reset(new LangOptions());
|
2010-06-14 01:34:29 +08:00
|
|
|
ParseLangArgs(*m_language_options_ap, IK_ObjCXX);
|
|
|
|
// InitializeLangOptions(*m_language_options_ap, IK_ObjCXX);
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
return m_language_options_ap.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
SelectorTable *
|
|
|
|
ClangASTContext::getSelectorTable()
|
|
|
|
{
|
|
|
|
if (m_selector_table_ap.get() == NULL)
|
|
|
|
m_selector_table_ap.reset (new SelectorTable());
|
|
|
|
return m_selector_table_ap.get();
|
|
|
|
}
|
|
|
|
|
2010-11-18 10:56:27 +08:00
|
|
|
clang::FileManager *
|
|
|
|
ClangASTContext::getFileManager()
|
|
|
|
{
|
|
|
|
if (m_file_manager_ap.get() == NULL)
|
2010-12-03 07:20:03 +08:00
|
|
|
{
|
|
|
|
clang::FileSystemOptions file_system_options;
|
|
|
|
m_file_manager_ap.reset(new clang::FileManager(file_system_options));
|
|
|
|
}
|
2010-11-18 10:56:27 +08:00
|
|
|
return m_file_manager_ap.get();
|
|
|
|
}
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
clang::SourceManager *
|
2010-06-09 00:52:24 +08:00
|
|
|
ClangASTContext::getSourceManager()
|
|
|
|
{
|
|
|
|
if (m_source_manager_ap.get() == NULL)
|
2010-12-03 07:20:03 +08:00
|
|
|
m_source_manager_ap.reset(new clang::SourceManager(*getDiagnostic(), *getFileManager()));
|
2010-06-09 00:52:24 +08:00
|
|
|
return m_source_manager_ap.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
Diagnostic *
|
|
|
|
ClangASTContext::getDiagnostic()
|
|
|
|
{
|
|
|
|
if (m_diagnostic_ap.get() == NULL)
|
2010-11-20 05:46:54 +08:00
|
|
|
{
|
|
|
|
llvm::IntrusiveRefCntPtr<DiagnosticIDs> diag_id_sp(new DiagnosticIDs());
|
|
|
|
m_diagnostic_ap.reset(new Diagnostic(diag_id_sp));
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
return m_diagnostic_ap.get();
|
|
|
|
}
|
|
|
|
|
2010-12-11 08:08:56 +08:00
|
|
|
class NullDiagnosticClient : public DiagnosticClient
|
|
|
|
{
|
|
|
|
public:
|
|
|
|
NullDiagnosticClient ()
|
|
|
|
{
|
|
|
|
m_log = lldb_private::GetLogIfAllCategoriesSet (LIBLLDB_LOG_EXPRESSIONS);
|
|
|
|
}
|
|
|
|
|
|
|
|
void HandleDiagnostic (Diagnostic::Level DiagLevel, const DiagnosticInfo &info)
|
|
|
|
{
|
|
|
|
if (m_log)
|
|
|
|
{
|
|
|
|
llvm::SmallVectorImpl<char> diag_str(10);
|
|
|
|
info.FormatDiagnostic(diag_str);
|
|
|
|
diag_str.push_back('\0');
|
|
|
|
m_log->Printf("Compiler diagnostic: %s\n", diag_str.data());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
private:
|
|
|
|
LogSP m_log;
|
|
|
|
};
|
|
|
|
|
|
|
|
DiagnosticClient *
|
|
|
|
ClangASTContext::getDiagnosticClient()
|
|
|
|
{
|
|
|
|
if (m_diagnostic_client_ap.get() == NULL)
|
|
|
|
m_diagnostic_client_ap.reset(new NullDiagnosticClient);
|
|
|
|
|
|
|
|
return m_diagnostic_client_ap.get();
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
TargetOptions *
|
|
|
|
ClangASTContext::getTargetOptions()
|
|
|
|
{
|
|
|
|
if (m_target_options_ap.get() == NULL && !m_target_triple.empty())
|
|
|
|
{
|
|
|
|
m_target_options_ap.reset (new TargetOptions());
|
|
|
|
if (m_target_options_ap.get())
|
|
|
|
m_target_options_ap->Triple = m_target_triple;
|
|
|
|
}
|
|
|
|
return m_target_options_ap.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
TargetInfo *
|
|
|
|
ClangASTContext::getTargetInfo()
|
|
|
|
{
|
|
|
|
// target_triple should be something like "x86_64-apple-darwin10"
|
|
|
|
if (m_target_info_ap.get() == NULL && !m_target_triple.empty())
|
|
|
|
m_target_info_ap.reset (TargetInfo::CreateTargetInfo(*getDiagnostic(), *getTargetOptions()));
|
|
|
|
return m_target_info_ap.get();
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark Basic Types
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
QualTypeMatchesBitSize(const uint64_t bit_size, ASTContext *ast_context, QualType qual_type)
|
|
|
|
{
|
|
|
|
uint64_t qual_type_bit_size = ast_context->getTypeSize(qual_type);
|
|
|
|
if (qual_type_bit_size == bit_size)
|
|
|
|
return true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-08-05 09:57:25 +08:00
|
|
|
ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (Encoding encoding, uint32_t bit_size)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
|
|
|
|
return GetBuiltinTypeForEncodingAndBitSize (ast_context, encoding, bit_size);
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::GetBuiltinTypeForEncodingAndBitSize (ASTContext *ast_context, Encoding encoding, uint32_t bit_size)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (!ast_context)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
switch (encoding)
|
|
|
|
{
|
2010-08-05 09:57:25 +08:00
|
|
|
case eEncodingInvalid:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy))
|
|
|
|
return ast_context->VoidPtrTy.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
2010-08-05 09:57:25 +08:00
|
|
|
case eEncodingUint:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
|
|
|
|
return ast_context->UnsignedCharTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy))
|
|
|
|
return ast_context->UnsignedShortTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy))
|
|
|
|
return ast_context->UnsignedIntTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy))
|
|
|
|
return ast_context->UnsignedLongTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy))
|
|
|
|
return ast_context->UnsignedLongLongTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty))
|
|
|
|
return ast_context->UnsignedInt128Ty.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
2010-08-05 09:57:25 +08:00
|
|
|
case eEncodingSint:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy))
|
|
|
|
return ast_context->CharTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy))
|
|
|
|
return ast_context->ShortTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy))
|
|
|
|
return ast_context->IntTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy))
|
|
|
|
return ast_context->LongTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy))
|
|
|
|
return ast_context->LongLongTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty))
|
|
|
|
return ast_context->Int128Ty.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
2010-08-05 09:57:25 +08:00
|
|
|
case eEncodingIEEE754:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy))
|
|
|
|
return ast_context->FloatTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy))
|
|
|
|
return ast_context->DoubleTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy))
|
|
|
|
return ast_context->LongDoubleTy.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
2010-08-05 09:57:25 +08:00
|
|
|
case eEncodingVector:
|
2010-06-09 00:52:24 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-06-09 00:52:24 +08:00
|
|
|
ClangASTContext::GetBuiltinTypeForDWARFEncodingAndBitSize (const char *type_name, uint32_t dw_ate, uint32_t bit_size)
|
|
|
|
{
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
|
|
|
|
#define streq(a,b) strcmp(a,b) == 0
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
if (ast_context)
|
|
|
|
{
|
|
|
|
switch (dw_ate)
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DW_ATE_address:
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->VoidPtrTy))
|
|
|
|
return ast_context->VoidPtrTy.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DW_ATE_boolean:
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->BoolTy))
|
|
|
|
return ast_context->BoolTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
|
|
|
|
return ast_context->UnsignedCharTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy))
|
|
|
|
return ast_context->UnsignedShortTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy))
|
|
|
|
return ast_context->UnsignedIntTy.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DW_ATE_complex_float:
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatComplexTy))
|
|
|
|
return ast_context->FloatComplexTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleComplexTy))
|
|
|
|
return ast_context->DoubleComplexTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleComplexTy))
|
|
|
|
return ast_context->LongDoubleComplexTy.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DW_ATE_float:
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->FloatTy))
|
|
|
|
return ast_context->FloatTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->DoubleTy))
|
|
|
|
return ast_context->DoubleTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongDoubleTy))
|
|
|
|
return ast_context->LongDoubleTy.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DW_ATE_signed:
|
|
|
|
if (type_name)
|
|
|
|
{
|
2010-11-02 11:48:39 +08:00
|
|
|
if (strstr(type_name, "long long"))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-11-02 11:48:39 +08:00
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy))
|
|
|
|
return ast_context->LongLongTy.getAsOpaquePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2010-11-02 11:48:39 +08:00
|
|
|
else if (strstr(type_name, "long"))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy))
|
|
|
|
return ast_context->LongTy.getAsOpaquePtr();
|
|
|
|
}
|
2010-11-02 11:48:39 +08:00
|
|
|
else if (strstr(type_name, "short"))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy))
|
|
|
|
return ast_context->ShortTy.getAsOpaquePtr();
|
|
|
|
}
|
2010-11-02 11:48:39 +08:00
|
|
|
else if (strstr(type_name, "char"))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy))
|
|
|
|
return ast_context->CharTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy))
|
|
|
|
return ast_context->SignedCharTy.getAsOpaquePtr();
|
|
|
|
}
|
2010-11-02 11:48:39 +08:00
|
|
|
else if (strstr(type_name, "int"))
|
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy))
|
|
|
|
return ast_context->IntTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty))
|
|
|
|
return ast_context->Int128Ty.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
else if (streq(type_name, "wchar_t"))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->WCharTy))
|
|
|
|
return ast_context->WCharTy.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// We weren't able to match up a type name, just search by size
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy))
|
|
|
|
return ast_context->CharTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->ShortTy))
|
|
|
|
return ast_context->ShortTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->IntTy))
|
|
|
|
return ast_context->IntTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongTy))
|
|
|
|
return ast_context->LongTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->LongLongTy))
|
|
|
|
return ast_context->LongLongTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->Int128Ty))
|
|
|
|
return ast_context->Int128Ty.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DW_ATE_signed_char:
|
|
|
|
if (type_name)
|
|
|
|
{
|
|
|
|
if (streq(type_name, "signed char"))
|
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy))
|
|
|
|
return ast_context->SignedCharTy.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->CharTy))
|
|
|
|
return ast_context->CharTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->SignedCharTy))
|
|
|
|
return ast_context->SignedCharTy.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DW_ATE_unsigned:
|
|
|
|
if (type_name)
|
|
|
|
{
|
2010-11-02 11:48:39 +08:00
|
|
|
if (strstr(type_name, "long long"))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-11-02 11:48:39 +08:00
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy))
|
|
|
|
return ast_context->UnsignedLongLongTy.getAsOpaquePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2010-11-02 11:48:39 +08:00
|
|
|
else if (strstr(type_name, "long"))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy))
|
|
|
|
return ast_context->UnsignedLongTy.getAsOpaquePtr();
|
|
|
|
}
|
2010-11-02 11:48:39 +08:00
|
|
|
else if (strstr(type_name, "short"))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy))
|
|
|
|
return ast_context->UnsignedShortTy.getAsOpaquePtr();
|
|
|
|
}
|
2010-11-02 11:48:39 +08:00
|
|
|
else if (strstr(type_name, "char"))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
|
|
|
|
return ast_context->UnsignedCharTy.getAsOpaquePtr();
|
|
|
|
}
|
2010-11-02 11:48:39 +08:00
|
|
|
else if (strstr(type_name, "int"))
|
|
|
|
{
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy))
|
|
|
|
return ast_context->UnsignedIntTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty))
|
|
|
|
return ast_context->UnsignedInt128Ty.getAsOpaquePtr();
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
// We weren't able to match up a type name, just search by size
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
|
|
|
|
return ast_context->UnsignedCharTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedShortTy))
|
|
|
|
return ast_context->UnsignedShortTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedIntTy))
|
|
|
|
return ast_context->UnsignedIntTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongTy))
|
|
|
|
return ast_context->UnsignedLongTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedLongLongTy))
|
|
|
|
return ast_context->UnsignedLongLongTy.getAsOpaquePtr();
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedInt128Ty))
|
|
|
|
return ast_context->UnsignedInt128Ty.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DW_ATE_unsigned_char:
|
|
|
|
if (QualTypeMatchesBitSize (bit_size, ast_context, ast_context->UnsignedCharTy))
|
|
|
|
return ast_context->UnsignedCharTy.getAsOpaquePtr();
|
|
|
|
break;
|
|
|
|
|
|
|
|
case DW_ATE_imaginary_float:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// This assert should fire for anything that we don't catch above so we know
|
|
|
|
// to fix any issues we run into.
|
|
|
|
assert (!"error: ClangASTContext::GetClangTypeForDWARFEncodingAndSize() contains an unhandled encoding. Fix this ASAP!");
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::GetBuiltInType_void(ASTContext *ast_context)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-09-17 10:24:29 +08:00
|
|
|
return ast_context->VoidTy.getAsOpaquePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2010-11-19 10:52:21 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::GetBuiltInType_bool()
|
|
|
|
{
|
|
|
|
return getASTContext()->BoolTy.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-08-03 08:35:52 +08:00
|
|
|
ClangASTContext::GetBuiltInType_objc_id()
|
|
|
|
{
|
2010-12-07 07:53:20 +08:00
|
|
|
return getASTContext()->getPointerType(getASTContext()->ObjCBuiltinIdTy).getAsOpaquePtr();
|
2010-08-03 08:35:52 +08:00
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-08-03 08:35:52 +08:00
|
|
|
ClangASTContext::GetBuiltInType_objc_Class()
|
|
|
|
{
|
2010-10-25 08:29:48 +08:00
|
|
|
return getASTContext()->ObjCBuiltinClassTy.getAsOpaquePtr();
|
2010-08-03 08:35:52 +08:00
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-08-03 08:35:52 +08:00
|
|
|
ClangASTContext::GetBuiltInType_objc_selector()
|
|
|
|
{
|
2010-12-07 07:53:20 +08:00
|
|
|
return getASTContext()->getPointerType(getASTContext()->ObjCBuiltinSelTy).getAsOpaquePtr();
|
2010-08-03 08:35:52 +08:00
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-06-09 00:52:24 +08:00
|
|
|
ClangASTContext::GetCStringType (bool is_const)
|
|
|
|
{
|
|
|
|
QualType char_type(getASTContext()->CharTy);
|
|
|
|
|
|
|
|
if (is_const)
|
|
|
|
char_type.addConst();
|
|
|
|
|
|
|
|
return getASTContext()->getPointerType(char_type).getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-06-09 00:52:24 +08:00
|
|
|
ClangASTContext::GetVoidPtrType (bool is_const)
|
|
|
|
{
|
|
|
|
return GetVoidPtrType(getASTContext(), is_const);
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::GetVoidPtrType (ASTContext *ast_context, bool is_const)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
QualType void_ptr_type(ast_context->VoidPtrTy);
|
|
|
|
|
|
|
|
if (is_const)
|
|
|
|
void_ptr_type.addConst();
|
|
|
|
|
|
|
|
return void_ptr_type.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-12-03 07:20:03 +08:00
|
|
|
ClangASTContext::CopyType (ASTContext *dst_ast,
|
|
|
|
ASTContext *src_ast,
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-11-18 10:56:27 +08:00
|
|
|
FileSystemOptions file_system_options;
|
2010-12-03 07:20:03 +08:00
|
|
|
FileManager file_manager (file_system_options);
|
|
|
|
ASTImporter importer(*dst_ast, file_manager,
|
|
|
|
*src_ast, file_manager);
|
2010-11-10 06:37:10 +08:00
|
|
|
|
2010-12-03 07:20:03 +08:00
|
|
|
QualType src (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
QualType dst (importer.Import(src));
|
2010-11-10 06:37:10 +08:00
|
|
|
|
|
|
|
return dst.getAsOpaquePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
2010-11-13 11:52:47 +08:00
|
|
|
|
|
|
|
clang::Decl *
|
2010-12-03 07:20:03 +08:00
|
|
|
ClangASTContext::CopyDecl (ASTContext *dst_ast,
|
|
|
|
ASTContext *src_ast,
|
2010-11-13 11:52:47 +08:00
|
|
|
clang::Decl *source_decl)
|
2010-12-11 08:08:56 +08:00
|
|
|
{
|
2010-11-18 10:56:27 +08:00
|
|
|
FileSystemOptions file_system_options;
|
2010-12-03 07:20:03 +08:00
|
|
|
FileManager file_manager (file_system_options);
|
|
|
|
ASTImporter importer(*dst_ast, file_manager,
|
|
|
|
*src_ast, file_manager);
|
2010-11-13 11:52:47 +08:00
|
|
|
|
|
|
|
return importer.Import(source_decl);
|
|
|
|
}
|
|
|
|
|
2010-07-16 08:00:27 +08:00
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::AreTypesSame(ASTContext *ast_context,
|
|
|
|
clang_type_t type1,
|
|
|
|
clang_type_t type2)
|
2010-07-16 06:30:52 +08:00
|
|
|
{
|
|
|
|
return ast_context->hasSameType(QualType::getFromOpaquePtr(type1),
|
|
|
|
QualType::getFromOpaquePtr(type2));
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
#pragma mark CVR modifiers
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::AddConstModifier (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType result(QualType::getFromOpaquePtr(clang_type));
|
|
|
|
result.addConst();
|
|
|
|
return result.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::AddRestrictModifier (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType result(QualType::getFromOpaquePtr(clang_type));
|
|
|
|
result.getQualifiers().setRestrict (true);
|
|
|
|
return result.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::AddVolatileModifier (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType result(QualType::getFromOpaquePtr(clang_type));
|
|
|
|
result.getQualifiers().setVolatile (true);
|
|
|
|
return result.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark Structure, Unions, Classes
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-08-05 09:57:25 +08:00
|
|
|
ClangASTContext::CreateRecordType (const char *name, int kind, DeclContext *decl_ctx, LanguageType language)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
assert (ast_context != NULL);
|
2010-10-25 08:29:48 +08:00
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
if (decl_ctx == NULL)
|
|
|
|
decl_ctx = ast_context->getTranslationUnitDecl();
|
|
|
|
|
2010-07-28 10:04:09 +08:00
|
|
|
|
2010-08-05 09:57:25 +08:00
|
|
|
if (language == eLanguageTypeObjC)
|
2010-07-28 10:04:09 +08:00
|
|
|
{
|
2010-10-11 10:25:34 +08:00
|
|
|
bool isForwardDecl = true;
|
2010-07-28 10:04:09 +08:00
|
|
|
bool isInternal = false;
|
|
|
|
return CreateObjCClass (name, decl_ctx, isForwardDecl, isInternal);
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
// 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.
|
|
|
|
CXXRecordDecl *decl = CXXRecordDecl::Create(*ast_context,
|
|
|
|
(TagDecl::TagKind)kind,
|
|
|
|
decl_ctx,
|
|
|
|
SourceLocation(),
|
|
|
|
name && name[0] ? &ast_context->Idents.get(name) : NULL);
|
|
|
|
|
|
|
|
return ast_context->getTagDeclType(decl).getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
|
2010-10-02 07:13:49 +08:00
|
|
|
static bool
|
|
|
|
IsOperator (const char *name, OverloadedOperatorKind &op_kind)
|
|
|
|
{
|
|
|
|
if (name == NULL || name[0] == '\0')
|
|
|
|
return false;
|
|
|
|
|
2010-12-11 03:51:54 +08:00
|
|
|
#define OPERATOR_PREFIX "operator"
|
2010-12-14 10:59:59 +08:00
|
|
|
#define OPERATOR_PREFIX_LENGTH (sizeof (OPERATOR_PREFIX) - 1)
|
2010-12-10 10:15:55 +08:00
|
|
|
|
|
|
|
const char *post_op_name = NULL;
|
|
|
|
|
2010-12-11 03:51:54 +08:00
|
|
|
bool no_space = true;
|
2010-12-10 10:15:55 +08:00
|
|
|
|
2010-12-14 10:59:59 +08:00
|
|
|
if (::strncmp(name, OPERATOR_PREFIX, OPERATOR_PREFIX_LENGTH))
|
2010-12-11 03:51:54 +08:00
|
|
|
return false;
|
|
|
|
|
2010-12-14 10:59:59 +08:00
|
|
|
post_op_name = name + OPERATOR_PREFIX_LENGTH;
|
|
|
|
|
2010-12-11 03:51:54 +08:00
|
|
|
if (post_op_name[0] == ' ')
|
2010-12-10 10:15:55 +08:00
|
|
|
{
|
2010-12-11 03:51:54 +08:00
|
|
|
post_op_name++;
|
|
|
|
no_space = false;
|
2010-12-10 10:15:55 +08:00
|
|
|
}
|
|
|
|
|
2010-12-11 03:51:54 +08:00
|
|
|
#undef OPERATOR_PREFIX
|
2010-12-14 10:59:59 +08:00
|
|
|
#undef OPERATOR_PREFIX_LENGTH
|
2010-10-02 07:13:49 +08:00
|
|
|
|
|
|
|
// This is an operator, set the overloaded operator kind to invalid
|
|
|
|
// in case this is a conversion operator...
|
|
|
|
op_kind = NUM_OVERLOADED_OPERATORS;
|
|
|
|
|
|
|
|
switch (post_op_name[0])
|
|
|
|
{
|
2010-12-10 10:15:55 +08:00
|
|
|
default:
|
|
|
|
if (no_space)
|
|
|
|
return false;
|
|
|
|
break;
|
2010-10-02 07:13:49 +08:00
|
|
|
case 'n':
|
2010-12-10 10:15:55 +08:00
|
|
|
if (no_space)
|
|
|
|
return false;
|
2010-10-02 07:13:49 +08:00
|
|
|
if (strcmp (post_op_name, "new") == 0)
|
|
|
|
op_kind = OO_New;
|
|
|
|
else if (strcmp (post_op_name, "new[]") == 0)
|
|
|
|
op_kind = OO_Array_New;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case 'd':
|
2010-12-10 10:15:55 +08:00
|
|
|
if (no_space)
|
|
|
|
return false;
|
2010-10-02 07:13:49 +08:00
|
|
|
if (strcmp (post_op_name, "delete") == 0)
|
|
|
|
op_kind = OO_Delete;
|
|
|
|
else if (strcmp (post_op_name, "delete[]") == 0)
|
|
|
|
op_kind = OO_Array_Delete;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '+':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Plus;
|
|
|
|
else if (post_op_name[2] == '\0')
|
|
|
|
{
|
|
|
|
if (post_op_name[1] == '=')
|
|
|
|
op_kind = OO_PlusEqual;
|
|
|
|
else if (post_op_name[1] == '+')
|
|
|
|
op_kind = OO_PlusPlus;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '-':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Minus;
|
|
|
|
else if (post_op_name[2] == '\0')
|
|
|
|
{
|
|
|
|
switch (post_op_name[1])
|
|
|
|
{
|
|
|
|
case '=': op_kind = OO_MinusEqual; break;
|
|
|
|
case '-': op_kind = OO_MinusMinus; break;
|
|
|
|
case '>': op_kind = OO_Arrow; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (post_op_name[3] == '\0')
|
|
|
|
{
|
|
|
|
if (post_op_name[2] == '*')
|
|
|
|
op_kind = OO_ArrowStar; break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '*':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Star;
|
|
|
|
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
|
|
|
|
op_kind = OO_StarEqual;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '/':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Slash;
|
|
|
|
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
|
|
|
|
op_kind = OO_SlashEqual;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '%':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Percent;
|
|
|
|
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
|
|
|
|
op_kind = OO_PercentEqual;
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
|
|
case '^':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Caret;
|
|
|
|
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
|
|
|
|
op_kind = OO_CaretEqual;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '&':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Amp;
|
|
|
|
else if (post_op_name[2] == '\0')
|
|
|
|
{
|
|
|
|
switch (post_op_name[1])
|
|
|
|
{
|
|
|
|
case '=': op_kind = OO_AmpEqual; break;
|
|
|
|
case '&': op_kind = OO_AmpAmp; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '|':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Pipe;
|
|
|
|
else if (post_op_name[2] == '\0')
|
|
|
|
{
|
|
|
|
switch (post_op_name[1])
|
|
|
|
{
|
|
|
|
case '=': op_kind = OO_PipeEqual; break;
|
|
|
|
case '|': op_kind = OO_PipePipe; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '~':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Tilde;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '!':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Exclaim;
|
|
|
|
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
|
|
|
|
op_kind = OO_ExclaimEqual;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '=':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Equal;
|
|
|
|
else if (post_op_name[1] == '=' && post_op_name[2] == '\0')
|
|
|
|
op_kind = OO_EqualEqual;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '<':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Less;
|
|
|
|
else if (post_op_name[2] == '\0')
|
|
|
|
{
|
|
|
|
switch (post_op_name[1])
|
|
|
|
{
|
|
|
|
case '<': op_kind = OO_LessLess; break;
|
|
|
|
case '=': op_kind = OO_LessEqual; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (post_op_name[3] == '\0')
|
|
|
|
{
|
|
|
|
if (post_op_name[2] == '=')
|
|
|
|
op_kind = OO_LessLessEqual;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '>':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Greater;
|
|
|
|
else if (post_op_name[2] == '\0')
|
|
|
|
{
|
|
|
|
switch (post_op_name[1])
|
|
|
|
{
|
|
|
|
case '>': op_kind = OO_GreaterGreater; break;
|
|
|
|
case '=': op_kind = OO_GreaterEqual; break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (post_op_name[1] == '>' &&
|
|
|
|
post_op_name[2] == '=' &&
|
|
|
|
post_op_name[3] == '\0')
|
|
|
|
{
|
|
|
|
op_kind = OO_GreaterGreaterEqual;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case ',':
|
|
|
|
if (post_op_name[1] == '\0')
|
|
|
|
op_kind = OO_Comma;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '(':
|
|
|
|
if (post_op_name[1] == ')' && post_op_name[2] == '\0')
|
|
|
|
op_kind = OO_Call;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case '[':
|
|
|
|
if (post_op_name[1] == ']' && post_op_name[2] == '\0')
|
|
|
|
op_kind = OO_Subscript;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
2010-09-23 09:09:21 +08:00
|
|
|
CXXMethodDecl *
|
2010-09-17 10:58:26 +08:00
|
|
|
ClangASTContext::AddMethodToCXXRecordType
|
|
|
|
(
|
2010-09-29 09:12:09 +08:00
|
|
|
ASTContext *ast_context,
|
|
|
|
clang_type_t record_opaque_type,
|
2010-09-23 09:09:21 +08:00
|
|
|
const char *name,
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t method_opaque_type,
|
2010-09-23 09:09:21 +08:00
|
|
|
lldb::AccessType access,
|
2010-09-24 13:15:53 +08:00
|
|
|
bool is_virtual,
|
|
|
|
bool is_static,
|
2010-10-01 10:31:07 +08:00
|
|
|
bool is_inline,
|
|
|
|
bool is_explicit
|
2010-09-23 09:09:21 +08:00
|
|
|
)
|
2010-09-17 10:58:26 +08:00
|
|
|
{
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 08:44:12 +08:00
|
|
|
if (!record_opaque_type || !method_opaque_type || !name)
|
2010-09-29 00:10:54 +08:00
|
|
|
return NULL;
|
2010-09-17 10:58:26 +08:00
|
|
|
|
|
|
|
assert(ast_context);
|
|
|
|
|
|
|
|
IdentifierTable *identifier_table = &ast_context->Idents;
|
|
|
|
|
|
|
|
assert(identifier_table);
|
|
|
|
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 08:44:12 +08:00
|
|
|
QualType record_qual_type(QualType::getFromOpaquePtr(record_opaque_type));
|
2010-09-24 13:15:53 +08:00
|
|
|
|
|
|
|
clang::Type *clang_type(record_qual_type.getTypePtr());
|
2010-09-17 10:58:26 +08:00
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
if (clang_type == NULL)
|
2010-09-23 09:09:21 +08:00
|
|
|
return NULL;
|
2010-09-17 10:58:26 +08:00
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
RecordType *record_clang_type(dyn_cast<RecordType>(clang_type));
|
2010-09-17 10:58:26 +08:00
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
if (record_clang_type == NULL)
|
2010-09-23 09:09:21 +08:00
|
|
|
return NULL;
|
2010-09-17 10:58:26 +08:00
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
RecordDecl *record_decl = record_clang_type->getDecl();
|
2010-09-17 10:58:26 +08:00
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
if (record_decl == NULL)
|
2010-09-23 09:09:21 +08:00
|
|
|
return NULL;
|
2010-09-17 10:58:26 +08:00
|
|
|
|
|
|
|
CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
|
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
if (cxx_record_decl == NULL)
|
2010-09-23 09:09:21 +08:00
|
|
|
return NULL;
|
2010-09-17 10:58:26 +08:00
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
QualType method_qual_type (QualType::getFromOpaquePtr (method_opaque_type));
|
|
|
|
|
2010-10-01 10:31:07 +08:00
|
|
|
CXXMethodDecl *cxx_method_decl = NULL;
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 08:44:12 +08:00
|
|
|
|
2010-10-01 10:31:07 +08:00
|
|
|
DeclarationName decl_name (&identifier_table->get(name));
|
2010-10-01 11:45:20 +08:00
|
|
|
|
|
|
|
const bool is_implicitly_declared = false;
|
|
|
|
|
2010-10-02 09:40:05 +08:00
|
|
|
clang::FunctionType *function_Type = dyn_cast<FunctionType>(method_qual_type.getTypePtr());
|
2010-10-01 11:45:20 +08:00
|
|
|
|
2010-10-02 09:40:05 +08:00
|
|
|
if (function_Type == NULL)
|
2010-10-01 11:45:20 +08:00
|
|
|
return NULL;
|
|
|
|
|
2010-10-02 09:40:05 +08:00
|
|
|
FunctionProtoType *method_function_prototype (dyn_cast<FunctionProtoType>(function_Type));
|
2010-10-01 10:31:07 +08:00
|
|
|
|
2010-10-01 11:45:20 +08:00
|
|
|
if (!method_function_prototype)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
unsigned int num_params = method_function_prototype->getNumArgs();
|
|
|
|
|
|
|
|
if (name[0] == '~')
|
|
|
|
{
|
|
|
|
cxx_method_decl = CXXDestructorDecl::Create (*ast_context,
|
|
|
|
cxx_record_decl,
|
2010-10-02 09:40:05 +08:00
|
|
|
DeclarationNameInfo (ast_context->DeclarationNames.getCXXDestructorName (ast_context->getCanonicalType (record_qual_type)), SourceLocation()),
|
2010-10-01 11:45:20 +08:00
|
|
|
method_qual_type,
|
2010-10-30 02:38:40 +08:00
|
|
|
NULL,
|
2010-10-01 11:45:20 +08:00
|
|
|
is_inline,
|
|
|
|
is_implicitly_declared);
|
|
|
|
}
|
|
|
|
else if (decl_name == record_decl->getDeclName())
|
2010-10-01 10:31:07 +08:00
|
|
|
{
|
|
|
|
cxx_method_decl = CXXConstructorDecl::Create (*ast_context,
|
|
|
|
cxx_record_decl,
|
2010-10-02 09:40:05 +08:00
|
|
|
DeclarationNameInfo (ast_context->DeclarationNames.getCXXConstructorName (ast_context->getCanonicalType (record_qual_type)), SourceLocation()),
|
2010-10-01 10:31:07 +08:00
|
|
|
method_qual_type,
|
|
|
|
NULL, // TypeSourceInfo *
|
|
|
|
is_explicit,
|
|
|
|
is_inline,
|
|
|
|
is_implicitly_declared);
|
|
|
|
}
|
|
|
|
else
|
2010-10-01 11:45:20 +08:00
|
|
|
{
|
2010-10-02 07:13:49 +08:00
|
|
|
|
|
|
|
OverloadedOperatorKind op_kind = NUM_OVERLOADED_OPERATORS;
|
|
|
|
if (IsOperator (name, op_kind))
|
2010-10-01 11:45:20 +08:00
|
|
|
{
|
2010-10-02 07:13:49 +08:00
|
|
|
if (op_kind != NUM_OVERLOADED_OPERATORS)
|
|
|
|
{
|
|
|
|
cxx_method_decl = CXXMethodDecl::Create (*ast_context,
|
2010-10-01 11:45:20 +08:00
|
|
|
cxx_record_decl,
|
2010-10-02 07:13:49 +08:00
|
|
|
DeclarationNameInfo (ast_context->DeclarationNames.getCXXOperatorName (op_kind), SourceLocation()),
|
2010-10-01 11:45:20 +08:00
|
|
|
method_qual_type,
|
|
|
|
NULL, // TypeSourceInfo *
|
2010-10-02 07:13:49 +08:00
|
|
|
is_static,
|
|
|
|
SC_None,
|
|
|
|
is_inline);
|
|
|
|
}
|
|
|
|
else if (num_params == 0)
|
|
|
|
{
|
|
|
|
// Conversion operators don't take params...
|
|
|
|
cxx_method_decl = CXXConversionDecl::Create (*ast_context,
|
|
|
|
cxx_record_decl,
|
2010-10-02 09:40:05 +08:00
|
|
|
DeclarationNameInfo (ast_context->DeclarationNames.getCXXConversionFunctionName (ast_context->getCanonicalType (function_Type->getResultType())), SourceLocation()),
|
2010-10-02 07:13:49 +08:00
|
|
|
method_qual_type,
|
|
|
|
NULL, // TypeSourceInfo *
|
|
|
|
is_inline,
|
|
|
|
is_explicit);
|
|
|
|
}
|
2010-10-01 11:45:20 +08:00
|
|
|
}
|
2010-10-02 07:13:49 +08:00
|
|
|
|
|
|
|
if (cxx_method_decl == NULL)
|
2010-10-01 11:45:20 +08:00
|
|
|
{
|
|
|
|
cxx_method_decl = CXXMethodDecl::Create (*ast_context,
|
|
|
|
cxx_record_decl,
|
2010-10-02 07:13:49 +08:00
|
|
|
DeclarationNameInfo (decl_name, SourceLocation()),
|
2010-10-01 11:45:20 +08:00
|
|
|
method_qual_type,
|
|
|
|
NULL, // TypeSourceInfo *
|
|
|
|
is_static,
|
|
|
|
SC_None,
|
|
|
|
is_inline);
|
|
|
|
}
|
2010-10-01 10:31:07 +08:00
|
|
|
}
|
2010-10-02 07:13:49 +08:00
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
AccessSpecifier access_specifier = ConvertAccessTypeToAccessSpecifier (access);
|
2010-09-23 11:01:22 +08:00
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
cxx_method_decl->setAccess (access_specifier);
|
|
|
|
cxx_method_decl->setVirtualAsWritten (is_virtual);
|
2010-09-23 11:01:22 +08:00
|
|
|
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 08:44:12 +08:00
|
|
|
// Populate the method decl with parameter decls
|
|
|
|
|
|
|
|
ParmVarDecl *params[num_params];
|
|
|
|
|
|
|
|
for (int param_index = 0;
|
|
|
|
param_index < num_params;
|
|
|
|
++param_index)
|
|
|
|
{
|
2010-09-24 13:15:53 +08:00
|
|
|
params[param_index] = ParmVarDecl::Create (*ast_context,
|
|
|
|
cxx_method_decl,
|
|
|
|
SourceLocation(),
|
|
|
|
NULL, // anonymous
|
|
|
|
method_function_prototype->getArgType(param_index),
|
|
|
|
NULL,
|
|
|
|
SC_None,
|
|
|
|
SC_None,
|
|
|
|
NULL);
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 08:44:12 +08:00
|
|
|
}
|
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
cxx_method_decl->setParams (params, num_params);
|
Removed the hacky "#define this ___clang_this" handler
for C++ classes. Replaced it with a less hacky approach:
- If an expression is defined in the context of a
method of class A, then that expression is wrapped as
___clang_class::___clang_expr(void*) { ... }
instead of ___clang_expr(void*) { ... }.
- ___clang_class is resolved as the type of the target
of the "this" pointer in the method the expression
is defined in.
- When reporting the type of ___clang_class, a method
with the signature ___clang_expr(void*) is added to
that class, so that Clang doesn't complain about a
method being defined without a corresponding
declaration.
- Whenever the expression gets called, "this" gets
looked up, type-checked, and then passed in as the
first argument.
This required the following changes:
- The ABIs were changed to support passing of the "this"
pointer as part of trivial calls.
- ThreadPlanCallFunction and ClangFunction were changed
to support passing of an optional "this" pointer.
- ClangUserExpression was extended to perform the
wrapping described above.
- ClangASTSource was changed to revert the changes
required by the hack.
- ClangExpressionParser, IRForTarget, and
ClangExpressionDeclMap were changed to handle
different manglings of ___clang_expr flexibly. This
meant no longer searching for a function called
___clang_expr, but rather looking for a function whose
name *contains* ___clang_expr.
- ClangExpressionParser and ClangExpressionDeclMap now
remember whether "this" is required, and know how to
look it up as necessary.
A few inheritance bugs remain, and I'm trying to resolve
these. But it is now possible to use "this" as well as
refer implicitly to member variables, when in the proper
context.
llvm-svn: 114384
2010-09-21 08:44:12 +08:00
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
cxx_record_decl->addDecl (cxx_method_decl);
|
2010-09-17 10:58:26 +08:00
|
|
|
|
2010-09-23 09:09:21 +08:00
|
|
|
return cxx_method_decl;
|
2010-09-17 10:58:26 +08:00
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
bool
|
2010-07-23 02:30:50 +08:00
|
|
|
ClangASTContext::AddFieldToRecordType
|
|
|
|
(
|
2010-09-29 09:12:09 +08:00
|
|
|
ASTContext *ast_context,
|
|
|
|
clang_type_t record_clang_type,
|
2010-07-23 02:30:50 +08:00
|
|
|
const char *name,
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t field_type,
|
2010-07-23 02:30:50 +08:00
|
|
|
AccessType access,
|
|
|
|
uint32_t bitfield_bit_size
|
|
|
|
)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (record_clang_type == NULL || field_type == NULL)
|
|
|
|
return false;
|
|
|
|
|
2010-09-17 04:01:08 +08:00
|
|
|
IdentifierTable *identifier_table = &ast_context->Idents;
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
assert (identifier_table != NULL);
|
|
|
|
|
|
|
|
QualType record_qual_type(QualType::getFromOpaquePtr(record_clang_type));
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
clang::Type *clang_type = record_qual_type.getTypePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
const RecordType *record_type = dyn_cast<RecordType>(clang_type);
|
|
|
|
|
|
|
|
if (record_type)
|
|
|
|
{
|
|
|
|
RecordDecl *record_decl = record_type->getDecl();
|
|
|
|
|
|
|
|
clang::Expr *bit_width = NULL;
|
|
|
|
if (bitfield_bit_size != 0)
|
|
|
|
{
|
|
|
|
APInt bitfield_bit_size_apint(ast_context->getTypeSize(ast_context->IntTy), bitfield_bit_size);
|
2010-09-23 11:01:22 +08:00
|
|
|
bit_width = new (*ast_context)IntegerLiteral (*ast_context, bitfield_bit_size_apint, ast_context->IntTy, SourceLocation());
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2010-07-23 02:30:50 +08:00
|
|
|
FieldDecl *field = FieldDecl::Create (*ast_context,
|
|
|
|
record_decl,
|
|
|
|
SourceLocation(),
|
|
|
|
name ? &identifier_table->get(name) : NULL, // Identifier
|
|
|
|
QualType::getFromOpaquePtr(field_type), // Field type
|
|
|
|
NULL, // DeclaratorInfo *
|
|
|
|
bit_width, // BitWidth
|
|
|
|
false); // Mutable
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2010-07-23 02:30:50 +08:00
|
|
|
field->setAccess (ConvertAccessTypeToAccessSpecifier (access));
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
if (field)
|
|
|
|
{
|
|
|
|
record_decl->addDecl(field);
|
|
|
|
}
|
|
|
|
}
|
2010-07-28 10:04:09 +08:00
|
|
|
else
|
|
|
|
{
|
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(clang_type);
|
|
|
|
if (objc_class_type)
|
|
|
|
{
|
2010-09-24 13:15:53 +08:00
|
|
|
bool is_synthesized = false;
|
2010-09-17 04:01:08 +08:00
|
|
|
ClangASTContext::AddObjCClassIVar (ast_context,
|
|
|
|
record_clang_type,
|
2010-07-28 10:04:09 +08:00
|
|
|
name,
|
|
|
|
field_type,
|
|
|
|
access,
|
|
|
|
bitfield_bit_size,
|
2010-09-24 13:15:53 +08:00
|
|
|
is_synthesized);
|
2010-07-28 10:04:09 +08:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ClangASTContext::FieldIsBitfield (FieldDecl* field, uint32_t& bitfield_bit_size)
|
|
|
|
{
|
|
|
|
return FieldIsBitfield(getASTContext(), field, bitfield_bit_size);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ClangASTContext::FieldIsBitfield
|
|
|
|
(
|
|
|
|
ASTContext *ast_context,
|
|
|
|
FieldDecl* field,
|
|
|
|
uint32_t& bitfield_bit_size
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (ast_context == NULL || field == NULL)
|
|
|
|
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_context))
|
|
|
|
{
|
|
|
|
bitfield_bit_size = bit_width_apsint.getLimitedValue(UINT32_MAX);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ClangASTContext::RecordHasFields (const RecordDecl *record_decl)
|
|
|
|
{
|
|
|
|
if (record_decl == NULL)
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::SetDefaultAccessForRecordFields (clang_type_t clang_qual_type, int default_accessibility, int *assigned_accessibilities, size_t num_assigned_accessibilities)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_qual_type)
|
|
|
|
{
|
|
|
|
QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type));
|
2010-07-22 06:12:05 +08:00
|
|
|
clang::Type *clang_type = qual_type.getTypePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
RecordType *record_type = dyn_cast<RecordType>(clang_type);
|
|
|
|
if (record_type)
|
|
|
|
{
|
|
|
|
RecordDecl *record_decl = record_type->getDecl();
|
|
|
|
if (record_decl)
|
|
|
|
{
|
|
|
|
uint32_t field_idx;
|
|
|
|
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 ((AccessSpecifier)default_accessibility);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark C++ Base Classes
|
|
|
|
|
|
|
|
CXXBaseSpecifier *
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::CreateBaseClassSpecifier (clang_type_t base_class_type, AccessType access, bool is_virtual, bool base_of_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (base_class_type)
|
2010-07-31 04:30:44 +08:00
|
|
|
return new CXXBaseSpecifier (SourceRange(),
|
|
|
|
is_virtual,
|
|
|
|
base_of_class,
|
|
|
|
ConvertAccessTypeToAccessSpecifier (access),
|
|
|
|
getASTContext()->CreateTypeSourceInfo (QualType::getFromOpaquePtr(base_class_type)));
|
2010-06-09 00:52:24 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-07-02 09:29:13 +08:00
|
|
|
void
|
|
|
|
ClangASTContext::DeleteBaseClassSpecifiers (CXXBaseSpecifier **base_classes, unsigned num_base_classes)
|
|
|
|
{
|
|
|
|
for (unsigned i=0; i<num_base_classes; ++i)
|
|
|
|
{
|
|
|
|
delete base_classes[i];
|
|
|
|
base_classes[i] = NULL;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::SetBaseClassesForClassType (clang_type_t class_clang_type, CXXBaseSpecifier const * const *base_classes, unsigned num_base_classes)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (class_clang_type)
|
|
|
|
{
|
2010-07-22 06:12:05 +08:00
|
|
|
clang::Type *clang_type = QualType::getFromOpaquePtr(class_clang_type).getTypePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
RecordType *record_type = dyn_cast<RecordType>(clang_type);
|
|
|
|
if (record_type)
|
|
|
|
{
|
|
|
|
CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_type->getDecl());
|
|
|
|
if (cxx_record_decl)
|
|
|
|
{
|
|
|
|
cxx_record_decl->setBases(base_classes, num_base_classes);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2010-07-23 02:30:50 +08:00
|
|
|
#pragma mark Objective C Classes
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-07-23 02:30:50 +08:00
|
|
|
ClangASTContext::CreateObjCClass
|
|
|
|
(
|
|
|
|
const char *name,
|
|
|
|
DeclContext *decl_ctx,
|
|
|
|
bool isForwardDecl,
|
|
|
|
bool isInternal
|
|
|
|
)
|
|
|
|
{
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
assert (name && name[0]);
|
|
|
|
if (decl_ctx == NULL)
|
|
|
|
decl_ctx = ast_context->getTranslationUnitDecl();
|
|
|
|
|
|
|
|
// 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.
|
|
|
|
ObjCInterfaceDecl *decl = ObjCInterfaceDecl::Create (*ast_context,
|
|
|
|
decl_ctx,
|
|
|
|
SourceLocation(),
|
|
|
|
&ast_context->Idents.get(name),
|
|
|
|
SourceLocation(),
|
|
|
|
isForwardDecl,
|
|
|
|
isInternal);
|
2010-07-28 10:04:09 +08:00
|
|
|
|
|
|
|
return ast_context->getObjCInterfaceType(decl).getAsOpaquePtr();
|
2010-07-23 02:30:50 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2010-07-23 02:30:50 +08:00
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::SetObjCSuperClass (clang_type_t class_opaque_type, clang_type_t super_opaque_type)
|
2010-07-23 02:30:50 +08:00
|
|
|
{
|
|
|
|
if (class_opaque_type && super_opaque_type)
|
|
|
|
{
|
|
|
|
QualType class_qual_type(QualType::getFromOpaquePtr(class_opaque_type));
|
|
|
|
QualType super_qual_type(QualType::getFromOpaquePtr(super_opaque_type));
|
|
|
|
clang::Type *class_type = class_qual_type.getTypePtr();
|
|
|
|
clang::Type *super_type = super_qual_type.getTypePtr();
|
|
|
|
if (class_type && super_type)
|
|
|
|
{
|
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(class_type);
|
|
|
|
ObjCObjectType *objc_super_type = dyn_cast<ObjCObjectType>(super_type);
|
|
|
|
if (objc_class_type && objc_super_type)
|
|
|
|
{
|
|
|
|
ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
|
|
|
ObjCInterfaceDecl *super_interface_decl = objc_super_type->getInterface();
|
|
|
|
if (class_interface_decl && super_interface_decl)
|
|
|
|
{
|
|
|
|
class_interface_decl->setSuperClass(super_interface_decl);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
bool
|
|
|
|
ClangASTContext::AddObjCClassIVar
|
|
|
|
(
|
2010-09-29 09:12:09 +08:00
|
|
|
ASTContext *ast_context,
|
|
|
|
clang_type_t class_opaque_type,
|
2010-07-23 02:30:50 +08:00
|
|
|
const char *name,
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t ivar_opaque_type,
|
2010-07-23 02:30:50 +08:00
|
|
|
AccessType access,
|
|
|
|
uint32_t bitfield_bit_size,
|
2010-09-24 13:15:53 +08:00
|
|
|
bool is_synthesized
|
2010-07-23 02:30:50 +08:00
|
|
|
)
|
|
|
|
{
|
|
|
|
if (class_opaque_type == NULL || ivar_opaque_type == NULL)
|
|
|
|
return false;
|
|
|
|
|
2010-09-17 04:01:08 +08:00
|
|
|
IdentifierTable *identifier_table = &ast_context->Idents;
|
2010-07-23 02:30:50 +08:00
|
|
|
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
assert (identifier_table != NULL);
|
|
|
|
|
|
|
|
QualType class_qual_type(QualType::getFromOpaquePtr(class_opaque_type));
|
|
|
|
|
|
|
|
clang::Type *class_type = class_qual_type.getTypePtr();
|
|
|
|
if (class_type)
|
|
|
|
{
|
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(class_type);
|
|
|
|
|
|
|
|
if (objc_class_type)
|
|
|
|
{
|
|
|
|
ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
|
|
|
|
|
|
|
if (class_interface_decl)
|
|
|
|
{
|
|
|
|
clang::Expr *bit_width = NULL;
|
|
|
|
if (bitfield_bit_size != 0)
|
|
|
|
{
|
|
|
|
APInt bitfield_bit_size_apint(ast_context->getTypeSize(ast_context->IntTy), bitfield_bit_size);
|
2010-09-23 11:01:22 +08:00
|
|
|
bit_width = new (*ast_context)IntegerLiteral (*ast_context, bitfield_bit_size_apint, ast_context->IntTy, SourceLocation());
|
2010-07-23 02:30:50 +08:00
|
|
|
}
|
|
|
|
|
2010-07-28 10:04:09 +08:00
|
|
|
ObjCIvarDecl *field = ObjCIvarDecl::Create (*ast_context,
|
|
|
|
class_interface_decl,
|
|
|
|
SourceLocation(),
|
|
|
|
&identifier_table->get(name), // Identifier
|
|
|
|
QualType::getFromOpaquePtr(ivar_opaque_type), // Field type
|
|
|
|
NULL, // TypeSourceInfo *
|
|
|
|
ConvertAccessTypeToObjCIvarAccessControl (access),
|
|
|
|
bit_width,
|
2010-09-24 13:15:53 +08:00
|
|
|
is_synthesized);
|
2010-07-28 10:04:09 +08:00
|
|
|
|
|
|
|
if (field)
|
|
|
|
{
|
|
|
|
class_interface_decl->addDecl(field);
|
|
|
|
return true;
|
|
|
|
}
|
2010-07-23 02:30:50 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2010-07-28 10:04:09 +08:00
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::ObjCTypeHasIVars (clang_type_t class_opaque_type, bool check_superclass)
|
2010-07-28 10:04:09 +08:00
|
|
|
{
|
|
|
|
QualType class_qual_type(QualType::getFromOpaquePtr(class_opaque_type));
|
|
|
|
|
|
|
|
clang::Type *class_type = class_qual_type.getTypePtr();
|
|
|
|
if (class_type)
|
|
|
|
{
|
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(class_type);
|
|
|
|
|
|
|
|
if (objc_class_type)
|
|
|
|
return ObjCDeclHasIVars (objc_class_type->getInterface(), check_superclass);
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
|
|
|
ClangASTContext::ObjCDeclHasIVars (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;
|
|
|
|
}
|
2010-09-24 13:15:53 +08:00
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
ObjCMethodDecl *
|
2010-09-24 13:15:53 +08:00
|
|
|
ClangASTContext::AddMethodToObjCObjectType
|
|
|
|
(
|
2010-09-29 09:12:09 +08:00
|
|
|
ASTContext *ast_context,
|
|
|
|
clang_type_t class_opaque_type,
|
2010-09-24 13:15:53 +08:00
|
|
|
const char *name, // the full symbol name as seen in the symbol table ("-[NString stringWithCString:]")
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t method_opaque_type,
|
2010-09-24 13:15:53 +08:00
|
|
|
lldb::AccessType access
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (class_opaque_type == NULL || method_opaque_type == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
IdentifierTable *identifier_table = &ast_context->Idents;
|
|
|
|
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
assert (identifier_table != NULL);
|
|
|
|
|
|
|
|
QualType class_qual_type(QualType::getFromOpaquePtr(class_opaque_type));
|
|
|
|
|
|
|
|
clang::Type *class_type = class_qual_type.getTypePtr();
|
|
|
|
if (class_type == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(class_type);
|
|
|
|
|
|
|
|
if (objc_class_type == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
|
|
|
|
|
|
|
if (class_interface_decl == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
const char *selector_start = ::strchr (name, ' ');
|
|
|
|
if (selector_start == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
selector_start++;
|
|
|
|
if (!(::isalpha (selector_start[0]) || selector_start[0] == '_'))
|
|
|
|
return NULL;
|
|
|
|
llvm::SmallVector<IdentifierInfo *, 12> selector_idents;
|
|
|
|
|
2010-10-12 10:24:53 +08:00
|
|
|
size_t len = 0;
|
2010-09-24 13:15:53 +08:00
|
|
|
const char *start;
|
2010-10-12 10:24:53 +08:00
|
|
|
//printf ("name = '%s'\n", name);
|
|
|
|
|
|
|
|
unsigned num_selectors_with_args = 0;
|
|
|
|
for (start = selector_start;
|
2010-09-24 13:15:53 +08:00
|
|
|
start && *start != '\0' && *start != ']';
|
2010-10-12 10:24:53 +08:00
|
|
|
start += len)
|
2010-09-24 13:15:53 +08:00
|
|
|
{
|
2010-10-12 10:24:53 +08:00
|
|
|
len = ::strcspn(start, ":]");
|
2010-10-27 12:01:14 +08:00
|
|
|
bool has_arg = (start[len] == ':');
|
|
|
|
if (has_arg)
|
2010-10-12 10:24:53 +08:00
|
|
|
++num_selectors_with_args;
|
2010-09-24 13:15:53 +08:00
|
|
|
selector_idents.push_back (&identifier_table->get (StringRef (start, len)));
|
2010-10-27 12:01:14 +08:00
|
|
|
if (has_arg)
|
|
|
|
len += 1;
|
2010-09-24 13:15:53 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (selector_idents.size() == 0)
|
|
|
|
return 0;
|
|
|
|
|
2010-10-12 10:24:53 +08:00
|
|
|
clang::Selector method_selector = ast_context->Selectors.getSelector (num_selectors_with_args ? selector_idents.size() : 0,
|
2010-09-24 13:15:53 +08:00
|
|
|
selector_idents.data());
|
|
|
|
|
|
|
|
QualType method_qual_type (QualType::getFromOpaquePtr (method_opaque_type));
|
|
|
|
|
|
|
|
// Populate the method decl with parameter decls
|
|
|
|
clang::Type *method_type(method_qual_type.getTypePtr());
|
|
|
|
|
|
|
|
if (method_type == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
FunctionProtoType *method_function_prototype (dyn_cast<FunctionProtoType>(method_type));
|
|
|
|
|
|
|
|
if (!method_function_prototype)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
|
|
|
|
bool is_variadic = false;
|
|
|
|
bool is_synthesized = false;
|
|
|
|
bool is_defined = false;
|
|
|
|
ObjCMethodDecl::ImplementationControl imp_control = ObjCMethodDecl::None;
|
|
|
|
|
|
|
|
const unsigned num_args = method_function_prototype->getNumArgs();
|
|
|
|
|
|
|
|
ObjCMethodDecl *objc_method_decl = ObjCMethodDecl::Create (*ast_context,
|
|
|
|
SourceLocation(), // beginLoc,
|
|
|
|
SourceLocation(), // endLoc,
|
|
|
|
method_selector,
|
|
|
|
method_function_prototype->getResultType(),
|
|
|
|
NULL, // TypeSourceInfo *ResultTInfo,
|
|
|
|
GetDeclContextForType (class_opaque_type),
|
|
|
|
name[0] == '-',
|
|
|
|
is_variadic,
|
|
|
|
is_synthesized,
|
|
|
|
is_defined,
|
|
|
|
imp_control,
|
|
|
|
num_args);
|
|
|
|
|
|
|
|
|
|
|
|
if (objc_method_decl == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (num_args > 0)
|
|
|
|
{
|
|
|
|
llvm::SmallVector<ParmVarDecl *, 12> params;
|
|
|
|
|
|
|
|
for (int param_index = 0; param_index < num_args; ++param_index)
|
|
|
|
{
|
|
|
|
params.push_back (ParmVarDecl::Create (*ast_context,
|
|
|
|
objc_method_decl,
|
|
|
|
SourceLocation(),
|
|
|
|
NULL, // anonymous
|
|
|
|
method_function_prototype->getArgType(param_index),
|
|
|
|
NULL,
|
|
|
|
SC_Auto,
|
|
|
|
SC_Auto,
|
|
|
|
NULL));
|
|
|
|
}
|
|
|
|
|
|
|
|
objc_method_decl->setMethodParams(*ast_context, params.data(), params.size(), num_args);
|
|
|
|
}
|
2010-07-28 10:04:09 +08:00
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
class_interface_decl->addDecl (objc_method_decl);
|
|
|
|
|
|
|
|
|
|
|
|
return objc_method_decl;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
uint32_t
|
2010-10-27 11:32:59 +08:00
|
|
|
ClangASTContext::GetTypeInfo
|
|
|
|
(
|
|
|
|
clang_type_t clang_type,
|
|
|
|
clang::ASTContext *ast_context,
|
|
|
|
clang_type_t *pointee_or_element_clang_type
|
|
|
|
)
|
2010-10-15 06:52:14 +08:00
|
|
|
{
|
|
|
|
if (clang_type == NULL)
|
2010-10-27 11:32:59 +08:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
if (pointee_or_element_clang_type)
|
|
|
|
*pointee_or_element_clang_type = NULL;
|
2010-10-15 06:52:14 +08:00
|
|
|
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
|
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
|
|
|
{
|
2010-10-25 08:29:48 +08:00
|
|
|
case clang::Type::Builtin:
|
|
|
|
switch (cast<clang::BuiltinType>(qual_type)->getKind())
|
|
|
|
{
|
|
|
|
case clang::BuiltinType::ObjCId:
|
|
|
|
case clang::BuiltinType::ObjCClass:
|
2010-10-27 11:32:59 +08:00
|
|
|
if (ast_context && pointee_or_element_clang_type)
|
|
|
|
*pointee_or_element_clang_type = ast_context->ObjCBuiltinClassTy.getAsOpaquePtr();
|
2010-10-25 08:29:48 +08:00
|
|
|
return eTypeIsBuiltIn | eTypeIsPointer | eTypeHasValue;
|
2010-10-27 11:32:59 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2010-10-25 08:29:48 +08:00
|
|
|
}
|
|
|
|
return eTypeIsBuiltIn | eTypeHasValue;
|
2010-10-27 11:32:59 +08:00
|
|
|
|
|
|
|
case clang::Type::BlockPointer:
|
|
|
|
if (pointee_or_element_clang_type)
|
|
|
|
*pointee_or_element_clang_type = qual_type->getPointeeType().getAsOpaquePtr();
|
|
|
|
return eTypeIsPointer | eTypeHasChildren | eTypeIsBlock;
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
case clang::Type::Complex: return eTypeHasChildren | eTypeIsBuiltIn | eTypeHasValue;
|
2010-10-27 11:32:59 +08:00
|
|
|
|
|
|
|
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 = cast<ArrayType>(qual_type.getTypePtr())->getElementType().getAsOpaquePtr();
|
|
|
|
return eTypeHasChildren | eTypeIsArray;
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
case clang::Type::DependentName: return 0;
|
|
|
|
case clang::Type::DependentSizedExtVector: return eTypeHasChildren | eTypeIsVector;
|
|
|
|
case clang::Type::DependentTemplateSpecialization: return eTypeIsTemplate;
|
|
|
|
case clang::Type::Decltype: return 0;
|
2010-10-27 11:32:59 +08:00
|
|
|
|
|
|
|
case clang::Type::Enum:
|
|
|
|
if (pointee_or_element_clang_type)
|
|
|
|
*pointee_or_element_clang_type = cast<EnumType>(qual_type)->getDecl()->getIntegerType().getAsOpaquePtr();
|
|
|
|
return eTypeIsEnumeration | eTypeHasValue;
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
case clang::Type::Elaborated: return 0;
|
|
|
|
case clang::Type::ExtVector: return eTypeHasChildren | eTypeIsVector;
|
|
|
|
case clang::Type::FunctionProto: return eTypeIsFuncPrototype | eTypeHasValue;
|
|
|
|
case clang::Type::FunctionNoProto: return eTypeIsFuncPrototype | eTypeHasValue;
|
|
|
|
case clang::Type::InjectedClassName: return 0;
|
2010-10-27 11:32:59 +08:00
|
|
|
|
|
|
|
case clang::Type::LValueReference:
|
|
|
|
case clang::Type::RValueReference:
|
|
|
|
if (pointee_or_element_clang_type)
|
|
|
|
*pointee_or_element_clang_type = cast<ReferenceType>(qual_type.getTypePtr())->getPointeeType().getAsOpaquePtr();
|
|
|
|
return eTypeHasChildren | eTypeIsReference | eTypeHasValue;
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
case clang::Type::MemberPointer: return eTypeIsPointer | eTypeIsMember | eTypeHasValue;
|
2010-10-27 11:32:59 +08:00
|
|
|
|
|
|
|
case clang::Type::ObjCObjectPointer:
|
|
|
|
if (pointee_or_element_clang_type)
|
|
|
|
*pointee_or_element_clang_type = qual_type->getPointeeType().getAsOpaquePtr();
|
|
|
|
return eTypeHasChildren | eTypeIsObjC | eTypeIsClass | eTypeIsPointer | eTypeHasValue;
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
case clang::Type::ObjCObject: return eTypeHasChildren | eTypeIsObjC | eTypeIsClass;
|
|
|
|
case clang::Type::ObjCInterface: return eTypeHasChildren | eTypeIsObjC | eTypeIsClass;
|
2010-10-27 11:32:59 +08:00
|
|
|
|
|
|
|
case clang::Type::Pointer:
|
|
|
|
if (pointee_or_element_clang_type)
|
|
|
|
*pointee_or_element_clang_type = qual_type->getPointeeType().getAsOpaquePtr();
|
|
|
|
return eTypeHasChildren | eTypeIsPointer | eTypeHasValue;
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
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;
|
2010-10-27 11:32:59 +08:00
|
|
|
|
|
|
|
case clang::Type::Typedef:
|
2010-12-13 09:26:27 +08:00
|
|
|
return eTypeIsTypedef | ClangASTContext::GetTypeInfo (cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(),
|
2010-10-27 11:32:59 +08:00
|
|
|
ast_context,
|
|
|
|
pointee_or_element_clang_type);
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
case clang::Type::TypeOfExpr: return 0;
|
|
|
|
case clang::Type::TypeOf: return 0;
|
|
|
|
case clang::Type::UnresolvedUsing: return 0;
|
|
|
|
case clang::Type::Vector: return eTypeHasChildren | eTypeIsVector;
|
|
|
|
default: return 0;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2010-07-28 10:04:09 +08:00
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
#pragma mark Aggregate Types
|
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsAggregateType (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
|
2010-09-13 11:32:57 +08:00
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::IncompleteArray:
|
|
|
|
case clang::Type::VariableArray:
|
|
|
|
case clang::Type::ConstantArray:
|
|
|
|
case clang::Type::ExtVector:
|
|
|
|
case clang::Type::Vector:
|
|
|
|
case clang::Type::Record:
|
2010-07-28 10:04:09 +08:00
|
|
|
case clang::Type::ObjCObject:
|
|
|
|
case clang::Type::ObjCInterface:
|
2010-06-09 00:52:24 +08:00
|
|
|
return true;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Typedef:
|
2010-12-13 09:26:27 +08:00
|
|
|
return ClangASTContext::IsAggregateType (cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr());
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
// The clang type does have a value
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
uint32_t
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::GetNumChildren (clang_type_t clang_qual_type, bool omit_empty_base_classes)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_qual_type == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
uint32_t num_children = 0;
|
|
|
|
QualType qual_type(QualType::getFromOpaquePtr(clang_qual_type));
|
2010-07-28 10:04:09 +08:00
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-08-03 08:35:52 +08:00
|
|
|
case clang::Type::Builtin:
|
|
|
|
switch (cast<clang::BuiltinType>(qual_type)->getKind())
|
|
|
|
{
|
2010-10-27 11:32:59 +08:00
|
|
|
case clang::BuiltinType::ObjCId: // child is Class
|
2010-08-03 08:35:52 +08:00
|
|
|
case clang::BuiltinType::ObjCClass: // child is Class
|
|
|
|
num_children = 1;
|
2010-10-27 11:32:59 +08:00
|
|
|
break;
|
2010-08-03 08:35:52 +08:00
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
2010-12-15 13:08:08 +08:00
|
|
|
|
|
|
|
case clang::Type::Complex:
|
|
|
|
return 2;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Record:
|
2010-11-11 10:14:53 +08:00
|
|
|
if (ClangASTType::IsDefined (clang_qual_type))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
|
|
|
|
const RecordDecl *record_decl = record_type->getDecl();
|
|
|
|
assert(record_decl);
|
|
|
|
const CXXRecordDecl *cxx_record_decl = dyn_cast<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.
|
|
|
|
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());
|
|
|
|
|
|
|
|
// Skip empty base classes
|
|
|
|
if (RecordHasFields(base_class_decl) == false)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
num_children++;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
// Include all base classes
|
|
|
|
num_children += cxx_record_decl->getNumBases();
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
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;
|
|
|
|
|
2010-07-28 10:04:09 +08:00
|
|
|
case clang::Type::ObjCObject:
|
|
|
|
case clang::Type::ObjCInterface:
|
|
|
|
{
|
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
|
|
|
|
assert (objc_class_type);
|
|
|
|
if (objc_class_type)
|
|
|
|
{
|
|
|
|
ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
|
|
|
|
|
|
|
if (class_interface_decl)
|
|
|
|
{
|
|
|
|
|
|
|
|
ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
|
|
|
|
if (superclass_interface_decl)
|
|
|
|
{
|
|
|
|
if (omit_empty_base_classes)
|
|
|
|
{
|
|
|
|
if (ClangASTContext::ObjCDeclHasIVars (superclass_interface_decl, true))
|
|
|
|
++num_children;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
++num_children;
|
|
|
|
}
|
|
|
|
|
|
|
|
num_children += class_interface_decl->ivar_size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case clang::Type::ObjCObjectPointer:
|
2010-08-03 08:35:52 +08:00
|
|
|
{
|
|
|
|
ObjCObjectPointerType *pointer_type = cast<ObjCObjectPointerType>(qual_type.getTypePtr());
|
|
|
|
QualType pointee_type = pointer_type->getPointeeType();
|
|
|
|
uint32_t num_pointee_children = ClangASTContext::GetNumChildren (pointee_type.getAsOpaquePtr(),
|
|
|
|
omit_empty_base_classes);
|
|
|
|
// 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;
|
2010-07-28 10:04:09 +08:00
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::ConstantArray:
|
2010-06-09 00:52:24 +08:00
|
|
|
num_children = cast<ConstantArrayType>(qual_type.getTypePtr())->getSize().getLimitedValue();
|
|
|
|
break;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Pointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
|
2010-12-15 13:08:08 +08:00
|
|
|
QualType pointee_type (pointer_type->getPointeeType());
|
2010-07-28 10:04:09 +08:00
|
|
|
uint32_t num_pointee_children = ClangASTContext::GetNumChildren (pointee_type.getAsOpaquePtr(),
|
|
|
|
omit_empty_base_classes);
|
2010-06-09 00:52:24 +08:00
|
|
|
if (num_pointee_children == 0)
|
2010-12-15 13:08:08 +08:00
|
|
|
{
|
|
|
|
// We have a pointer to a pointee type that claims it has no children.
|
|
|
|
// We will want to look at
|
|
|
|
num_children = ClangASTContext::GetNumPointeeChildren (pointee_type.getAsOpaquePtr());
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
else
|
|
|
|
num_children = num_pointee_children;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-10-27 11:32:59 +08:00
|
|
|
case clang::Type::LValueReference:
|
|
|
|
case clang::Type::RValueReference:
|
|
|
|
{
|
|
|
|
ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
|
|
|
|
QualType pointee_type = reference_type->getPointeeType();
|
|
|
|
uint32_t num_pointee_children = ClangASTContext::GetNumChildren (pointee_type.getAsOpaquePtr(),
|
|
|
|
omit_empty_base_classes);
|
|
|
|
// 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;
|
|
|
|
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Typedef:
|
2010-12-13 09:26:27 +08:00
|
|
|
num_children = ClangASTContext::GetNumChildren (cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), omit_empty_base_classes);
|
2010-06-09 00:52:24 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return num_children;
|
|
|
|
}
|
|
|
|
|
2010-12-15 13:08:08 +08:00
|
|
|
// 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_type_t clang_type)
|
|
|
|
{
|
|
|
|
if (clang_type == NULL)
|
|
|
|
return 0;
|
|
|
|
|
|
|
|
QualType qual_type(QualType::getFromOpaquePtr(clang_type));
|
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
|
|
|
{
|
|
|
|
case clang::Type::Builtin: return 1;
|
|
|
|
case clang::Type::Complex: return 2;
|
|
|
|
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::Paren: return 0;
|
|
|
|
case clang::Type::Typedef: return ClangASTContext::GetNumPointeeChildren (cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr());
|
|
|
|
case clang::Type::TypeOfExpr: return 0;
|
|
|
|
case clang::Type::TypeOf: return 0;
|
|
|
|
case clang::Type::Decltype: return 0;
|
|
|
|
case clang::Type::Record: return 0;
|
|
|
|
case clang::Type::Enum: return 1;
|
|
|
|
case clang::Type::Elaborated: 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;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-06-09 00:52:24 +08:00
|
|
|
ClangASTContext::GetChildClangTypeAtIndex
|
|
|
|
(
|
|
|
|
const char *parent_name,
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t parent_clang_type,
|
2010-06-09 00:52:24 +08:00
|
|
|
uint32_t idx,
|
|
|
|
bool transparent_pointers,
|
|
|
|
bool omit_empty_base_classes,
|
|
|
|
std::string& child_name,
|
|
|
|
uint32_t &child_byte_size,
|
|
|
|
int32_t &child_byte_offset,
|
|
|
|
uint32_t &child_bitfield_bit_size,
|
2010-10-15 06:52:14 +08:00
|
|
|
uint32_t &child_bitfield_bit_offset,
|
|
|
|
bool &child_is_base_class
|
2010-06-09 00:52:24 +08:00
|
|
|
)
|
|
|
|
{
|
|
|
|
if (parent_clang_type)
|
|
|
|
|
|
|
|
return GetChildClangTypeAtIndex (getASTContext(),
|
|
|
|
parent_name,
|
|
|
|
parent_clang_type,
|
|
|
|
idx,
|
|
|
|
transparent_pointers,
|
|
|
|
omit_empty_base_classes,
|
|
|
|
child_name,
|
|
|
|
child_byte_size,
|
|
|
|
child_byte_offset,
|
|
|
|
child_bitfield_bit_size,
|
2010-10-15 06:52:14 +08:00
|
|
|
child_bitfield_bit_offset,
|
|
|
|
child_is_base_class);
|
2010-06-09 00:52:24 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
2010-06-09 00:52:24 +08:00
|
|
|
ClangASTContext::GetChildClangTypeAtIndex
|
|
|
|
(
|
|
|
|
ASTContext *ast_context,
|
|
|
|
const char *parent_name,
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t parent_clang_type,
|
2010-06-09 00:52:24 +08:00
|
|
|
uint32_t idx,
|
|
|
|
bool transparent_pointers,
|
|
|
|
bool omit_empty_base_classes,
|
|
|
|
std::string& child_name,
|
|
|
|
uint32_t &child_byte_size,
|
|
|
|
int32_t &child_byte_offset,
|
|
|
|
uint32_t &child_bitfield_bit_size,
|
2010-10-15 06:52:14 +08:00
|
|
|
uint32_t &child_bitfield_bit_offset,
|
|
|
|
bool &child_is_base_class
|
2010-06-09 00:52:24 +08:00
|
|
|
)
|
|
|
|
{
|
|
|
|
if (parent_clang_type == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
if (idx < ClangASTContext::GetNumChildren (parent_clang_type, omit_empty_base_classes))
|
|
|
|
{
|
|
|
|
uint32_t bit_offset;
|
|
|
|
child_bitfield_bit_size = 0;
|
|
|
|
child_bitfield_bit_offset = 0;
|
2010-10-15 06:52:14 +08:00
|
|
|
child_is_base_class = false;
|
2010-06-09 00:52:24 +08:00
|
|
|
QualType parent_qual_type(QualType::getFromOpaquePtr(parent_clang_type));
|
2010-09-13 11:32:57 +08:00
|
|
|
const clang::Type::TypeClass parent_type_class = parent_qual_type->getTypeClass();
|
|
|
|
switch (parent_type_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-08-03 08:35:52 +08:00
|
|
|
case clang::Type::Builtin:
|
|
|
|
switch (cast<clang::BuiltinType>(parent_qual_type)->getKind())
|
|
|
|
{
|
|
|
|
case clang::BuiltinType::ObjCId:
|
|
|
|
case clang::BuiltinType::ObjCClass:
|
2010-10-25 08:29:48 +08:00
|
|
|
child_name = "isa";
|
|
|
|
child_byte_size = ast_context->getTypeSize(ast_context->ObjCBuiltinClassTy) / CHAR_BIT;
|
2010-08-03 08:35:52 +08:00
|
|
|
return ast_context->ObjCBuiltinClassTy.getAsOpaquePtr();
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Record:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
const RecordType *record_type = cast<RecordType>(parent_qual_type.getTypePtr());
|
|
|
|
const RecordDecl *record_decl = record_type->getDecl();
|
|
|
|
assert(record_decl);
|
|
|
|
const ASTRecordLayout &record_layout = ast_context->getASTRecordLayout(record_decl);
|
|
|
|
uint32_t child_idx = 0;
|
|
|
|
|
|
|
|
const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
|
|
|
|
if (cxx_record_decl)
|
|
|
|
{
|
|
|
|
// We might have base classes to print out first
|
|
|
|
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 = NULL;
|
|
|
|
|
|
|
|
// Skip empty base classes
|
|
|
|
if (omit_empty_base_classes)
|
|
|
|
{
|
|
|
|
base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
|
|
|
|
if (RecordHasFields(base_class_decl) == false)
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (idx == child_idx)
|
|
|
|
{
|
|
|
|
if (base_class_decl == NULL)
|
|
|
|
base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
|
|
|
|
|
|
|
|
|
|
|
|
if (base_class->isVirtual())
|
2010-11-18 10:56:27 +08:00
|
|
|
bit_offset = record_layout.getVBaseClassOffset(base_class_decl).getQuantity();
|
2010-06-09 00:52:24 +08:00
|
|
|
else
|
2010-11-18 10:56:27 +08:00
|
|
|
bit_offset = record_layout.getBaseClassOffset(base_class_decl).getQuantity();
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
// Base classes should be a multiple of 8 bits in size
|
|
|
|
assert (bit_offset % 8 == 0);
|
|
|
|
child_byte_offset = bit_offset/8;
|
|
|
|
std::string base_class_type_name(base_class->getType().getAsString());
|
|
|
|
|
|
|
|
child_name.assign(base_class_type_name.c_str());
|
|
|
|
|
|
|
|
uint64_t clang_type_info_bit_size = ast_context->getTypeSize(base_class->getType());
|
|
|
|
|
|
|
|
// Base classes biut sizes should be a multiple of 8 bits in size
|
|
|
|
assert (clang_type_info_bit_size % 8 == 0);
|
|
|
|
child_byte_size = clang_type_info_bit_size / 8;
|
2010-10-15 06:52:14 +08:00
|
|
|
child_is_base_class = true;
|
2010-06-09 00:52:24 +08:00
|
|
|
return base_class->getType().getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
// 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;
|
|
|
|
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().c_str());
|
|
|
|
|
|
|
|
// Figure out the type byte size (field_type_info.first) and
|
|
|
|
// alignment (field_type_info.second) from the AST context.
|
|
|
|
std::pair<uint64_t, unsigned> field_type_info = ast_context->getTypeInfo(field->getType());
|
2010-07-10 04:39:50 +08:00
|
|
|
assert(field_idx < record_layout.getFieldCount());
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
child_byte_size = field_type_info.first / 8;
|
|
|
|
|
|
|
|
// Figure out the field offset within the current struct/union/class type
|
|
|
|
bit_offset = record_layout.getFieldOffset (field_idx);
|
|
|
|
child_byte_offset = bit_offset / 8;
|
|
|
|
if (ClangASTContext::FieldIsBitfield (ast_context, *field, child_bitfield_bit_size))
|
|
|
|
child_bitfield_bit_offset = bit_offset % 8;
|
|
|
|
|
|
|
|
return field->getType().getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-07-28 10:04:09 +08:00
|
|
|
case clang::Type::ObjCObject:
|
|
|
|
case clang::Type::ObjCInterface:
|
|
|
|
{
|
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(parent_qual_type.getTypePtr());
|
|
|
|
assert (objc_class_type);
|
|
|
|
if (objc_class_type)
|
|
|
|
{
|
|
|
|
uint32_t child_idx = 0;
|
|
|
|
ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
|
|
|
|
|
|
|
if (class_interface_decl)
|
|
|
|
{
|
|
|
|
|
|
|
|
const ASTRecordLayout &interface_layout = ast_context->getASTObjCInterfaceLayout(class_interface_decl);
|
|
|
|
ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
|
|
|
|
if (superclass_interface_decl)
|
|
|
|
{
|
|
|
|
if (omit_empty_base_classes)
|
|
|
|
{
|
2010-08-03 08:35:52 +08:00
|
|
|
if (ClangASTContext::GetNumChildren(ast_context->getObjCInterfaceType(superclass_interface_decl).getAsOpaquePtr(), omit_empty_base_classes) > 0)
|
2010-07-28 10:04:09 +08:00
|
|
|
{
|
|
|
|
if (idx == 0)
|
|
|
|
{
|
|
|
|
QualType ivar_qual_type(ast_context->getObjCInterfaceType(superclass_interface_decl));
|
|
|
|
|
|
|
|
|
|
|
|
child_name.assign(superclass_interface_decl->getNameAsString().c_str());
|
|
|
|
|
|
|
|
std::pair<uint64_t, unsigned> ivar_type_info = ast_context->getTypeInfo(ivar_qual_type.getTypePtr());
|
|
|
|
|
|
|
|
child_byte_size = ivar_type_info.first / 8;
|
2010-08-03 08:35:52 +08:00
|
|
|
child_byte_offset = 0;
|
2010-10-15 06:52:14 +08:00
|
|
|
child_is_base_class = true;
|
2010-07-28 10:04:09 +08:00
|
|
|
|
|
|
|
return ivar_qual_type.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
|
|
|
|
++child_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
++child_idx;
|
|
|
|
}
|
2010-08-03 08:35:52 +08:00
|
|
|
|
|
|
|
const uint32_t superclass_idx = child_idx;
|
2010-07-28 10:04:09 +08:00
|
|
|
|
|
|
|
if (idx < (child_idx + class_interface_decl->ivar_size()))
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
const ObjCIvarDecl* ivar_decl = *ivar_pos;
|
|
|
|
|
|
|
|
QualType ivar_qual_type(ivar_decl->getType());
|
|
|
|
|
|
|
|
child_name.assign(ivar_decl->getNameAsString().c_str());
|
|
|
|
|
|
|
|
std::pair<uint64_t, unsigned> ivar_type_info = ast_context->getTypeInfo(ivar_qual_type.getTypePtr());
|
|
|
|
|
|
|
|
child_byte_size = ivar_type_info.first / 8;
|
|
|
|
|
|
|
|
// Figure out the field offset within the current struct/union/class type
|
2010-08-03 08:35:52 +08:00
|
|
|
bit_offset = interface_layout.getFieldOffset (child_idx - superclass_idx);
|
2010-07-28 10:04:09 +08:00
|
|
|
child_byte_offset = bit_offset / 8;
|
|
|
|
|
|
|
|
return ivar_qual_type.getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
++child_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case clang::Type::ObjCObjectPointer:
|
|
|
|
{
|
2010-08-03 08:35:52 +08:00
|
|
|
ObjCObjectPointerType *pointer_type = cast<ObjCObjectPointerType>(parent_qual_type.getTypePtr());
|
|
|
|
QualType pointee_type = pointer_type->getPointeeType();
|
|
|
|
|
|
|
|
if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
|
|
|
|
{
|
|
|
|
return GetChildClangTypeAtIndex (ast_context,
|
|
|
|
parent_name,
|
|
|
|
pointer_type->getPointeeType().getAsOpaquePtr(),
|
|
|
|
idx,
|
|
|
|
transparent_pointers,
|
|
|
|
omit_empty_base_classes,
|
|
|
|
child_name,
|
|
|
|
child_byte_size,
|
|
|
|
child_byte_offset,
|
|
|
|
child_bitfield_bit_size,
|
2010-10-15 06:52:14 +08:00
|
|
|
child_bitfield_bit_offset,
|
|
|
|
child_is_base_class);
|
2010-08-03 08:35:52 +08:00
|
|
|
}
|
|
|
|
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_context->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();
|
|
|
|
}
|
|
|
|
}
|
2010-07-28 10:04:09 +08:00
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::ConstantArray:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
const ConstantArrayType *array = cast<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_context->getTypeInfo(array->getElementType());
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
char element_name[64];
|
|
|
|
::snprintf (element_name, sizeof (element_name), "[%u]", idx);
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
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;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Pointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
PointerType *pointer_type = cast<PointerType>(parent_qual_type.getTypePtr());
|
|
|
|
QualType pointee_type = pointer_type->getPointeeType();
|
|
|
|
|
|
|
|
if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
|
|
|
|
{
|
|
|
|
return GetChildClangTypeAtIndex (ast_context,
|
|
|
|
parent_name,
|
|
|
|
pointer_type->getPointeeType().getAsOpaquePtr(),
|
|
|
|
idx,
|
|
|
|
transparent_pointers,
|
|
|
|
omit_empty_base_classes,
|
|
|
|
child_name,
|
|
|
|
child_byte_size,
|
|
|
|
child_byte_offset,
|
|
|
|
child_bitfield_bit_size,
|
2010-10-15 06:52:14 +08:00
|
|
|
child_bitfield_bit_offset,
|
|
|
|
child_is_base_class);
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
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_context->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;
|
|
|
|
|
2010-10-27 11:32:59 +08:00
|
|
|
case clang::Type::LValueReference:
|
|
|
|
case clang::Type::RValueReference:
|
|
|
|
{
|
|
|
|
ReferenceType *reference_type = cast<ReferenceType>(parent_qual_type.getTypePtr());
|
|
|
|
QualType pointee_type(reference_type->getPointeeType());
|
|
|
|
clang_type_t pointee_clang_type = pointee_type.getAsOpaquePtr();
|
|
|
|
if (transparent_pointers && ClangASTContext::IsAggregateType (pointee_clang_type))
|
|
|
|
{
|
|
|
|
return GetChildClangTypeAtIndex (ast_context,
|
|
|
|
parent_name,
|
|
|
|
pointee_clang_type,
|
|
|
|
idx,
|
|
|
|
transparent_pointers,
|
|
|
|
omit_empty_base_classes,
|
|
|
|
child_name,
|
|
|
|
child_byte_size,
|
|
|
|
child_byte_offset,
|
|
|
|
child_bitfield_bit_size,
|
|
|
|
child_bitfield_bit_offset,
|
|
|
|
child_is_base_class);
|
|
|
|
}
|
|
|
|
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_context->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;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Typedef:
|
2010-06-09 00:52:24 +08:00
|
|
|
return GetChildClangTypeAtIndex (ast_context,
|
|
|
|
parent_name,
|
2010-12-13 09:26:27 +08:00
|
|
|
cast<TypedefType>(parent_qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(),
|
2010-06-09 00:52:24 +08:00
|
|
|
idx,
|
|
|
|
transparent_pointers,
|
|
|
|
omit_empty_base_classes,
|
|
|
|
child_name,
|
|
|
|
child_byte_size,
|
|
|
|
child_byte_offset,
|
|
|
|
child_bitfield_bit_size,
|
2010-10-15 06:52:14 +08:00
|
|
|
child_bitfield_bit_offset,
|
|
|
|
child_is_base_class);
|
2010-06-09 00:52:24 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2010-07-23 23:37:46 +08:00
|
|
|
return NULL;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static inline bool
|
|
|
|
BaseSpecifierIsEmpty (const CXXBaseSpecifier *b)
|
|
|
|
{
|
|
|
|
return ClangASTContext::RecordHasFields(cast<CXXRecordDecl>(b->getType()->getAs<RecordType>()->getDecl())) == false;
|
|
|
|
}
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
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;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
GetIndexForRecordBase
|
|
|
|
(
|
|
|
|
const RecordDecl *record_decl,
|
|
|
|
const CXXBaseSpecifier *base_spec,
|
|
|
|
bool omit_empty_base_classes
|
|
|
|
)
|
|
|
|
{
|
|
|
|
uint32_t child_idx = 0;
|
|
|
|
|
|
|
|
const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
|
|
|
|
|
|
|
|
// const char *super_name = record_decl->getNameAsCString();
|
|
|
|
// const char *base_name = base_spec->getType()->getAs<RecordType>()->getDecl()->getNameAsCString();
|
|
|
|
// printf ("GetIndexForRecordChild (%s, %s)\n", super_name, base_name);
|
|
|
|
//
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
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<RecordType>()->getDecl()->getNameAsCString());
|
|
|
|
//
|
|
|
|
//
|
|
|
|
if (base_class == base_spec)
|
|
|
|
return child_idx;
|
|
|
|
++child_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static uint32_t
|
|
|
|
GetIndexForRecordChild
|
|
|
|
(
|
|
|
|
const RecordDecl *record_decl,
|
|
|
|
NamedDecl *canonical_decl,
|
|
|
|
bool omit_empty_base_classes
|
|
|
|
)
|
|
|
|
{
|
|
|
|
uint32_t child_idx = GetNumBaseClasses (dyn_cast<CXXRecordDecl>(record_decl), omit_empty_base_classes);
|
|
|
|
|
|
|
|
// const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
|
|
|
|
//
|
|
|
|
//// printf ("GetIndexForRecordChild (%s, %s)\n", record_decl->getNameAsCString(), canonical_decl->getNameAsCString());
|
|
|
|
// 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)
|
|
|
|
// {
|
|
|
|
// if (omit_empty_base_classes)
|
|
|
|
// {
|
|
|
|
// if (BaseSpecifierIsEmpty (base_class))
|
|
|
|
// continue;
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
//// printf ("GetIndexForRecordChild (%s, %s) base[%u] = %s\n",
|
|
|
|
//// record_decl->getNameAsCString(),
|
|
|
|
//// canonical_decl->getNameAsCString(),
|
|
|
|
//// child_idx,
|
|
|
|
//// base_class->getType()->getAs<RecordType>()->getDecl()->getNameAsCString());
|
|
|
|
//
|
|
|
|
//
|
|
|
|
// CXXRecordDecl *curr_base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
|
|
|
|
// if (curr_base_class_decl == canonical_decl)
|
|
|
|
// {
|
|
|
|
// return child_idx;
|
|
|
|
// }
|
|
|
|
// ++child_idx;
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
//
|
|
|
|
// const uint32_t num_bases = child_idx;
|
|
|
|
RecordDecl::field_iterator field, field_end;
|
|
|
|
for (field = record_decl->field_begin(), field_end = record_decl->field_end();
|
|
|
|
field != field_end;
|
|
|
|
++field, ++child_idx)
|
|
|
|
{
|
|
|
|
// printf ("GetIndexForRecordChild (%s, %s) field[%u] = %s\n",
|
|
|
|
// record_decl->getNameAsCString(),
|
|
|
|
// canonical_decl->getNameAsCString(),
|
|
|
|
// child_idx - num_bases,
|
|
|
|
// field->getNameAsCString());
|
|
|
|
|
|
|
|
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
|
|
|
|
(
|
|
|
|
ASTContext *ast_context,
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t clang_type,
|
2010-06-09 00:52:24 +08:00
|
|
|
const char *name,
|
|
|
|
bool omit_empty_base_classes,
|
|
|
|
std::vector<uint32_t>& child_indexes
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (clang_type && name && name[0])
|
|
|
|
{
|
|
|
|
QualType qual_type(QualType::getFromOpaquePtr(clang_type));
|
2010-09-13 11:32:57 +08:00
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Record:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
|
|
|
|
const RecordDecl *record_decl = record_type->getDecl();
|
|
|
|
|
|
|
|
assert(record_decl);
|
|
|
|
uint32_t child_idx = 0;
|
|
|
|
|
|
|
|
const CXXRecordDecl *cxx_record_decl = dyn_cast<CXXRecordDecl>(record_decl);
|
|
|
|
|
|
|
|
// Try and find a field that matches NAME
|
|
|
|
RecordDecl::field_iterator field, field_end;
|
|
|
|
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))
|
|
|
|
{
|
|
|
|
// We have to add on the number of base classes to this index!
|
|
|
|
child_indexes.push_back (child_idx + GetNumBaseClasses (cxx_record_decl, omit_empty_base_classes));
|
|
|
|
return child_indexes.size();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (cxx_record_decl)
|
|
|
|
{
|
|
|
|
const 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...
|
|
|
|
IdentifierInfo & ident_ref = ast_context->Idents.get(name, name + strlen (name));
|
|
|
|
DeclarationName decl_name(&ident_ref);
|
|
|
|
|
|
|
|
CXXBasePaths paths;
|
|
|
|
if (cxx_record_decl->lookupInBases(CXXRecordDecl::FindOrdinaryMember,
|
|
|
|
decl_name.getAsOpaquePtr(),
|
|
|
|
paths))
|
|
|
|
{
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
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 = cast<RecordDecl>(elem.Base->getType()->getAs<RecordType>()->getDecl());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
DeclContext::lookup_iterator named_decl_pos;
|
|
|
|
for (named_decl_pos = path->Decls.first;
|
|
|
|
named_decl_pos != path->Decls.second && parent_record_decl;
|
|
|
|
++named_decl_pos)
|
|
|
|
{
|
|
|
|
//printf ("path[%zu] = %s\n", child_indexes.size(), (*named_decl_pos)->getNameAsCString());
|
|
|
|
|
|
|
|
child_idx = GetIndexForRecordChild (parent_record_decl, *named_decl_pos, 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;
|
|
|
|
|
2010-07-28 10:04:09 +08:00
|
|
|
case clang::Type::ObjCObject:
|
|
|
|
case clang::Type::ObjCInterface:
|
|
|
|
{
|
|
|
|
StringRef name_sref(name);
|
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
|
|
|
|
assert (objc_class_type);
|
|
|
|
if (objc_class_type)
|
|
|
|
{
|
|
|
|
uint32_t child_idx = 0;
|
|
|
|
ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
|
|
|
|
|
|
|
if (class_interface_decl)
|
|
|
|
{
|
|
|
|
ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
|
|
|
|
ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
|
|
|
|
|
2010-09-18 10:11:07 +08:00
|
|
|
for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos, ++child_idx)
|
2010-07-28 10:04:09 +08:00
|
|
|
{
|
|
|
|
const 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);
|
|
|
|
|
|
|
|
if (GetIndexOfChildMemberWithName (ast_context,
|
|
|
|
ast_context->getObjCInterfaceType(superclass_interface_decl).getAsOpaquePtr(),
|
|
|
|
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:
|
|
|
|
{
|
|
|
|
return GetIndexOfChildMemberWithName (ast_context,
|
|
|
|
cast<ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType().getAsOpaquePtr(),
|
|
|
|
name,
|
|
|
|
omit_empty_base_classes,
|
|
|
|
child_indexes);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::ConstantArray:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
// const ConstantArrayType *array = cast<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_context->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;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
// case clang::Type::MemberPointerType:
|
2010-06-09 00:52:24 +08:00
|
|
|
// {
|
|
|
|
// MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr());
|
|
|
|
// QualType pointee_type = mem_ptr_type->getPointeeType();
|
|
|
|
//
|
|
|
|
// if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
|
|
|
|
// {
|
|
|
|
// return GetIndexOfChildWithName (ast_context,
|
|
|
|
// mem_ptr_type->getPointeeType().getAsOpaquePtr(),
|
|
|
|
// name);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
//
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::LValueReference:
|
|
|
|
case clang::Type::RValueReference:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
|
|
|
|
QualType pointee_type = reference_type->getPointeeType();
|
|
|
|
|
|
|
|
if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
|
|
|
|
{
|
|
|
|
return GetIndexOfChildMemberWithName (ast_context,
|
|
|
|
reference_type->getPointeeType().getAsOpaquePtr(),
|
|
|
|
name,
|
|
|
|
omit_empty_base_classes,
|
|
|
|
child_indexes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Pointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
|
|
|
|
QualType pointee_type = pointer_type->getPointeeType();
|
|
|
|
|
|
|
|
if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
|
|
|
|
{
|
|
|
|
return GetIndexOfChildMemberWithName (ast_context,
|
|
|
|
pointer_type->getPointeeType().getAsOpaquePtr(),
|
|
|
|
name,
|
|
|
|
omit_empty_base_classes,
|
|
|
|
child_indexes);
|
|
|
|
}
|
|
|
|
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_context->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;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Typedef:
|
2010-06-09 00:52:24 +08:00
|
|
|
return GetIndexOfChildMemberWithName (ast_context,
|
2010-12-13 09:26:27 +08:00
|
|
|
cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(),
|
2010-06-09 00:52:24 +08:00
|
|
|
name,
|
|
|
|
omit_empty_base_classes,
|
|
|
|
child_indexes);
|
|
|
|
|
|
|
|
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
|
|
|
|
(
|
|
|
|
ASTContext *ast_context,
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t clang_type,
|
2010-06-09 00:52:24 +08:00
|
|
|
const char *name,
|
|
|
|
bool omit_empty_base_classes
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (clang_type && name && name[0])
|
|
|
|
{
|
|
|
|
QualType qual_type(QualType::getFromOpaquePtr(clang_type));
|
2010-07-28 10:04:09 +08:00
|
|
|
|
2010-09-13 11:32:57 +08:00
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
2010-07-28 10:04:09 +08:00
|
|
|
|
2010-09-13 11:32:57 +08:00
|
|
|
switch (type_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Record:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
const RecordType *record_type = cast<RecordType>(qual_type.getTypePtr());
|
|
|
|
const RecordDecl *record_decl = record_type->getDecl();
|
|
|
|
|
|
|
|
assert(record_decl);
|
|
|
|
uint32_t child_idx = 0;
|
|
|
|
|
|
|
|
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)
|
|
|
|
{
|
|
|
|
// Skip empty base classes
|
|
|
|
CXXRecordDecl *base_class_decl = cast<CXXRecordDecl>(base_class->getType()->getAs<RecordType>()->getDecl());
|
|
|
|
if (omit_empty_base_classes && RecordHasFields(base_class_decl) == false)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
if (base_class->getType().getAsString().compare (name) == 0)
|
|
|
|
return child_idx;
|
|
|
|
++child_idx;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Try and find a field that matches NAME
|
|
|
|
RecordDecl::field_iterator field, field_end;
|
|
|
|
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;
|
|
|
|
|
2010-07-28 10:04:09 +08:00
|
|
|
case clang::Type::ObjCObject:
|
|
|
|
case clang::Type::ObjCInterface:
|
|
|
|
{
|
|
|
|
StringRef name_sref(name);
|
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type.getTypePtr());
|
|
|
|
assert (objc_class_type);
|
|
|
|
if (objc_class_type)
|
|
|
|
{
|
|
|
|
uint32_t child_idx = 0;
|
|
|
|
ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
|
|
|
|
|
|
|
if (class_interface_decl)
|
|
|
|
{
|
|
|
|
ObjCInterfaceDecl::ivar_iterator ivar_pos, ivar_end = class_interface_decl->ivar_end();
|
|
|
|
ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
|
|
|
|
|
|
|
|
for (ivar_pos = class_interface_decl->ivar_begin(); ivar_pos != ivar_end; ++ivar_pos)
|
|
|
|
{
|
|
|
|
const 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:
|
|
|
|
{
|
|
|
|
return GetIndexOfChildWithName (ast_context,
|
|
|
|
cast<ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType().getAsOpaquePtr(),
|
|
|
|
name,
|
|
|
|
omit_empty_base_classes);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::ConstantArray:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
// const ConstantArrayType *array = cast<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_context->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;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
// case clang::Type::MemberPointerType:
|
2010-06-09 00:52:24 +08:00
|
|
|
// {
|
|
|
|
// MemberPointerType *mem_ptr_type = cast<MemberPointerType>(qual_type.getTypePtr());
|
|
|
|
// QualType pointee_type = mem_ptr_type->getPointeeType();
|
|
|
|
//
|
|
|
|
// if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
|
|
|
|
// {
|
|
|
|
// return GetIndexOfChildWithName (ast_context,
|
|
|
|
// mem_ptr_type->getPointeeType().getAsOpaquePtr(),
|
|
|
|
// name);
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// break;
|
|
|
|
//
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::LValueReference:
|
|
|
|
case clang::Type::RValueReference:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
|
|
|
|
QualType pointee_type = reference_type->getPointeeType();
|
|
|
|
|
|
|
|
if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
|
|
|
|
{
|
|
|
|
return GetIndexOfChildWithName (ast_context,
|
|
|
|
reference_type->getPointeeType().getAsOpaquePtr(),
|
|
|
|
name,
|
|
|
|
omit_empty_base_classes);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Pointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
PointerType *pointer_type = cast<PointerType>(qual_type.getTypePtr());
|
|
|
|
QualType pointee_type = pointer_type->getPointeeType();
|
|
|
|
|
|
|
|
if (ClangASTContext::IsAggregateType (pointee_type.getAsOpaquePtr()))
|
|
|
|
{
|
|
|
|
return GetIndexOfChildWithName (ast_context,
|
|
|
|
pointer_type->getPointeeType().getAsOpaquePtr(),
|
|
|
|
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_context->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;
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Typedef:
|
2010-06-09 00:52:24 +08:00
|
|
|
return GetIndexOfChildWithName (ast_context,
|
2010-12-13 09:26:27 +08:00
|
|
|
cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(),
|
2010-06-09 00:52:24 +08:00
|
|
|
name,
|
|
|
|
omit_empty_base_classes);
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return UINT32_MAX;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark TagType
|
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::SetTagTypeKind (clang_type_t tag_clang_type, int kind)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (tag_clang_type)
|
|
|
|
{
|
|
|
|
QualType tag_qual_type(QualType::getFromOpaquePtr(tag_clang_type));
|
2010-07-22 06:12:05 +08:00
|
|
|
clang::Type *clang_type = tag_qual_type.getTypePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
TagType *tag_type = dyn_cast<TagType>(clang_type);
|
|
|
|
if (tag_type)
|
|
|
|
{
|
|
|
|
TagDecl *tag_decl = dyn_cast<TagDecl>(tag_type->getDecl());
|
|
|
|
if (tag_decl)
|
|
|
|
{
|
|
|
|
tag_decl->setTagKind ((TagDecl::TagKind)kind);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark DeclContext Functions
|
|
|
|
|
|
|
|
DeclContext *
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::GetDeclContextForType (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type == NULL)
|
|
|
|
return NULL;
|
|
|
|
|
|
|
|
QualType qual_type(QualType::getFromOpaquePtr(clang_type));
|
2010-09-13 11:32:57 +08:00
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-07-28 10:04:09 +08:00
|
|
|
case clang::Type::FunctionNoProto: break;
|
|
|
|
case clang::Type::FunctionProto: break;
|
|
|
|
case clang::Type::IncompleteArray: break;
|
|
|
|
case clang::Type::VariableArray: break;
|
|
|
|
case clang::Type::ConstantArray: break;
|
|
|
|
case clang::Type::ExtVector: break;
|
|
|
|
case clang::Type::Vector: break;
|
|
|
|
case clang::Type::Builtin: break;
|
|
|
|
case clang::Type::BlockPointer: break;
|
|
|
|
case clang::Type::Pointer: break;
|
|
|
|
case clang::Type::LValueReference: break;
|
|
|
|
case clang::Type::RValueReference: break;
|
|
|
|
case clang::Type::MemberPointer: break;
|
|
|
|
case clang::Type::Complex: break;
|
|
|
|
case clang::Type::ObjCObject: break;
|
|
|
|
case clang::Type::ObjCInterface: return cast<ObjCObjectType>(qual_type.getTypePtr())->getInterface();
|
|
|
|
case clang::Type::ObjCObjectPointer: return ClangASTContext::GetDeclContextForType (cast<ObjCObjectPointerType>(qual_type.getTypePtr())->getPointeeType().getAsOpaquePtr());
|
|
|
|
case clang::Type::Record: return cast<RecordType>(qual_type)->getDecl();
|
|
|
|
case clang::Type::Enum: return cast<EnumType>(qual_type)->getDecl();
|
2010-12-13 09:26:27 +08:00
|
|
|
case clang::Type::Typedef: return ClangASTContext::GetDeclContextForType (cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr());
|
2010-07-28 10:04:09 +08:00
|
|
|
|
|
|
|
case clang::Type::TypeOfExpr: break;
|
|
|
|
case clang::Type::TypeOf: break;
|
|
|
|
case clang::Type::Decltype: break;
|
|
|
|
//case clang::Type::QualifiedName: break;
|
|
|
|
case clang::Type::TemplateSpecialization: break;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
// No DeclContext in this type...
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark Namespace Declarations
|
|
|
|
|
|
|
|
NamespaceDecl *
|
|
|
|
ClangASTContext::GetUniqueNamespaceDeclaration (const char *name, const Declaration &decl, DeclContext *decl_ctx)
|
|
|
|
{
|
|
|
|
// TODO: Do something intelligent with the Declaration object passed in
|
|
|
|
// like maybe filling in the SourceLocation with it...
|
|
|
|
if (name)
|
|
|
|
{
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
if (decl_ctx == NULL)
|
|
|
|
decl_ctx = ast_context->getTranslationUnitDecl();
|
|
|
|
return NamespaceDecl::Create(*ast_context, decl_ctx, SourceLocation(), &ast_context->Idents.get(name));
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark Function Types
|
|
|
|
|
|
|
|
FunctionDecl *
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::CreateFunctionDeclaration (const char *name, clang_type_t function_clang_type, int storage, bool is_inline)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (name)
|
|
|
|
{
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
|
|
|
|
if (name && name[0])
|
|
|
|
{
|
|
|
|
return FunctionDecl::Create(*ast_context,
|
|
|
|
ast_context->getTranslationUnitDecl(),
|
|
|
|
SourceLocation(),
|
|
|
|
DeclarationName (&ast_context->Idents.get(name)),
|
|
|
|
QualType::getFromOpaquePtr(function_clang_type),
|
|
|
|
NULL,
|
|
|
|
(FunctionDecl::StorageClass)storage,
|
|
|
|
(FunctionDecl::StorageClass)storage,
|
|
|
|
is_inline);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return FunctionDecl::Create(*ast_context,
|
|
|
|
ast_context->getTranslationUnitDecl(),
|
|
|
|
SourceLocation(),
|
|
|
|
DeclarationName (),
|
|
|
|
QualType::getFromOpaquePtr(function_clang_type),
|
|
|
|
NULL,
|
|
|
|
(FunctionDecl::StorageClass)storage,
|
|
|
|
(FunctionDecl::StorageClass)storage,
|
|
|
|
is_inline);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::CreateFunctionType (ASTContext *ast_context,
|
|
|
|
clang_type_t result_type,
|
|
|
|
clang_type_t *args,
|
2010-09-17 04:40:25 +08:00
|
|
|
unsigned num_args,
|
|
|
|
bool is_variadic,
|
|
|
|
unsigned type_quals)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
std::vector<QualType> qual_type_args;
|
|
|
|
for (unsigned i=0; i<num_args; ++i)
|
|
|
|
qual_type_args.push_back (QualType::getFromOpaquePtr(args[i]));
|
|
|
|
|
|
|
|
// TODO: Detect calling convention in DWARF?
|
|
|
|
return ast_context->getFunctionType(QualType::getFromOpaquePtr(result_type),
|
2010-07-21 06:52:08 +08:00
|
|
|
qual_type_args.empty() ? NULL : &qual_type_args.front(),
|
2010-06-09 00:52:24 +08:00
|
|
|
qual_type_args.size(),
|
2010-09-17 04:40:25 +08:00
|
|
|
is_variadic,
|
|
|
|
type_quals,
|
2010-06-09 00:52:24 +08:00
|
|
|
false, // hasExceptionSpec
|
|
|
|
false, // hasAnyExceptionSpec,
|
|
|
|
0, // NumExs
|
|
|
|
0, // const QualType *ExArray
|
|
|
|
FunctionType::ExtInfo ()).getAsOpaquePtr(); // NoReturn);
|
|
|
|
}
|
|
|
|
|
|
|
|
ParmVarDecl *
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::CreateParameterDeclaration (const char *name, clang_type_t param_type, int storage)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
return ParmVarDecl::Create(*ast_context,
|
|
|
|
ast_context->getTranslationUnitDecl(),
|
|
|
|
SourceLocation(),
|
|
|
|
name && name[0] ? &ast_context->Idents.get(name) : NULL,
|
2010-09-17 04:40:25 +08:00
|
|
|
QualType::getFromOpaquePtr(param_type),
|
2010-06-09 00:52:24 +08:00
|
|
|
NULL,
|
|
|
|
(VarDecl::StorageClass)storage,
|
|
|
|
(VarDecl::StorageClass)storage,
|
|
|
|
0);
|
|
|
|
}
|
|
|
|
|
|
|
|
void
|
|
|
|
ClangASTContext::SetFunctionParameters (FunctionDecl *function_decl, ParmVarDecl **params, unsigned num_params)
|
|
|
|
{
|
|
|
|
if (function_decl)
|
|
|
|
function_decl->setParams (params, num_params);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark Array Types
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::CreateArrayType (clang_type_t element_type, size_t element_count, uint32_t bit_stride)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (element_type)
|
|
|
|
{
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
llvm::APInt ap_element_count (64, element_count);
|
|
|
|
return ast_context->getConstantArrayType(QualType::getFromOpaquePtr(element_type),
|
|
|
|
ap_element_count,
|
|
|
|
ArrayType::Normal,
|
|
|
|
0).getAsOpaquePtr(); // ElemQuals
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark TagDecl
|
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::StartTagDeclarationDefinition (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
2010-07-22 06:12:05 +08:00
|
|
|
clang::Type *t = qual_type.getTypePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
if (t)
|
|
|
|
{
|
|
|
|
TagType *tag_type = dyn_cast<TagType>(t);
|
|
|
|
if (tag_type)
|
|
|
|
{
|
|
|
|
TagDecl *tag_decl = tag_type->getDecl();
|
|
|
|
if (tag_decl)
|
|
|
|
{
|
|
|
|
tag_decl->startDefinition();
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::CompleteTagDeclarationDefinition (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
2010-09-29 11:44:17 +08:00
|
|
|
|
|
|
|
CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
|
|
|
|
|
|
|
|
if (cxx_record_decl)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-09-29 11:44:17 +08:00
|
|
|
cxx_record_decl->completeDefinition();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2010-10-25 08:29:48 +08:00
|
|
|
ObjCObjectType *objc_class_type = dyn_cast<ObjCObjectType>(qual_type);
|
|
|
|
|
|
|
|
if (objc_class_type)
|
|
|
|
{
|
|
|
|
ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
|
|
|
|
|
|
|
|
class_interface_decl->setForwardDecl(false);
|
|
|
|
}
|
|
|
|
|
2010-09-29 11:44:17 +08:00
|
|
|
const EnumType *enum_type = dyn_cast<EnumType>(qual_type.getTypePtr());
|
|
|
|
|
|
|
|
if (enum_type)
|
|
|
|
{
|
|
|
|
EnumDecl *enum_decl = enum_type->getDecl();
|
|
|
|
|
|
|
|
if (enum_decl)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-09-29 11:44:17 +08:00
|
|
|
/// TODO This really needs to be fixed.
|
|
|
|
|
|
|
|
unsigned NumPositiveBits = 1;
|
|
|
|
unsigned NumNegativeBits = 0;
|
|
|
|
|
2010-10-12 12:29:14 +08:00
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
|
|
|
|
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_context->getTypeSize(enum_decl->getIntegerType()) < ast_context->getTypeSize(ast_context->IntTy))
|
|
|
|
{
|
|
|
|
if (enum_decl->getIntegerType()->isSignedIntegerType())
|
|
|
|
promotion_qual_type = ast_context->IntTy;
|
|
|
|
else
|
|
|
|
promotion_qual_type = ast_context->UnsignedIntTy;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
promotion_qual_type = enum_decl->getIntegerType();
|
|
|
|
|
|
|
|
enum_decl->completeDefinition(enum_decl->getIntegerType(), promotion_qual_type, NumPositiveBits, NumNegativeBits);
|
2010-09-29 11:44:17 +08:00
|
|
|
return true;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark Enumeration Types
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::CreateEnumerationType (const Declaration &decl, const char *name, clang_type_t integer_qual_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
// TODO: Do something intelligent with the Declaration object passed in
|
|
|
|
// like maybe filling in the SourceLocation with it...
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
assert (ast_context != NULL);
|
2010-10-12 12:29:14 +08:00
|
|
|
|
|
|
|
// TODO: ask about these...
|
|
|
|
// const bool IsScoped = false;
|
|
|
|
// const bool IsFixed = false;
|
|
|
|
|
|
|
|
EnumDecl *enum_decl = EnumDecl::Create (*ast_context,
|
|
|
|
ast_context->getTranslationUnitDecl(),
|
|
|
|
SourceLocation(),
|
|
|
|
name && name[0] ? &ast_context->Idents.get(name) : NULL,
|
|
|
|
SourceLocation(),
|
2010-12-13 09:26:27 +08:00
|
|
|
NULL,
|
|
|
|
false, // IsScoped
|
|
|
|
false, // IsScopedUsingClassTag
|
|
|
|
false); // IsFixed
|
2010-06-09 00:52:24 +08:00
|
|
|
if (enum_decl)
|
2010-09-13 07:17:56 +08:00
|
|
|
{
|
|
|
|
// TODO: check if we should be setting the promotion type too?
|
|
|
|
enum_decl->setIntegerType(QualType::getFromOpaquePtr (integer_qual_type));
|
2010-06-09 00:52:24 +08:00
|
|
|
return ast_context->getTagDeclType(enum_decl).getAsOpaquePtr();
|
2010-09-13 07:17:56 +08:00
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::GetEnumerationIntegerType (clang_type_t enum_clang_type)
|
|
|
|
{
|
|
|
|
QualType enum_qual_type (QualType::getFromOpaquePtr(enum_clang_type));
|
|
|
|
|
|
|
|
clang::Type *clang_type = enum_qual_type.getTypePtr();
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
const EnumType *enum_type = dyn_cast<EnumType>(clang_type);
|
|
|
|
if (enum_type)
|
|
|
|
{
|
|
|
|
EnumDecl *enum_decl = enum_type->getDecl();
|
|
|
|
if (enum_decl)
|
|
|
|
return enum_decl->getIntegerType().getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
bool
|
|
|
|
ClangASTContext::AddEnumerationValueToEnumerationType
|
|
|
|
(
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t enum_clang_type,
|
|
|
|
clang_type_t enumerator_clang_type,
|
2010-06-09 00:52:24 +08:00
|
|
|
const Declaration &decl,
|
|
|
|
const char *name,
|
|
|
|
int64_t enum_value,
|
|
|
|
uint32_t enum_value_bit_size
|
|
|
|
)
|
|
|
|
{
|
|
|
|
if (enum_clang_type && enumerator_clang_type && name)
|
|
|
|
{
|
|
|
|
// TODO: Do something intelligent with the Declaration object passed in
|
|
|
|
// like maybe filling in the SourceLocation with it...
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
IdentifierTable *identifier_table = getIdentifierTable();
|
|
|
|
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
assert (identifier_table != NULL);
|
|
|
|
QualType enum_qual_type (QualType::getFromOpaquePtr(enum_clang_type));
|
|
|
|
|
2010-07-22 06:12:05 +08:00
|
|
|
clang::Type *clang_type = enum_qual_type.getTypePtr();
|
2010-06-09 00:52:24 +08:00
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
const EnumType *enum_type = dyn_cast<EnumType>(clang_type);
|
|
|
|
|
|
|
|
if (enum_type)
|
|
|
|
{
|
|
|
|
llvm::APSInt enum_llvm_apsint(enum_value_bit_size, false);
|
|
|
|
enum_llvm_apsint = enum_value;
|
|
|
|
EnumConstantDecl *enumerator_decl =
|
|
|
|
EnumConstantDecl::Create(*ast_context,
|
|
|
|
enum_type->getDecl(),
|
|
|
|
SourceLocation(),
|
|
|
|
name ? &identifier_table->get(name) : NULL, // Identifier
|
|
|
|
QualType::getFromOpaquePtr(enumerator_clang_type),
|
|
|
|
NULL,
|
|
|
|
enum_llvm_apsint);
|
|
|
|
|
|
|
|
if (enumerator_decl)
|
|
|
|
{
|
|
|
|
enum_type->getDecl()->addDecl(enumerator_decl);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
#pragma mark Pointers & References
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::CreatePointerType (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-12-14 10:59:59 +08:00
|
|
|
return CreatePointerType (getASTContext(), clang_type);
|
|
|
|
}
|
|
|
|
|
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::CreatePointerType (clang::ASTContext *ast, clang_type_t clang_type)
|
|
|
|
{
|
|
|
|
if (ast && clang_type)
|
2010-07-30 04:06:32 +08:00
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
|
2010-09-13 11:32:57 +08:00
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
2010-07-30 04:06:32 +08:00
|
|
|
{
|
|
|
|
case clang::Type::ObjCObject:
|
|
|
|
case clang::Type::ObjCInterface:
|
2010-12-14 10:59:59 +08:00
|
|
|
return ast->getObjCObjectPointerType(qual_type).getAsOpaquePtr();
|
2010-07-30 04:06:32 +08:00
|
|
|
|
|
|
|
default:
|
2010-12-14 10:59:59 +08:00
|
|
|
return ast->getPointerType(qual_type).getAsOpaquePtr();
|
2010-07-30 04:06:32 +08:00
|
|
|
}
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::CreateLValueReferenceType (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
return getASTContext()->getLValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::CreateRValueReferenceType (clang_type_t clang_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
return getASTContext()->getRValueReferenceType (QualType::getFromOpaquePtr(clang_type)).getAsOpaquePtr();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::CreateMemberPointerType (clang_type_t clang_pointee_type, clang_type_t clang_class_type)
|
2010-06-12 09:20:30 +08:00
|
|
|
{
|
|
|
|
if (clang_pointee_type && clang_pointee_type)
|
|
|
|
return getASTContext()->getMemberPointerType(QualType::getFromOpaquePtr(clang_pointee_type),
|
|
|
|
QualType::getFromOpaquePtr(clang_class_type).getTypePtr()).getAsOpaquePtr();
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
size_t
|
|
|
|
ClangASTContext::GetPointerBitSize ()
|
|
|
|
{
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
return ast_context->getTypeSize(ast_context->VoidPtrTy);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsPointerOrReferenceType (clang_type_t clang_type, clang_type_t*target_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
2010-09-13 11:32:57 +08:00
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-10-25 08:29:48 +08:00
|
|
|
case clang::Type::Builtin:
|
|
|
|
switch (cast<clang::BuiltinType>(qual_type)->getKind())
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case clang::BuiltinType::ObjCId:
|
|
|
|
case clang::BuiltinType::ObjCClass:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::ObjCObjectPointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<ObjCObjectPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::BlockPointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<BlockPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Pointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<PointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::MemberPointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<MemberPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::LValueReference:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<LValueReferenceType>(qual_type)->desugar().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::RValueReference:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<LValueReferenceType>(qual_type)->desugar().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Typedef:
|
2010-12-13 09:26:27 +08:00
|
|
|
return ClangASTContext::IsPointerOrReferenceType (cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr());
|
2010-06-09 00:52:24 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsIntegerType (clang_type_t clang_type, bool &is_signed)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (!clang_type)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
const BuiltinType *builtin_type = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal());
|
|
|
|
|
|
|
|
if (builtin_type)
|
|
|
|
{
|
|
|
|
if (builtin_type->isInteger())
|
|
|
|
is_signed = builtin_type->isSignedInteger();
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsPointerType (clang_type_t clang_type, clang_type_t*target_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
2010-09-13 11:32:57 +08:00
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-10-25 08:29:48 +08:00
|
|
|
case clang::Type::Builtin:
|
|
|
|
switch (cast<clang::BuiltinType>(qual_type)->getKind())
|
|
|
|
{
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
case clang::BuiltinType::ObjCId:
|
|
|
|
case clang::BuiltinType::ObjCClass:
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::ObjCObjectPointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<ObjCObjectPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::BlockPointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<BlockPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Pointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<PointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::MemberPointer:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (target_type)
|
|
|
|
*target_type = cast<MemberPointerType>(qual_type)->getPointeeType().getAsOpaquePtr();
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::Typedef:
|
2010-12-13 09:26:27 +08:00
|
|
|
return ClangASTContext::IsPointerOrReferenceType (cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr(), target_type);
|
2010-06-09 00:52:24 +08:00
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsFloatingPointType (clang_type_t clang_type, uint32_t &count, bool &is_complex)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
|
|
|
|
if (const BuiltinType *BT = dyn_cast<BuiltinType>(qual_type->getCanonicalTypeInternal()))
|
|
|
|
{
|
|
|
|
clang::BuiltinType::Kind kind = BT->getKind();
|
|
|
|
if (kind >= BuiltinType::Float && kind <= BuiltinType::LongDouble)
|
|
|
|
{
|
|
|
|
count = 1;
|
|
|
|
is_complex = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (const ComplexType *CT = dyn_cast<ComplexType>(qual_type->getCanonicalTypeInternal()))
|
|
|
|
{
|
|
|
|
if (IsFloatingPointType(CT->getElementType().getAsOpaquePtr(), count, is_complex))
|
|
|
|
{
|
|
|
|
count = 2;
|
|
|
|
is_complex = true;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else if (const VectorType *VT = dyn_cast<VectorType>(qual_type->getCanonicalTypeInternal()))
|
|
|
|
{
|
|
|
|
if (IsFloatingPointType(VT->getElementType().getAsOpaquePtr(), count, is_complex))
|
|
|
|
{
|
|
|
|
count = VT->getNumElements();
|
|
|
|
is_complex = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-10-15 06:52:14 +08:00
|
|
|
|
|
|
|
bool
|
|
|
|
ClangASTContext::GetCXXClassName (clang_type_t clang_type, std::string &class_name)
|
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
|
|
|
|
CXXRecordDecl *cxx_record_decl = qual_type->getAsCXXRecordDecl();
|
|
|
|
if (cxx_record_decl)
|
|
|
|
{
|
|
|
|
class_name.assign (cxx_record_decl->getIdentifier()->getNameStart());
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
class_name.clear();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-09-24 13:15:53 +08:00
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsCXXClassType (clang_type_t clang_type)
|
2010-09-24 13:15:53 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
if (qual_type->getAsCXXRecordDecl() != NULL)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsObjCClassType (clang_type_t clang_type)
|
2010-09-24 13:15:53 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
if (qual_type->isObjCObjectOrInterfaceType())
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2010-10-27 11:32:59 +08:00
|
|
|
bool
|
|
|
|
ClangASTContext::IsCharType (clang_type_t clang_type)
|
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
return QualType::getFromOpaquePtr(clang_type)->isCharType();
|
|
|
|
return false;
|
|
|
|
}
|
2010-06-09 00:52:24 +08:00
|
|
|
|
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsCStringType (clang_type_t clang_type, uint32_t &length)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-10-27 11:32:59 +08:00
|
|
|
clang_type_t pointee_or_element_clang_type = NULL;
|
|
|
|
Flags type_flags (ClangASTContext::GetTypeInfo (clang_type, NULL, &pointee_or_element_clang_type));
|
|
|
|
|
|
|
|
if (pointee_or_element_clang_type == NULL)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
if (type_flags.AnySet (eTypeIsArray | eTypeIsPointer))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-10-27 11:32:59 +08:00
|
|
|
QualType pointee_or_element_qual_type (QualType::getFromOpaquePtr (pointee_or_element_clang_type));
|
|
|
|
|
|
|
|
if (pointee_or_element_qual_type.getUnqualifiedType()->isCharType())
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-10-27 11:32:59 +08:00
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
if (type_flags.Test (eTypeIsArray))
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-10-27 11:32:59 +08:00
|
|
|
// We know the size of the array and it could be a C string
|
|
|
|
// since it is an array of characters
|
|
|
|
length = cast<ConstantArrayType>(qual_type.getTypePtr())->getSize().getLimitedValue();
|
|
|
|
return true;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
2010-10-27 11:32:59 +08:00
|
|
|
else
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-10-27 11:32:59 +08:00
|
|
|
length = 0;
|
|
|
|
return true;
|
2010-06-09 00:52:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-09-13 11:32:57 +08:00
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsFunctionPointerType (clang_type_t clang_type)
|
2010-09-13 11:32:57 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
|
|
|
|
if (qual_type->isFunctionPointerType())
|
|
|
|
return true;
|
|
|
|
|
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
|
|
|
{
|
|
|
|
case clang::Type::Typedef:
|
2010-12-13 09:26:27 +08:00
|
|
|
return ClangASTContext::IsFunctionPointerType (cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType().getAsOpaquePtr());
|
2010-09-13 11:32:57 +08:00
|
|
|
|
|
|
|
case clang::Type::LValueReference:
|
|
|
|
case clang::Type::RValueReference:
|
|
|
|
{
|
|
|
|
ReferenceType *reference_type = cast<ReferenceType>(qual_type.getTypePtr());
|
|
|
|
if (reference_type)
|
|
|
|
return ClangASTContext::IsFunctionPointerType (reference_type->getPointeeType().getAsOpaquePtr());
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2010-10-27 11:32:59 +08:00
|
|
|
size_t
|
|
|
|
ClangASTContext::GetArraySize (clang_type_t clang_type)
|
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
ConstantArrayType *array = cast<ConstantArrayType>(QualType::getFromOpaquePtr(clang_type).getTypePtr());
|
|
|
|
if (array)
|
|
|
|
return array->getSize().getLimitedValue();
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2010-09-13 11:32:57 +08:00
|
|
|
|
2010-06-09 00:52:24 +08:00
|
|
|
bool
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::IsArrayType (clang_type_t clang_type, clang_type_t*member_type, uint64_t *size)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (!clang_type)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
|
2010-09-13 11:32:57 +08:00
|
|
|
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
|
|
|
switch (type_class)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::ConstantArray:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (member_type)
|
|
|
|
*member_type = cast<ConstantArrayType>(qual_type)->getElementType().getAsOpaquePtr();
|
|
|
|
if (size)
|
|
|
|
*size = cast<ConstantArrayType>(qual_type)->getSize().getLimitedValue(ULONG_LONG_MAX);
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::IncompleteArray:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (member_type)
|
|
|
|
*member_type = cast<IncompleteArrayType>(qual_type)->getElementType().getAsOpaquePtr();
|
|
|
|
if (size)
|
|
|
|
*size = 0;
|
|
|
|
return true;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::VariableArray:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (member_type)
|
|
|
|
*member_type = cast<VariableArrayType>(qual_type)->getElementType().getAsOpaquePtr();
|
|
|
|
if (size)
|
|
|
|
*size = 0;
|
2010-07-22 06:12:05 +08:00
|
|
|
case clang::Type::DependentSizedArray:
|
2010-06-09 00:52:24 +08:00
|
|
|
if (member_type)
|
|
|
|
*member_type = cast<DependentSizedArrayType>(qual_type)->getElementType().getAsOpaquePtr();
|
|
|
|
if (size)
|
|
|
|
*size = 0;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#pragma mark Typedefs
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
clang_type_t
|
|
|
|
ClangASTContext::CreateTypedefType (const char *name, clang_type_t clang_type, DeclContext *decl_ctx)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
ASTContext *ast_context = getASTContext();
|
|
|
|
IdentifierTable *identifier_table = getIdentifierTable();
|
|
|
|
assert (ast_context != NULL);
|
|
|
|
assert (identifier_table != NULL);
|
|
|
|
if (decl_ctx == NULL)
|
|
|
|
decl_ctx = ast_context->getTranslationUnitDecl();
|
|
|
|
TypedefDecl *decl = TypedefDecl::Create(*ast_context,
|
|
|
|
decl_ctx,
|
|
|
|
SourceLocation(),
|
|
|
|
name ? &identifier_table->get(name) : NULL, // Identifier
|
|
|
|
ast_context->CreateTypeSourceInfo(qual_type));
|
|
|
|
|
|
|
|
// Get a uniqued QualType for the typedef decl type
|
|
|
|
return ast_context->getTypedefType (decl).getAsOpaquePtr();
|
|
|
|
}
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::string
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::GetTypeName (clang_type_t opaque_qual_type)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
std::string return_name;
|
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
QualType qual_type(QualType::getFromOpaquePtr(opaque_qual_type));
|
2010-06-09 00:52:24 +08:00
|
|
|
|
2010-09-29 09:12:09 +08:00
|
|
|
const TypedefType *typedef_type = qual_type->getAs<TypedefType>();
|
2010-06-09 00:52:24 +08:00
|
|
|
if (typedef_type)
|
|
|
|
{
|
2010-09-29 09:12:09 +08:00
|
|
|
const TypedefDecl *typedef_decl = typedef_type->getDecl();
|
2010-06-09 00:52:24 +08:00
|
|
|
return_name = typedef_decl->getQualifiedNameAsString();
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return_name = qual_type.getAsString();
|
|
|
|
}
|
|
|
|
|
|
|
|
return return_name;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Disable this for now since I can't seem to get a nicely formatted float
|
|
|
|
// out of the APFloat class without just getting the float, double or quad
|
|
|
|
// and then using a formatted print on it which defeats the purpose. We ideally
|
|
|
|
// would like to get perfect string values for any kind of float semantics
|
|
|
|
// so we can support remote targets. The code below also requires a patch to
|
|
|
|
// llvm::APInt.
|
|
|
|
//bool
|
2010-09-29 09:12:09 +08:00
|
|
|
//ClangASTContext::ConvertFloatValueToString (ASTContext *ast_context, clang_type_t clang_type, const uint8_t* bytes, size_t byte_size, int apint_byte_order, std::string &float_str)
|
2010-06-09 00:52:24 +08:00
|
|
|
//{
|
|
|
|
// uint32_t count = 0;
|
|
|
|
// bool is_complex = false;
|
|
|
|
// if (ClangASTContext::IsFloatingPointType (clang_type, count, is_complex))
|
|
|
|
// {
|
|
|
|
// unsigned num_bytes_per_float = byte_size / count;
|
|
|
|
// unsigned num_bits_per_float = num_bytes_per_float * 8;
|
|
|
|
//
|
|
|
|
// float_str.clear();
|
|
|
|
// uint32_t i;
|
|
|
|
// for (i=0; i<count; i++)
|
|
|
|
// {
|
|
|
|
// APInt ap_int(num_bits_per_float, bytes + i * num_bytes_per_float, (APInt::ByteOrder)apint_byte_order);
|
|
|
|
// bool is_ieee = false;
|
|
|
|
// APFloat ap_float(ap_int, is_ieee);
|
|
|
|
// char s[1024];
|
|
|
|
// unsigned int hex_digits = 0;
|
|
|
|
// bool upper_case = false;
|
|
|
|
//
|
|
|
|
// if (ap_float.convertToHexString(s, hex_digits, upper_case, APFloat::rmNearestTiesToEven) > 0)
|
|
|
|
// {
|
|
|
|
// if (i > 0)
|
|
|
|
// float_str.append(", ");
|
|
|
|
// float_str.append(s);
|
|
|
|
// if (i == 1 && is_complex)
|
|
|
|
// float_str.append(1, 'i');
|
|
|
|
// }
|
|
|
|
// }
|
|
|
|
// return !float_str.empty();
|
|
|
|
// }
|
|
|
|
// return false;
|
|
|
|
//}
|
|
|
|
|
|
|
|
size_t
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::ConvertStringToFloatValue (ASTContext *ast_context, clang_type_t clang_type, const char *s, uint8_t *dst, size_t dst_size)
|
2010-06-09 00:52:24 +08:00
|
|
|
{
|
|
|
|
if (clang_type)
|
|
|
|
{
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
uint32_t count = 0;
|
|
|
|
bool is_complex = false;
|
|
|
|
if (ClangASTContext::IsFloatingPointType (clang_type, count, is_complex))
|
|
|
|
{
|
|
|
|
// TODO: handle complex and vector types
|
|
|
|
if (count != 1)
|
|
|
|
return false;
|
|
|
|
|
|
|
|
StringRef s_sref(s);
|
|
|
|
APFloat ap_float(ast_context->getFloatTypeSemantics(qual_type), s_sref);
|
|
|
|
|
|
|
|
const uint64_t bit_size = ast_context->getTypeSize (qual_type);
|
|
|
|
const uint64_t byte_size = bit_size / 8;
|
|
|
|
if (dst_size >= byte_size)
|
|
|
|
{
|
|
|
|
if (bit_size == sizeof(float)*8)
|
|
|
|
{
|
|
|
|
float float32 = ap_float.convertToFloat();
|
|
|
|
::memcpy (dst, &float32, byte_size);
|
|
|
|
return byte_size;
|
|
|
|
}
|
|
|
|
else if (bit_size >= 64)
|
|
|
|
{
|
|
|
|
llvm::APInt ap_int(ap_float.bitcastToAPInt());
|
|
|
|
::memcpy (dst, ap_int.getRawData(), byte_size);
|
|
|
|
return byte_size;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
2010-09-17 10:24:29 +08:00
|
|
|
|
|
|
|
unsigned
|
2010-09-29 09:12:09 +08:00
|
|
|
ClangASTContext::GetTypeQualifiers(clang_type_t clang_type)
|
2010-09-17 10:24:29 +08:00
|
|
|
{
|
|
|
|
assert (clang_type);
|
|
|
|
|
|
|
|
QualType qual_type (QualType::getFromOpaquePtr(clang_type));
|
|
|
|
|
|
|
|
return qual_type.getQualifiers().getCVRQualifiers();
|
|
|
|
}
|