forked from OSchip/llvm-project
Adding a new API call IsTypeComplete() to SBType. This call is meant to check if the type has been previously completed or not (which is mostly interesting from a performance point of view)
Adding a test case that checks that we do not complete types before due time. This should help us track cases similar to the cascading data formatters. llvm-svn: 153363
This commit is contained in:
parent
25553ab5fe
commit
86027e954c
|
@ -134,6 +134,9 @@ public:
|
|||
|
||||
lldb::TypeClass
|
||||
GetTypeClass ();
|
||||
|
||||
bool
|
||||
IsTypeComplete ();
|
||||
|
||||
// DEPRECATED: but needed for Xcode right now
|
||||
static bool
|
||||
|
|
|
@ -127,6 +127,13 @@ public:
|
|||
GetCompleteType (clang::ASTContext *ast,
|
||||
lldb::clang_type_t clang_type);
|
||||
|
||||
bool
|
||||
IsCompleteType (lldb::clang_type_t clang_type);
|
||||
|
||||
static bool
|
||||
IsCompleteType (clang::ASTContext *ast,
|
||||
lldb::clang_type_t clang_type);
|
||||
|
||||
bool
|
||||
GetCompleteDecl (clang::Decl *decl)
|
||||
{
|
||||
|
|
|
@ -199,6 +199,9 @@ public:
|
|||
|
||||
lldb::TemplateArgumentKind
|
||||
GetTemplateArgumentKind (uint32_t idx);
|
||||
|
||||
bool
|
||||
IsTypeComplete ();
|
||||
|
||||
%pythoncode %{
|
||||
def template_arg_array(self):
|
||||
|
@ -239,7 +242,9 @@ public:
|
|||
|
||||
__swig_getmethods__["class"] = GetTypeClass
|
||||
if _newclass: x = property(GetTypeClass, None)
|
||||
|
||||
|
||||
__swig_getmethods__["is_complete"] = IsTypeComplete
|
||||
if _newclass: is_complete = property(IsTypeComplete, None)
|
||||
%}
|
||||
|
||||
};
|
||||
|
|
|
@ -426,6 +426,15 @@ SBType::GetFieldAtIndex (uint32_t idx)
|
|||
return sb_type_member;
|
||||
}
|
||||
|
||||
bool
|
||||
SBType::IsTypeComplete()
|
||||
{
|
||||
if (!IsValid())
|
||||
return false;
|
||||
|
||||
return ClangASTContext::IsCompleteType(m_opaque_sp->GetASTContext(), m_opaque_sp->GetOpaqueQualType());
|
||||
}
|
||||
|
||||
const char*
|
||||
SBType::GetName()
|
||||
{
|
||||
|
|
|
@ -78,7 +78,7 @@ using namespace clang;
|
|||
|
||||
|
||||
static bool
|
||||
GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type)
|
||||
GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type, bool allow_completion = true)
|
||||
{
|
||||
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
|
||||
switch (type_class)
|
||||
|
@ -88,7 +88,7 @@ GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type)
|
|||
const clang::ArrayType *array_type = dyn_cast<clang::ArrayType>(qual_type.getTypePtr());
|
||||
|
||||
if (array_type)
|
||||
return GetCompleteQualType (ast, array_type->getElementType());
|
||||
return GetCompleteQualType (ast, array_type->getElementType(), allow_completion);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -103,6 +103,9 @@ GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type)
|
|||
{
|
||||
if (tag_decl->getDefinition())
|
||||
return true;
|
||||
|
||||
if (!allow_completion)
|
||||
return false;
|
||||
|
||||
if (tag_decl->hasExternalLexicalStorage())
|
||||
{
|
||||
|
@ -137,6 +140,9 @@ GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type)
|
|||
if (class_interface_decl->getDefinition())
|
||||
return true;
|
||||
|
||||
if (!allow_completion)
|
||||
return false;
|
||||
|
||||
if (class_interface_decl->hasExternalLexicalStorage())
|
||||
{
|
||||
if (ast)
|
||||
|
@ -156,10 +162,10 @@ GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type)
|
|||
break;
|
||||
|
||||
case clang::Type::Typedef:
|
||||
return GetCompleteQualType (ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType());
|
||||
return GetCompleteQualType (ast, cast<TypedefType>(qual_type)->getDecl()->getUnderlyingType(), allow_completion);
|
||||
|
||||
case clang::Type::Elaborated:
|
||||
return GetCompleteQualType (ast, cast<ElaboratedType>(qual_type)->getNamedType());
|
||||
return GetCompleteQualType (ast, cast<ElaboratedType>(qual_type)->getNamedType(), allow_completion);
|
||||
|
||||
default:
|
||||
break;
|
||||
|
@ -168,7 +174,6 @@ GetCompleteQualType (clang::ASTContext *ast, clang::QualType qual_type)
|
|||
return true;
|
||||
}
|
||||
|
||||
|
||||
static AccessSpecifier
|
||||
ConvertAccessTypeToAccessSpecifier (AccessType access)
|
||||
{
|
||||
|
@ -6337,6 +6342,22 @@ ClangASTContext::GetCompleteType (clang_type_t clang_type)
|
|||
return ClangASTContext::GetCompleteType (getASTContext(), clang_type);
|
||||
}
|
||||
|
||||
bool
|
||||
ClangASTContext::IsCompleteType (clang::ASTContext *ast, lldb::clang_type_t clang_type)
|
||||
{
|
||||
if (clang_type == NULL)
|
||||
return false;
|
||||
|
||||
return GetCompleteQualType (ast, clang::QualType::getFromOpaquePtr(clang_type), false); // just check but don't let it actually complete
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
ClangASTContext::IsCompleteType (clang_type_t clang_type)
|
||||
{
|
||||
return ClangASTContext::IsCompleteType (getASTContext(), clang_type);
|
||||
}
|
||||
|
||||
bool
|
||||
ClangASTContext::GetCompleteDecl (clang::ASTContext *ast,
|
||||
clang::Decl *decl)
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
LEVEL = ../../make
|
||||
|
||||
CXX_SOURCES := main.cpp
|
||||
|
||||
include $(LEVEL)/Makefile.rules
|
|
@ -0,0 +1,139 @@
|
|||
"""
|
||||
Check that types only get completed when necessary.
|
||||
"""
|
||||
|
||||
import os, time
|
||||
import unittest2
|
||||
import lldb
|
||||
from lldbtest import *
|
||||
|
||||
class TypeCompletionTestCase(TestBase):
|
||||
|
||||
mydir = os.path.join("functionalities", "type_completion")
|
||||
|
||||
@unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin")
|
||||
def test_with_dsym_and_run_command(self):
|
||||
"""Check that types only get completed when necessary."""
|
||||
self.buildDsym()
|
||||
self.type_completion_commands()
|
||||
|
||||
def test_with_dwarf_and_run_command(self):
|
||||
"""Check that types only get completed when necessary."""
|
||||
self.buildDwarf()
|
||||
self.type_completion_commands()
|
||||
|
||||
def setUp(self):
|
||||
# Call super's setUp().
|
||||
TestBase.setUp(self)
|
||||
# Find the line number to break at.
|
||||
self.line = line_number('main.cpp', '// Set break point at this line.')
|
||||
|
||||
def type_completion_commands(self):
|
||||
"""Check that types only get completed when necessary."""
|
||||
self.runCmd("file a.out", CURRENT_EXECUTABLE_SET)
|
||||
|
||||
self.expect("breakpoint set -f main.cpp -l %d" % self.line,
|
||||
BREAKPOINT_CREATED,
|
||||
startstr = "Breakpoint created: 1: file ='main.cpp', line = %d" %
|
||||
self.line)
|
||||
|
||||
self.runCmd("run", RUN_SUCCEEDED)
|
||||
|
||||
# The stop reason of the thread should be breakpoint.
|
||||
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
|
||||
substrs = ['stopped',
|
||||
'stop reason = breakpoint'])
|
||||
|
||||
# This is the function to remove the custom formats in order to have a
|
||||
# clean slate for the next test case.
|
||||
def cleanup():
|
||||
self.runCmd('type category enable gnu-libstdc++', check=False)
|
||||
|
||||
self.runCmd('type category disable gnu-libstdc++', check=False)
|
||||
|
||||
# Execute the cleanup function during test case tear down.
|
||||
self.addTearDownHook(cleanup)
|
||||
|
||||
p_vector = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('p')
|
||||
p_type = p_vector.GetType()
|
||||
self.assertFalse(p_type.IsTypeComplete(), 'vector<T> complete but it should not be')
|
||||
|
||||
self.runCmd("next")
|
||||
self.runCmd("next")
|
||||
|
||||
p_vector = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('p')
|
||||
p_type = p_vector.GetType()
|
||||
self.assertFalse(p_type.IsTypeComplete(), 'vector<T> complete but it should not be')
|
||||
|
||||
self.runCmd("next")
|
||||
self.runCmd("next")
|
||||
|
||||
self.runCmd("frame variable p --show-types")
|
||||
|
||||
p_vector = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('p')
|
||||
p_type = p_vector.GetType()
|
||||
self.assertTrue(p_type.IsTypeComplete(), 'vector<T> should now be complete')
|
||||
name_address_type = p_type.GetTemplateArgumentType(0)
|
||||
self.assertTrue(name_address_type.IsValid(), 'NameAndAddress should be valid')
|
||||
self.assertFalse(name_address_type.IsTypeComplete(), 'NameAndAddress complete but it should not be')
|
||||
|
||||
self.runCmd("next")
|
||||
self.runCmd("next")
|
||||
|
||||
self.runCmd("frame variable guy --show-types")
|
||||
|
||||
p_vector = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('p')
|
||||
p_type = p_vector.GetType()
|
||||
self.assertTrue(p_type.IsTypeComplete(), 'vector<T> should now be complete')
|
||||
name_address_type = p_type.GetTemplateArgumentType(0)
|
||||
self.assertTrue(name_address_type.IsValid(), 'NameAndAddress should be valid')
|
||||
self.assertTrue(name_address_type.IsTypeComplete(), 'NameAndAddress should now be complete')
|
||||
field0 = name_address_type.GetFieldAtIndex(0)
|
||||
if self.TraceOn():
|
||||
print 'field0: ' + str(field0)
|
||||
self.assertTrue(field0.IsValid(), 'NameAndAddress::m_name should be valid')
|
||||
string = field0.GetType().GetPointeeType()
|
||||
if self.TraceOn():
|
||||
print 'string: ' + str(string)
|
||||
self.assertTrue(string.IsValid(), 'std::string should be valid')
|
||||
self.assertFalse(string.IsTypeComplete(), 'std::string complete but it should not be')
|
||||
|
||||
self.runCmd("next")
|
||||
self.runCmd("next")
|
||||
|
||||
p_vector = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('p')
|
||||
p_type = p_vector.GetType()
|
||||
self.assertTrue(p_type.IsTypeComplete(), 'vector<T> should now be complete')
|
||||
name_address_type = p_type.GetTemplateArgumentType(0)
|
||||
self.assertTrue(name_address_type.IsValid(), 'NameAndAddress should be valid')
|
||||
self.assertTrue(name_address_type.IsTypeComplete(), 'NameAndAddress should now be complete')
|
||||
field0 = name_address_type.GetFieldAtIndex(0)
|
||||
if self.TraceOn():
|
||||
print 'field0: ' + str(field0)
|
||||
self.assertTrue(field0.IsValid(), 'NameAndAddress::m_name should be valid')
|
||||
string = field0.GetType().GetPointeeType()
|
||||
if self.TraceOn():
|
||||
print 'string: ' + str(string)
|
||||
self.assertTrue(string.IsValid(), 'std::string should be valid')
|
||||
self.assertFalse(string.IsTypeComplete(), 'std::string complete but it should not be')
|
||||
|
||||
self.runCmd('type category enable gnu-libstdc++', check=False)
|
||||
self.runCmd('frame variable guy --show-types')
|
||||
|
||||
p_vector = self.dbg.GetSelectedTarget().GetProcess().GetSelectedThread().GetSelectedFrame().FindVariable('p')
|
||||
p_type = p_vector.GetType()
|
||||
self.assertTrue(p_type.IsTypeComplete(), 'vector<T> should now be complete')
|
||||
name_address_type = p_type.GetTemplateArgumentType(0)
|
||||
self.assertTrue(name_address_type.IsValid(), 'NameAndAddress should be valid')
|
||||
self.assertTrue(name_address_type.IsTypeComplete(), 'NameAndAddress should now be complete')
|
||||
field0 = name_address_type.GetFieldAtIndex(0)
|
||||
self.assertTrue(field0.IsValid(), 'NameAndAddress::m_name should be valid')
|
||||
string = field0.GetType().GetPointeeType()
|
||||
self.assertTrue(string.IsValid(), 'std::string should be valid')
|
||||
self.assertTrue(string.IsTypeComplete(), 'std::string should now be complete')
|
||||
|
||||
if __name__ == '__main__':
|
||||
import atexit
|
||||
lldb.SBDebugger.Initialize()
|
||||
atexit.register(lambda: lldb.SBDebugger.Terminate())
|
||||
unittest2.main()
|
|
@ -0,0 +1,52 @@
|
|||
//===-- main.cpp ------------------------------------------------*- C++ -*-===//
|
||||
//
|
||||
// The LLVM Compiler Infrastructure
|
||||
//
|
||||
// This file is distributed under the University of Illinois Open Source
|
||||
// License. See LICENSE.TXT for details.
|
||||
//
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <iostream>
|
||||
|
||||
class NameAndAddress
|
||||
{
|
||||
public:
|
||||
std::string& GetName() { return *m_name; }
|
||||
std::string& GetAddress() { return *m_address; }
|
||||
NameAndAddress(const char* N, const char* A) : m_name(new std::string(N)), m_address(new std::string(A))
|
||||
{
|
||||
}
|
||||
~NameAndAddress()
|
||||
{
|
||||
}
|
||||
|
||||
private:
|
||||
std::string* m_name;
|
||||
std::string* m_address;
|
||||
};
|
||||
|
||||
typedef std::vector<NameAndAddress> People;
|
||||
|
||||
int main (int argc, const char * argv[])
|
||||
{
|
||||
People p;
|
||||
p.push_back(NameAndAddress("Enrico","123 Main Street"));
|
||||
p.push_back(NameAndAddress("Foo","10710 Johnson Avenue")); // Set break point at this line.
|
||||
p.push_back(NameAndAddress("Arpia","6956 Florey Street"));
|
||||
p.push_back(NameAndAddress("Apple","1 Infinite Loop"));
|
||||
p.push_back(NameAndAddress("Richard","9500 Gilman Drive"));
|
||||
p.push_back(NameAndAddress("Bar","3213 Windsor Rd"));
|
||||
|
||||
for (int j = 0; j<p.size(); j++)
|
||||
{
|
||||
NameAndAddress guy = p[j];
|
||||
std::cout << "Person " << j << " is named " << guy.GetName() << " and lives at " << guy.GetAddress() << std::endl;
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue