From 1ac6296376f47314cf5bd7ad2a1b2fc85e118ca5 Mon Sep 17 00:00:00 2001 From: Enrico Granata Date: Thu, 10 Apr 2014 00:14:07 +0000 Subject: [PATCH] Enable data formatters to see-through pointers/references to typedefs For instance, if Foo is a typedef to Bar, and there is a formatter for any/all of Bar*, Bar&, Bar&&, then Foo*, Foo&, and Foo&& should pick these up if Foo-specific formatters don't exist llvm-svn: 205939 --- lldb/include/lldb/Symbol/ClangASTType.h | 2 +- lldb/source/DataFormatters/FormatManager.cpp | 32 ++++++++- lldb/source/Symbol/ClangASTType.cpp | 14 ++-- .../data-formatter/ptr_ref_typedef/Makefile | 7 ++ .../ptr_ref_typedef/TestPtrRef2Typedef.py | 68 +++++++++++++++++++ .../data-formatter/ptr_ref_typedef/main.cpp | 19 ++++++ 6 files changed, 133 insertions(+), 9 deletions(-) create mode 100644 lldb/test/functionalities/data-formatter/ptr_ref_typedef/Makefile create mode 100644 lldb/test/functionalities/data-formatter/ptr_ref_typedef/TestPtrRef2Typedef.py create mode 100644 lldb/test/functionalities/data-formatter/ptr_ref_typedef/main.cpp diff --git a/lldb/include/lldb/Symbol/ClangASTType.h b/lldb/include/lldb/Symbol/ClangASTType.h index d3a98b951605..0f2eb965ca67 100644 --- a/lldb/include/lldb/Symbol/ClangASTType.h +++ b/lldb/include/lldb/Symbol/ClangASTType.h @@ -213,7 +213,7 @@ public: IsPointerOrReferenceType (ClangASTType *pointee_type = NULL) const; bool - IsReferenceType (ClangASTType *pointee_type = NULL) const; + IsReferenceType (ClangASTType *pointee_type = nullptr, bool* is_rvalue = nullptr) const; bool IsScalarType () const; diff --git a/lldb/source/DataFormatters/FormatManager.cpp b/lldb/source/DataFormatters/FormatManager.cpp index 2f026b50a28b..0ccb826bd82f 100644 --- a/lldb/source/DataFormatters/FormatManager.cpp +++ b/lldb/source/DataFormatters/FormatManager.cpp @@ -185,8 +185,8 @@ FormatManager::GetPossibleMatches (ValueObject& valobj, reason |= lldb_private::eFormatterChoiceCriterionStrippedBitField; } entries.push_back({type_name,reason,did_strip_ptr,did_strip_ref,did_strip_typedef}); - - if (clang_type.IsReferenceType()) + + for (bool is_rvalue_ref = true, j = true; j && clang_type.IsReferenceType(nullptr, &is_rvalue_ref); j = false) { ClangASTType non_ref_type = clang_type.GetNonReferenceType(); GetPossibleMatches(valobj, @@ -197,8 +197,22 @@ FormatManager::GetPossibleMatches (ValueObject& valobj, did_strip_ptr, true, did_strip_typedef); + if (non_ref_type.IsTypedefType()) + { + ClangASTType deffed_referenced_type = non_ref_type.GetTypedefedType(); + deffed_referenced_type = is_rvalue_ref ? deffed_referenced_type.GetRValueReferenceType() : deffed_referenced_type.GetLValueReferenceType(); + GetPossibleMatches(valobj, + deffed_referenced_type, + reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs, + use_dynamic, + entries, + did_strip_ptr, + did_strip_ref, + true); // this is not exactly the usual meaning of stripping typedefs + } } - else if (clang_type.IsPointerType()) + + if (clang_type.IsPointerType()) { ClangASTType non_ptr_type = clang_type.GetPointeeType(); GetPossibleMatches(valobj, @@ -209,6 +223,18 @@ FormatManager::GetPossibleMatches (ValueObject& valobj, true, did_strip_ref, did_strip_typedef); + if (non_ptr_type.IsTypedefType()) + { + ClangASTType deffed_pointed_type = non_ptr_type.GetTypedefedType().GetPointerType(); + GetPossibleMatches(valobj, + deffed_pointed_type, + reason | lldb_private::eFormatterChoiceCriterionNavigatedTypedefs, + use_dynamic, + entries, + did_strip_ptr, + did_strip_ref, + true); // this is not exactly the usual meaning of stripping typedefs + } } bool canBeObjCDynamic = clang_type.IsPossibleDynamicType (NULL, false, // no C diff --git a/lldb/source/Symbol/ClangASTType.cpp b/lldb/source/Symbol/ClangASTType.cpp index 0ef6afd72306..729acf35fba5 100644 --- a/lldb/source/Symbol/ClangASTType.cpp +++ b/lldb/source/Symbol/ClangASTType.cpp @@ -680,7 +680,7 @@ ClangASTType::IsPointerOrReferenceType (ClangASTType *pointee_type) const return true; case clang::Type::RValueReference: if (pointee_type) - pointee_type->SetClangType(m_ast, cast(qual_type)->desugar()); + pointee_type->SetClangType(m_ast, cast(qual_type)->desugar()); return true; case clang::Type::Typedef: return ClangASTType (m_ast, cast(qual_type)->getDecl()->getUnderlyingType()).IsPointerOrReferenceType(pointee_type); @@ -699,7 +699,7 @@ ClangASTType::IsPointerOrReferenceType (ClangASTType *pointee_type) const bool -ClangASTType::IsReferenceType (ClangASTType *pointee_type) const +ClangASTType::IsReferenceType (ClangASTType *pointee_type, bool* is_rvalue) const { if (IsValid()) { @@ -711,17 +711,21 @@ ClangASTType::IsReferenceType (ClangASTType *pointee_type) const case clang::Type::LValueReference: if (pointee_type) pointee_type->SetClangType(m_ast, cast(qual_type)->desugar()); + if (is_rvalue) + *is_rvalue = false; return true; case clang::Type::RValueReference: if (pointee_type) pointee_type->SetClangType(m_ast, cast(qual_type)->desugar()); + if (is_rvalue) + *is_rvalue = true; return true; case clang::Type::Typedef: - return ClangASTType(m_ast, cast(qual_type)->getDecl()->getUnderlyingType()).IsReferenceType(pointee_type); + return ClangASTType(m_ast, cast(qual_type)->getDecl()->getUnderlyingType()).IsReferenceType(pointee_type, is_rvalue); case clang::Type::Elaborated: - return ClangASTType(m_ast, cast(qual_type)->getNamedType()).IsReferenceType(pointee_type); + return ClangASTType(m_ast, cast(qual_type)->getNamedType()).IsReferenceType(pointee_type, is_rvalue); case clang::Type::Paren: - return ClangASTType(m_ast, cast(qual_type)->desugar()).IsReferenceType(pointee_type); + return ClangASTType(m_ast, cast(qual_type)->desugar()).IsReferenceType(pointee_type, is_rvalue); default: break; diff --git a/lldb/test/functionalities/data-formatter/ptr_ref_typedef/Makefile b/lldb/test/functionalities/data-formatter/ptr_ref_typedef/Makefile new file mode 100644 index 000000000000..d85e665333ea --- /dev/null +++ b/lldb/test/functionalities/data-formatter/ptr_ref_typedef/Makefile @@ -0,0 +1,7 @@ +LEVEL = ../../../make + +CXX_SOURCES := main.cpp + +CFLAGS_EXTRAS += -std=c++11 + +include $(LEVEL)/Makefile.rules diff --git a/lldb/test/functionalities/data-formatter/ptr_ref_typedef/TestPtrRef2Typedef.py b/lldb/test/functionalities/data-formatter/ptr_ref_typedef/TestPtrRef2Typedef.py new file mode 100644 index 000000000000..74f7b9adee40 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/ptr_ref_typedef/TestPtrRef2Typedef.py @@ -0,0 +1,68 @@ +""" +Test lldb data formatter subsystem. +""" + +import os, time +import unittest2 +import lldb +from lldbtest import * +import lldbutil + +class PtrRef2TypedefTestCase(TestBase): + + mydir = TestBase.compute_mydir(__file__) + + @unittest2.skipUnless(sys.platform.startswith("darwin"), "requires Darwin") + @dsym_test + def test_with_dsym_and_run_command(self): + """Test data formatter commands.""" + self.buildDsym() + self.data_formatter_commands() + + @dwarf_test + def test_with_dwarf_and_run_command(self): + """Test data formatter commands.""" + self.buildDwarf() + self.data_formatter_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 breakpoint here') + + def data_formatter_commands(self): + """Test that a pointer/reference to a typedef is formatted as we want.""" + self.runCmd("file a.out", CURRENT_EXECUTABLE_SET) + + lldbutil.run_break_set_by_file_and_line (self, "main.cpp", self.line, num_expected_locations=1, loc_exact=True) + + 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 format clear', check=False) + self.runCmd('type summary clear', check=False) + + # Execute the cleanup function during test case tear down. + self.addTearDownHook(cleanup) + + self.runCmd('type summary add --cascade true -s "IntPointer" "int *"') + self.runCmd('type summary add --cascade true -s "IntLRef" "int &"') + self.runCmd('type summary add --cascade true -s "IntRRef" "int &&"') + + self.expect("frame variable x", substrs = ['(Foo *) x = 0x','IntPointer']) + self.expect("frame variable y", substrs = ['(Foo &) y = 0x','IntLRef']) + self.expect("frame variable z", substrs = ['(Foo &&) z = 0x','IntRRef']) + +if __name__ == '__main__': + import atexit + lldb.SBDebugger.Initialize() + atexit.register(lambda: lldb.SBDebugger.Terminate()) + unittest2.main() diff --git a/lldb/test/functionalities/data-formatter/ptr_ref_typedef/main.cpp b/lldb/test/functionalities/data-formatter/ptr_ref_typedef/main.cpp new file mode 100644 index 000000000000..219f398da3f5 --- /dev/null +++ b/lldb/test/functionalities/data-formatter/ptr_ref_typedef/main.cpp @@ -0,0 +1,19 @@ +//===-- main.cpp ------------------------------------------------*- C++ -*-===// +// +// The LLVM Compiler Infrastructure +// +// This file is distributed under the University of Illinois Open Source +// License. See LICENSE.TXT for details. +// +//===----------------------------------------------------------------------===// + +typedef int Foo; + +int main() { + int lval = 1; + Foo* x = &lval; + Foo& y = lval; + Foo&& z = 1; + return 0; // Set breakpoint here +} +