summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--lldb/include/lldb/API/SBType.h3
-rw-r--r--lldb/include/lldb/Symbol/ClangASTContext.h7
-rw-r--r--lldb/scripts/Python/interface/SBType.i7
-rw-r--r--lldb/source/API/SBType.cpp9
-rw-r--r--lldb/source/Symbol/ClangASTContext.cpp31
-rw-r--r--lldb/test/functionalities/type_completion/Makefile5
-rw-r--r--lldb/test/functionalities/type_completion/TestTypeCompletion.py139
-rw-r--r--lldb/test/functionalities/type_completion/main.cpp52
8 files changed, 247 insertions, 6 deletions
diff --git a/lldb/include/lldb/API/SBType.h b/lldb/include/lldb/API/SBType.h
index ef61614d017..9ad2e062a1b 100644
--- a/lldb/include/lldb/API/SBType.h
+++ b/lldb/include/lldb/API/SBType.h
@@ -134,6 +134,9 @@ public:
lldb::TypeClass
GetTypeClass ();
+
+ bool
+ IsTypeComplete ();
// DEPRECATED: but needed for Xcode right now
static bool
diff --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h
index d39de6f215b..a6ee36686cf 100644
--- a/lldb/include/lldb/Symbol/ClangASTContext.h
+++ b/lldb/include/lldb/Symbol/ClangASTContext.h
@@ -128,6 +128,13 @@ public:
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)
{
return ClangASTContext::GetCompleteDecl(getASTContext(), decl);
diff --git a/lldb/scripts/Python/interface/SBType.i b/lldb/scripts/Python/interface/SBType.i
index 4c84b2d816e..2b1d972fd8a 100644
--- a/lldb/scripts/Python/interface/SBType.i
+++ b/lldb/scripts/Python/interface/SBType.i
@@ -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)
%}
};
diff --git a/lldb/source/API/SBType.cpp b/lldb/source/API/SBType.cpp
index 52f173f8300..f1d651faf3e 100644
--- a/lldb/source/API/SBType.cpp
+++ b/lldb/source/API/SBType.cpp
@@ -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()
{
diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp
index 4abedef1c5a..3a78854db84 100644
--- a/lldb/source/Symbol/ClangASTContext.cpp
+++ b/lldb/source/Symbol/ClangASTContext.cpp
@@ -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)
{
@@ -6338,6 +6343,22 @@ ClangASTContext::GetCompleteType (clang_type_t 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)
{
diff --git a/lldb/test/functionalities/type_completion/Makefile b/lldb/test/functionalities/type_completion/Makefile
new file mode 100644
index 00000000000..8a7102e347a
--- /dev/null
+++ b/lldb/test/functionalities/type_completion/Makefile
@@ -0,0 +1,5 @@
+LEVEL = ../../make
+
+CXX_SOURCES := main.cpp
+
+include $(LEVEL)/Makefile.rules
diff --git a/lldb/test/functionalities/type_completion/TestTypeCompletion.py b/lldb/test/functionalities/type_completion/TestTypeCompletion.py
new file mode 100644
index 00000000000..5e214512313
--- /dev/null
+++ b/lldb/test/functionalities/type_completion/TestTypeCompletion.py
@@ -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()
diff --git a/lldb/test/functionalities/type_completion/main.cpp b/lldb/test/functionalities/type_completion/main.cpp
new file mode 100644
index 00000000000..33ff3b05413
--- /dev/null
+++ b/lldb/test/functionalities/type_completion/main.cpp
@@ -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;
+
+}
+
OpenPOWER on IntegriCloud