diff options
-rw-r--r-- | lldb/include/lldb/API/SBType.h | 3 | ||||
-rw-r--r-- | lldb/include/lldb/Symbol/ClangASTContext.h | 7 | ||||
-rw-r--r-- | lldb/scripts/Python/interface/SBType.i | 7 | ||||
-rw-r--r-- | lldb/source/API/SBType.cpp | 9 | ||||
-rw-r--r-- | lldb/source/Symbol/ClangASTContext.cpp | 31 | ||||
-rw-r--r-- | lldb/test/functionalities/type_completion/Makefile | 5 | ||||
-rw-r--r-- | lldb/test/functionalities/type_completion/TestTypeCompletion.py | 139 | ||||
-rw-r--r-- | lldb/test/functionalities/type_completion/main.cpp | 52 |
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; + +} + |