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:
Enrico Granata 2012-03-24 01:11:14 +00:00
parent 25553ab5fe
commit 86027e954c
8 changed files with 247 additions and 6 deletions

View File

@ -134,6 +134,9 @@ public:
lldb::TypeClass
GetTypeClass ();
bool
IsTypeComplete ();
// DEPRECATED: but needed for Xcode right now
static bool

View File

@ -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)
{

View File

@ -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)
%}
};

View File

@ -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()
{

View File

@ -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)

View File

@ -0,0 +1,5 @@
LEVEL = ../../make
CXX_SOURCES := main.cpp
include $(LEVEL)/Makefile.rules

View File

@ -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()

View File

@ -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;
}