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
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to