werat updated this revision to Diff 315343.
werat added a comment.
Generate fully qualified names for enum constants.
Repository:
rG LLVM Github Monorepo
CHANGES SINCE LAST ACTION
https://reviews.llvm.org/D94077/new/
https://reviews.llvm.org/D94077
Files:
lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
lldb/test/API/lang/cpp/enum_types/TestCPP11EnumTypes.py
lldb/test/API/lang/cpp/enum_types/main.cpp
lldb/test/API/python_api/target/globals/Makefile
lldb/test/API/python_api/target/globals/TestTargetGlobals.py
lldb/test/API/python_api/target/globals/main.cpp
Index: lldb/test/API/python_api/target/globals/main.cpp
===================================================================
--- /dev/null
+++ lldb/test/API/python_api/target/globals/main.cpp
@@ -0,0 +1,22 @@
+namespace A {
+enum AEnum { eMany = 0 } ae;
+};
+
+struct B {
+ enum BEnum { eMany = 1 } be;
+} b;
+
+enum CEnum { eMany = 2 } ce;
+
+enum MyEnum {
+ eFirst,
+} my_enum;
+
+enum class MyScopedEnum {
+ eFoo = 1,
+ eBar,
+} my_scoped_enum;
+
+int eFoo = 2;
+
+int main() {}
Index: lldb/test/API/python_api/target/globals/TestTargetGlobals.py
===================================================================
--- /dev/null
+++ lldb/test/API/python_api/target/globals/TestTargetGlobals.py
@@ -0,0 +1,46 @@
+"""
+Test SBTarget::FindGlobalVariables API.
+"""
+
+from lldbsuite.test.decorators import *
+from lldbsuite.test.lldbtest import *
+
+class TargetAPITestCase(TestBase):
+
+ mydir = TestBase.compute_mydir(__file__)
+
+ @add_test_categories(['pyapi'])
+ def test_find_global_variables(self):
+ """Exercise SBTarget.FindGlobalVariables() API."""
+ self.build()
+
+ # Don't need to launch a process, since we're only interested in
+ # looking up global variables.
+ target = self.dbg.CreateTarget(self.getBuildArtifact())
+
+ def test_global_var(query, name, type_name, value):
+ value_list = target.FindGlobalVariables(query, 1)
+ self.assertEqual(value_list.GetSize(), 1)
+ var = value_list.GetValueAtIndex(0)
+ self.DebugSBValue(var)
+ self.assertTrue(var)
+ self.assertEqual(var.GetName(), name)
+ self.assertEqual(var.GetTypeName(), type_name)
+ self.assertEqual(var.GetValue(), value)
+
+ test_global_var("eFirst", "::eFirst", "MyEnum", "eFirst")
+ test_global_var("A::eMany", "A::eMany", "A::AEnum", "eMany")
+
+ # Global variable eFoo is looked up fine, since scoped enumeration
+ # members are not available as constants in the surrounding scope.
+ test_global_var("eFoo", "::eFoo", "int", "2")
+
+ # eBar is not available since it's a member of a scoped enumeration.
+ value_list = target.FindGlobalVariables("eBar", 1)
+ self.assertEqual(value_list.GetSize(), 0)
+
+ # Get enumerator values from all scopes.
+ value_list = target.FindGlobalVariables("eMany", 100500)
+ self.assertEqual(value_list.GetSize(), 3)
+ value_types = {value.GetTypeName() for value in value_list}
+ self.assertEqual(value_types, {"A::AEnum", "B::BEnum", "CEnum"})
Index: lldb/test/API/python_api/target/globals/Makefile
===================================================================
--- /dev/null
+++ lldb/test/API/python_api/target/globals/Makefile
@@ -0,0 +1,3 @@
+CXX_SOURCES := main.cpp
+
+include Makefile.rules
Index: lldb/test/API/lang/cpp/enum_types/main.cpp
===================================================================
--- lldb/test/API/lang/cpp/enum_types/main.cpp
+++ lldb/test/API/lang/cpp/enum_types/main.cpp
@@ -25,4 +25,44 @@
DEFINE_UNSIGNED_ENUM(ull, unsigned long long)
DEFINE_SIGNED_ENUM(ll, signed long long)
-int main(int argc, char const *argv[]) { return 0; }
+enum MyEnum {
+ eFoo = 1,
+};
+MyEnum my_enum = eFoo;
+
+enum class MyScopedEnum {
+ eBar = 1,
+};
+MyScopedEnum my_scoped_enum = MyScopedEnum::eBar;
+
+int x = 2;
+
+enum CEnum { eValue = 2 } ce;
+
+namespace A {
+
+enum AEnum { eValue = 0 } ae;
+
+void g() {
+ // break here
+}
+
+}; // namespace A
+
+struct B {
+ enum BEnum { eValue = 1 } be;
+
+ void f() {
+ // break here
+ }
+};
+
+int main() {
+ A::g();
+
+ B b;
+ b.f();
+
+ // break here
+ return 0;
+}
Index: lldb/test/API/lang/cpp/enum_types/TestCPP11EnumTypes.py
===================================================================
--- lldb/test/API/lang/cpp/enum_types/TestCPP11EnumTypes.py
+++ lldb/test/API/lang/cpp/enum_types/TestCPP11EnumTypes.py
@@ -1,9 +1,7 @@
"""Look up enum type information and check for correct display."""
-import lldb
from lldbsuite.test.decorators import *
from lldbsuite.test.lldbtest import *
-import lldbsuite.test.lldbutil as lldbutil
class CPP11EnumTypesTestCase(TestBase):
@@ -51,3 +49,32 @@
self.check_enum("l")
self.check_enum("ull")
self.check_enum("ll")
+
+ self.expect_expr("eFoo", result_type="MyEnum", result_value="eFoo")
+ self.expect_expr("MyEnum::eFoo", result_type="MyEnum", result_value="eFoo")
+ self.expect_expr("my_enum + eFoo + MyEnum::eFoo", result_value="3")
+
+ self.expect("p eBar", error=True,
+ substrs=["use of undeclared identifier 'eBar'"])
+
+ @skipIf(dwarf_version=['<', '4'])
+ def test_enums_from_different_scopes(self):
+ self.build()
+ _ = self.dbg.CreateTarget(self.getBuildArtifact())
+
+ lldbutil.run_break_set_by_source_regexp(
+ self, "// break here", num_expected_locations=3)
+
+ # Break in A::g()
+ self.runCmd("run")
+ self.expect_expr("eValue", result_type="A::AEnum", result_value="eValue")
+
+ # Break in B::f()
+ self.runCmd("continue")
+ self.expect_expr("eValue", result_type="B::BEnum", result_value="eValue")
+
+ # Break in main()
+ self.runCmd("continue")
+ self.expect_expr("eValue", result_type="CEnum", result_value="eValue")
+
+ self.runCmd("kill")
Index: lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
===================================================================
--- lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
+++ lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
@@ -9275,6 +9275,14 @@
found_decls.push_back(GetCompilerDecl(nd));
}
}
+ } else if (clang::EnumDecl *ed =
+ llvm::dyn_cast<clang::EnumDecl>(child)) {
+ for (clang::EnumConstantDecl *ecd : ed->enumerators()) {
+ IdentifierInfo *ii = ecd->getIdentifier();
+ if (ii != nullptr &&
+ ii->getName().equals(name.AsCString(nullptr)))
+ found_decls.push_back(GetCompilerDecl(ecd));
+ }
} else if (clang::NamedDecl *nd =
llvm::dyn_cast<clang::NamedDecl>(child)) {
IdentifierInfo *ii = nd->getIdentifier();
Index: lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp
@@ -2115,7 +2115,7 @@
sc.module_sp = m_objfile_sp->GetModule();
assert(sc.module_sp);
- if (die.Tag() != DW_TAG_variable)
+ if (die.Tag() != DW_TAG_variable && die.Tag() != DW_TAG_enumerator)
return true;
auto *dwarf_cu = llvm::dyn_cast<DWARFCompileUnit>(die.GetCU());
@@ -3096,6 +3096,7 @@
ModuleSP module = GetObjectFile()->GetModule();
if (tag != DW_TAG_variable && tag != DW_TAG_constant &&
+ tag != DW_TAG_enumerator &&
(tag != DW_TAG_formal_parameter || !sc.function))
return nullptr;
@@ -3106,7 +3107,7 @@
const char *name = nullptr;
const char *mangled = nullptr;
Declaration decl;
- DWARFFormValue type_die_form;
+ DWARFDIE type_die;
DWARFExpression location;
bool is_external = false;
bool is_artificial = false;
@@ -3138,7 +3139,7 @@
mangled = form_value.AsCString();
break;
case DW_AT_type:
- type_die_form = form_value;
+ type_die = form_value.Reference();
break;
case DW_AT_external:
is_external = form_value.Boolean();
@@ -3170,6 +3171,11 @@
}
}
+ // For enumerators the type is their parent (DW_TAG_enumeration_type).
+ if (tag == DW_TAG_enumerator) {
+ type_die = die.GetParent();
+ }
+
// Prefer DW_AT_location over DW_AT_const_value. Both can be emitted e.g.
// for static constexpr member variables -- DW_AT_const_value will be
// present in the class declaration and DW_AT_location in the DIE defining
@@ -3252,7 +3258,8 @@
// able to generate a fully qualified name from the
// declaration context.
if ((parent_tag == DW_TAG_compile_unit ||
- parent_tag == DW_TAG_partial_unit) &&
+ parent_tag == DW_TAG_partial_unit ||
+ parent_tag == DW_TAG_enumeration_type) &&
Language::LanguageIsCPlusPlus(GetLanguage(*die.GetCU())))
mangled =
GetDWARFDeclContext(die).GetQualifiedNameAsConstString().GetCString();
@@ -3260,6 +3267,8 @@
if (tag == DW_TAG_formal_parameter)
scope = eValueTypeVariableArgument;
+ else if (tag == DW_TAG_enumerator)
+ scope = eValueTypeVariableGlobal;
else {
// DWARF doesn't specify if a DW_TAG_variable is a local, global
// or static variable, so we have to do a little digging:
@@ -3401,8 +3410,7 @@
}
if (symbol_context_scope) {
- auto type_sp = std::make_shared<SymbolFileType>(
- *this, GetUID(type_die_form.Reference()));
+ auto type_sp = std::make_shared<SymbolFileType>(*this, GetUID(type_die));
if (use_type_size_for_value && type_sp->GetType())
location.UpdateValue(
@@ -3499,6 +3507,7 @@
} else {
// We haven't already parsed it, lets do that now.
if ((tag == DW_TAG_variable) || (tag == DW_TAG_constant) ||
+ (tag == DW_TAG_enumerator) ||
(tag == DW_TAG_formal_parameter && sc.function)) {
if (variable_list_sp.get() == nullptr) {
DWARFDIE sc_parent_die = GetParentSymbolContextDIE(orig_die);
Index: lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/ManualDWARFIndex.cpp
@@ -172,6 +172,7 @@
bool is_declaration = false;
// bool is_artificial = false;
bool has_address = false;
+ bool is_enum_class = false;
bool has_location_or_const_value = false;
bool is_global_or_static_variable = false;
@@ -192,6 +193,11 @@
is_declaration = form_value.Unsigned() != 0;
break;
+ case DW_AT_enum_class:
+ if (attributes.ExtractFormValueAtIndex(i, form_value))
+ is_enum_class = form_value.Boolean();
+ break;
+
case DW_AT_MIPS_linkage_name:
case DW_AT_linkage_name:
if (attributes.ExtractFormValueAtIndex(i, form_value))
@@ -295,6 +301,16 @@
set.types.Insert(ConstString(name), ref);
if (mangled_cstr && !is_declaration)
set.types.Insert(ConstString(mangled_cstr), ref);
+ // Unscoped enumerators are basically constants in the surrounding scope.
+ if (tag == DW_TAG_enumeration_type && !is_enum_class) {
+ for (const DWARFDebugInfoEntry *value = die.GetFirstChild();
+ value != nullptr; value = value->GetSibling()) {
+ if (value->Tag() == DW_TAG_enumerator) {
+ DIERef value_ref = DWARFDIE(&unit, value).GetDIERef().getValue();
+ set.globals.Insert(ConstString(value->GetName(&unit)), value_ref);
+ }
+ }
+ }
break;
case DW_TAG_namespace:
Index: lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
===================================================================
--- lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
+++ lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp
@@ -3135,7 +3135,10 @@
Type *DWARFASTParserClang::GetTypeForDIE(const DWARFDIE &die) {
if (die) {
- SymbolFileDWARF *dwarf = die.GetDWARF();
+ if (die.Tag() == DW_TAG_enumerator) {
+ return die.GetDWARF()->ResolveTypeUID(die.GetParent(), true);
+ }
+
DWARFAttributes attributes;
const size_t num_attributes = die.GetAttributes(attributes);
if (num_attributes > 0) {
@@ -3146,7 +3149,7 @@
if (attr == DW_AT_type &&
attributes.ExtractFormValueAtIndex(i, form_value))
- return dwarf->ResolveTypeUID(form_value.Reference(), true);
+ return die.GetDWARF()->ResolveTypeUID(form_value.Reference(), true);
}
}
}
@@ -3161,6 +3164,7 @@
switch (die.Tag()) {
case DW_TAG_variable:
case DW_TAG_constant:
+ case DW_TAG_enumerator:
case DW_TAG_formal_parameter:
case DW_TAG_imported_declaration:
case DW_TAG_imported_module:
@@ -3206,6 +3210,28 @@
}
break;
}
+ case DW_TAG_enumerator: {
+ Type *type = GetTypeForDIE(die);
+ if (type) {
+ CompilerType compiler_type = type->GetForwardCompilerType();
+ clang::QualType qual_type = ClangUtil::GetQualType(compiler_type);
+ const clang::Type *clang_type = qual_type.getTypePtrOrNull();
+ if (clang_type) {
+ clang::EnumDecl *enum_decl =
+ llvm::dyn_cast_or_null<clang::EnumDecl>(clang_type->getAsTagDecl());
+ if (enum_decl) {
+ const char *name = die.GetName();
+ for (clang::EnumConstantDecl *ecd : enum_decl->enumerators()) {
+ if (ecd->getName() == name) {
+ decl = ecd;
+ break;
+ }
+ }
+ }
+ }
+ }
+ break;
+ }
case DW_TAG_imported_declaration: {
SymbolFileDWARF *dwarf = die.GetDWARF();
DWARFDIE imported_uid = die.GetAttributeValueAsReferenceDIE(DW_AT_import);
Index: lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
===================================================================
--- lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
+++ lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionDeclMap.cpp
@@ -1567,6 +1567,23 @@
CompleteType(objc_object_ptr_type->getInterfaceDecl());
}
+ // Check if this variable actually represents an unscoped enumeration
+ // constant. They're stored in the index with global variables and thus can be
+ // looked up as a global variable. But the declarations for the enumeration
+ // members (enumerators) are already generated and exist in the AST context.
+ // We just need to find the one corresponsing to this "variable".
+ if (const clang::EnumType *enum_type =
+ dyn_cast<clang::EnumType>(parser_opaque_type.getTypePtr())) {
+ if (!enum_type->isScopedEnumeralType()) {
+ for (clang::EnumConstantDecl *ecd : enum_type->getDecl()->enumerators()) {
+ if (ecd->getName() == var->GetUnqualifiedName().GetStringRef()) {
+ context.AddNamedDecl(ecd);
+ return;
+ }
+ }
+ }
+ }
+
bool is_reference = pt.IsReferenceType();
NamedDecl *var_decl = nullptr;
_______________________________________________
lldb-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits