| //===-- 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; |
| } |