Skip to content

[lldb] Fix expressions that involve nested structs/classes/unions. #77029

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Jan 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
13 changes: 12 additions & 1 deletion lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2150,6 +2150,7 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
SymbolFileDWARF *dwarf = die.GetDWARF();

ClangASTImporter::LayoutInfo layout_info;
std::vector<DWARFDIE> contained_type_dies;

if (die.HasChildren()) {
const bool type_is_objc_object_or_interface =
Expand All @@ -2175,7 +2176,8 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,

DelayedPropertyList delayed_properties;
ParseChildMembers(die, clang_type, bases, member_function_dies,
delayed_properties, default_accessibility, layout_info);
contained_type_dies, delayed_properties,
default_accessibility, layout_info);

// Now parse any methods if there were any...
for (const DWARFDIE &die : member_function_dies)
Expand Down Expand Up @@ -2231,6 +2233,12 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
if (record_decl)
GetClangASTImporter().SetRecordLayout(record_decl, layout_info);
}
// Now parse all contained types inside of the class. We make forward
// declarations to all classes, but we need the CXXRecordDecl to have decls
// for all contained types because we don't get asked for them via the
// external AST support.
for (const DWARFDIE &die : contained_type_dies)
dwarf->ResolveType(die);

return (bool)clang_type;
}
Expand Down Expand Up @@ -3110,6 +3118,7 @@ bool DWARFASTParserClang::ParseChildMembers(
const DWARFDIE &parent_die, CompilerType &class_clang_type,
std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes,
std::vector<DWARFDIE> &member_function_dies,
std::vector<DWARFDIE> &contained_type_dies,
DelayedPropertyList &delayed_properties,
const AccessType default_accessibility,
ClangASTImporter::LayoutInfo &layout_info) {
Expand Down Expand Up @@ -3159,6 +3168,8 @@ bool DWARFASTParserClang::ParseChildMembers(
break;

default:
if (llvm::dwarf::isType(tag))
contained_type_dies.push_back(die);
break;
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,7 @@ class DWARFASTParserClang : public lldb_private::plugin::dwarf::DWARFASTParser {
lldb_private::CompilerType &class_compiler_type,
std::vector<std::unique_ptr<clang::CXXBaseSpecifier>> &base_classes,
std::vector<lldb_private::plugin::dwarf::DWARFDIE> &member_function_dies,
std::vector<lldb_private::plugin::dwarf::DWARFDIE> &contained_type_dies,
DelayedPropertyList &delayed_properties,
const lldb::AccessType default_accessibility,
lldb_private::ClangASTImporter::LayoutInfo &layout_info);
Expand Down
3 changes: 3 additions & 0 deletions lldb/test/API/commands/expression/nested/Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
CXX_SOURCES := main.cpp

include Makefile.rules
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
"""
Test calling an expression with errors that a FixIt can fix.
"""

import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
from lldbsuite.test import lldbutil


class NestedExpressions(TestBase):

def test_enum_in_nested_structs(self):
"""
Test expressions that references an enumeration in nested structs.
"""
self.build()
exe_path = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe_path)
self.assertTrue(target, "Target: %s is not valid." % (exe_path))
self.expect_expr("A::B::C::EnumType::Eleven",
result_type="A::B::C::EnumType",
result_value="Eleven")

def test_struct_in_nested_structs(self):
"""
Test expressions that references a struct in nested structs.
"""
self.build()
exe_path = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe_path)
self.assertTrue(target, "Target: %s is not valid." % (exe_path))
self.expect_expr("sizeof(A::B::C)", result_value="1")
self.expect_expr("sizeof(A::B)", result_value="2")

def test_static_in_nested_structs(self):
"""
Test expressions that references a static variable in nested structs.
"""
self.build()
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "Stop here to evaluate expressions", lldb.SBFileSpec("main.cpp")
)
self.expect_expr("A::B::C::enum_static",
result_type="A::B::C::EnumType",
result_value="Eleven")

def test_enum_in_nested_namespaces(self):
"""
Test expressions that references an enumeration in nested namespaces.
"""
self.build()
exe_path = self.getBuildArtifact("a.out")
target = self.dbg.CreateTarget(exe_path)
self.assertTrue(target, "Target: %s is not valid." % (exe_path))
self.expect_expr("a::b::c::Color::Blue",
result_type="a::b::c::Color",
result_value="Blue")

def test_static_in_nested_namespaces(self):
"""
Test expressions that references an enumeration in nested namespaces.
"""
self.build()
(target, process, thread, bkpt) = lldbutil.run_to_source_breakpoint(
self, "Stop here to evaluate expressions", lldb.SBFileSpec("main.cpp")
)
self.expect_expr("a::b::c::d",
result_type="int",
result_value="12")
31 changes: 31 additions & 0 deletions lldb/test/API/commands/expression/nested/main.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
namespace a {
namespace b {
namespace c {
static int d = 12;
enum Color { Red, Green, Blue };
} // namespace c
} // namespace b
} // namespace a

struct A {
int _a = 'a';
struct B {
short _b = 'b';
struct C {
char _c = 'c';
enum EnumType : int { Eleven = 11 };
static EnumType enum_static;
};
};
};

A::B::C::EnumType A::B::C::enum_static = A::B::C::Eleven;

int foo() {
a::b::c::Color color = a::b::c::Blue;
return A::B::C::enum_static == a::b::c::d && ((int)color == 0);
}

int main() {
return foo(); // Stop here to evaluate expressions
}