blob: 6bf4338535846df719fe475c2ccd11afc75908a2 [file] [log] [blame]
//===-- TypeHierarchyNavigator.cpp -----------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "lldb/Core/Error.h"
#include "lldb/Core/ValueObject.h"
#include "lldb/Symbol/ClangASTContext.h"
#include "lldb/Symbol/TypeHierarchyNavigator.h"
using namespace lldb;
using namespace lldb_private;
bool
TypeHierarchyNavigator::LoopThrough(TypeHierarchyNavigatorCallback callback,
void* callback_baton)
{
return LoopThrough(m_root_type,
callback,
eRootType,
(callback_baton ? callback_baton : m_default_callback_baton));
}
bool
TypeHierarchyNavigator::LoopThrough(const clang::QualType& qual_type,
TypeHierarchyNavigatorCallback callback,
RelationshipToCurrentType reason_why_here,
void* callback_baton)
{
if (qual_type.isNull())
return true;
clang::QualType type = qual_type.getUnqualifiedType();
type.removeLocalConst(); type.removeLocalVolatile(); type.removeLocalRestrict();
const clang::Type* typePtr = type.getTypePtrOrNull();
if (!typePtr)
return true;
if (!callback(type, reason_why_here, callback_baton))
return false;
// look for a "base type", whatever that means
if (typePtr->isReferenceType())
{
if (LoopThrough(type.getNonReferenceType(), callback, eStrippedReference, callback_baton) == false)
return false;
}
if (typePtr->isPointerType())
{
if (LoopThrough(typePtr->getPointeeType(), callback, eStrippedPointer, callback_baton) == false)
return false;
}
if (typePtr->isObjCObjectPointerType())
{
/*
for some reason, C++ can quite easily obtain the type hierarchy for a ValueObject
even if the VO represent a pointer-to-class, as long as the typePtr is right
Objective-C on the other hand cannot really complete an @interface when
the VO refers to a pointer-to-@interface
*/
Error error;
ValueObject* target = m_value_object.Dereference(error).get();
if (error.Fail() || !target)
return true;
if (LoopThrough(typePtr->getPointeeType(), callback, eStrippedPointer, callback_baton) == false)
return false;
}
const clang::ObjCObjectType *objc_class_type = typePtr->getAs<clang::ObjCObjectType>();
if (objc_class_type)
{
clang::ASTContext *ast = m_value_object.GetClangAST();
if (ClangASTContext::GetCompleteType(ast, m_value_object.GetClangType()) && !objc_class_type->isObjCId())
{
clang::ObjCInterfaceDecl *class_interface_decl = objc_class_type->getInterface();
if (class_interface_decl)
{
clang::ObjCInterfaceDecl *superclass_interface_decl = class_interface_decl->getSuperClass();
if (superclass_interface_decl)
{
clang::QualType ivar_qual_type(ast->getObjCInterfaceType(superclass_interface_decl));
return LoopThrough(ivar_qual_type, callback, eObjCBaseClass, callback_baton);
}
}
}
}
// for C++ classes, navigate up the hierarchy
if (typePtr->isRecordType())
{
clang::CXXRecordDecl* record = typePtr->getAsCXXRecordDecl();
if (record)
{
if (!record->hasDefinition())
ClangASTContext::GetCompleteType(m_value_object.GetClangAST(), m_value_object.GetClangType());
if (record->hasDefinition())
{
clang::CXXRecordDecl::base_class_iterator pos,end;
if ( record->getNumBases() > 0)
{
end = record->bases_end();
for (pos = record->bases_begin(); pos != end; pos++)
if (LoopThrough(pos->getType(), callback, eCXXBaseClass, callback_baton) == false)
return false;
}
if (record->getNumVBases() > 0)
{
end = record->vbases_end();
for (pos = record->vbases_begin(); pos != end; pos++)
if (LoopThrough(pos->getType(), callback, eCXXVBaseClass, callback_baton) == false)
return false;
}
}
}
}
// try to strip typedef chains
const clang::TypedefType* type_tdef = type->getAs<clang::TypedefType>();
if (type_tdef)
return LoopThrough(type_tdef->getDecl()->getUnderlyingType(), callback, eStrippedTypedef, callback_baton);
else
return true;
}