friss updated this revision to Diff 223705.
friss marked an inline comment as done.
friss added a comment.

Add comments to some tests.


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D67520/new/

https://reviews.llvm.org/D67520

Files:
  lit/SymbolFile/DWARF/debug-types-missing-signature.test
  packages/Python/lldbsuite/test/lang/c/enum_types/TestEnumTypes.py
  packages/Python/lldbsuite/test/lang/c/enum_types/main.c
  source/Symbol/ClangASTContext.cpp

Index: source/Symbol/ClangASTContext.cpp
===================================================================
--- source/Symbol/ClangASTContext.cpp
+++ source/Symbol/ClangASTContext.cpp
@@ -9370,6 +9370,82 @@
   }
 }
 
+static bool DumpEnumValue(const clang::QualType &qual_type, Stream *s,
+                          const DataExtractor &data, lldb::offset_t byte_offset,
+                          size_t byte_size, uint32_t bitfield_bit_offset,
+                          uint32_t bitfield_bit_size) {
+  const clang::EnumType *enutype =
+      llvm::cast<clang::EnumType>(qual_type.getTypePtr());
+  const clang::EnumDecl *enum_decl = enutype->getDecl();
+  assert(enum_decl);
+  lldb::offset_t offset = byte_offset;
+  const uint64_t enum_svalue = data.GetMaxS64Bitfield(
+      &offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
+  bool can_be_bitfield = true;
+  uint64_t covered_bits = 0;
+  int num_enumerators = 0;
+
+  // Try to find an exact match for the value.
+  // At the same time, we're applying a heuristic to determine whether we want
+  // to print this enum as a bitfield. We're likely dealing with a bitfield if
+  // every enumrator is either a one bit value or a superset of the previous
+  // enumerators. Also 0 doesn't make sense when the enumerators are used as
+  // flags.
+  for (auto enumerator : enum_decl->enumerators()) {
+    uint64_t val = enumerator->getInitVal().getSExtValue();
+    if (llvm::countPopulation(val) != 1 && (val & ~covered_bits) != 0)
+      can_be_bitfield = false;
+    covered_bits |= val;
+    ++num_enumerators;
+    if (val == enum_svalue) {
+      // Found an exact match, that's all we need to do.
+      s->PutCString(enumerator->getNameAsString());
+      return true;
+    }
+  }
+
+  // No exact match, but we don't think this is a bitfield. Print the value as
+  // decimal.
+  if (!can_be_bitfield) {
+    s->Printf("%" PRIi64, enum_svalue);
+    return true;
+  }
+
+  // Unsigned values make more sense for flags.
+  offset = byte_offset;
+  const uint64_t enum_uvalue = data.GetMaxU64Bitfield(
+      &offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
+
+  uint64_t remaining_value = enum_uvalue;
+  std::vector<std::pair<uint64_t, llvm::StringRef>> values;
+  values.reserve(num_enumerators);
+  for (auto enumerator : enum_decl->enumerators())
+    if (auto val = enumerator->getInitVal().getZExtValue())
+      values.emplace_back(val, enumerator->getName());
+
+  // Sort in reverse order of the number of the population count,  so that in
+  // `enum {A, B, ALL = A|B }` we visit ALL first. Use a stable sort so that
+  // A | C where A < C is displayed in this order.
+  std::stable_sort(values.begin(), values.end(), [](const auto &a, const auto &b) {
+        return llvm::countPopulation(a.first) > llvm::countPopulation(b.first);
+      });
+
+  for (const auto &val : values) {
+    if ((remaining_value & val.first) != val.first)
+      continue;
+    remaining_value &= ~val.first;
+    s->PutCString(val.second);
+    if (remaining_value)
+      s->PutCString(" | ");
+  }
+
+  // If there is a remainder that is not covered by the value, print it as hex.
+  if (remaining_value)
+    s->Printf("0x%" PRIx64, remaining_value);
+
+  return true;
+}
+
 bool ClangASTContext::DumpTypeValue(
     lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format,
     const DataExtractor &data, lldb::offset_t byte_offset, size_t byte_size,
@@ -9383,6 +9459,13 @@
     clang::QualType qual_type(GetQualType(type));
 
     const clang::Type::TypeClass type_class = qual_type->getTypeClass();
+
+    if (type_class == clang::Type::Elaborated) {
+      qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType();
+      return DumpTypeValue(qual_type.getAsOpaquePtr(), s, format, data, byte_offset, byte_size,
+                           bitfield_bit_size, bitfield_bit_offset, exe_scope);
+    }
+
     switch (type_class) {
     case clang::Type::Typedef: {
       clang::QualType typedef_qual_type =
@@ -9413,45 +9496,9 @@
       // If our format is enum or default, show the enumeration value as its
       // enumeration string value, else just display it as requested.
       if ((format == eFormatEnum || format == eFormatDefault) &&
-          GetCompleteType(type)) {
-        const clang::EnumType *enutype =
-            llvm::cast<clang::EnumType>(qual_type.getTypePtr());
-        const clang::EnumDecl *enum_decl = enutype->getDecl();
-        assert(enum_decl);
-        clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
-        const bool is_signed = qual_type->isSignedIntegerOrEnumerationType();
-        lldb::offset_t offset = byte_offset;
-        if (is_signed) {
-          const int64_t enum_svalue = data.GetMaxS64Bitfield(
-              &offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
-          for (enum_pos = enum_decl->enumerator_begin(),
-              enum_end_pos = enum_decl->enumerator_end();
-               enum_pos != enum_end_pos; ++enum_pos) {
-            if (enum_pos->getInitVal().getSExtValue() == enum_svalue) {
-              s->PutCString(enum_pos->getNameAsString());
-              return true;
-            }
-          }
-          // If we have gotten here we didn't get find the enumerator in the
-          // enum decl, so just print the integer.
-          s->Printf("%" PRIi64, enum_svalue);
-        } else {
-          const uint64_t enum_uvalue = data.GetMaxU64Bitfield(
-              &offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
-          for (enum_pos = enum_decl->enumerator_begin(),
-              enum_end_pos = enum_decl->enumerator_end();
-               enum_pos != enum_end_pos; ++enum_pos) {
-            if (enum_pos->getInitVal().getZExtValue() == enum_uvalue) {
-              s->PutCString(enum_pos->getNameAsString());
-              return true;
-            }
-          }
-          // If we have gotten here we didn't get find the enumerator in the
-          // enum decl, so just print the integer.
-          s->Printf("%" PRIu64, enum_uvalue);
-        }
-        return true;
-      }
+          GetCompleteType(type))
+        return DumpEnumValue(qual_type, s, data, byte_offset, byte_size,
+                             bitfield_bit_offset, bitfield_bit_size);
       // format was not enum, just fall through and dump the value as
       // requested....
       LLVM_FALLTHROUGH;
Index: packages/Python/lldbsuite/test/lang/c/enum_types/main.c
===================================================================
--- packages/Python/lldbsuite/test/lang/c/enum_types/main.c
+++ packages/Python/lldbsuite/test/lang/c/enum_types/main.c
@@ -18,6 +18,20 @@
 
 int main (int argc, char const *argv[])
 {
+    enum bitfield {
+        None = 0,
+        A = 1 << 0,
+        B = 1 << 1,
+        C = 1 << 2,
+        AB = A | B,
+        ALL = A | B | C,
+    };
+
+    enum non_bitfield {
+        Alpha = 3,
+        Beta = 4
+    };
+
     enum days {
         Monday = -3,
         Tuesday,
@@ -28,9 +42,14 @@
         Sunday,
         kNumDays
     };
+
+    enum bitfield a = A, b = B, c = C, ab = AB, ac = A | C, all = ALL;
+    int nonsense = a + b + c + ab + ac + all;
+    enum non_bitfield omega = Alpha | Beta;
+
     enum days day;
     struct foo f;
-    f.op = NULL;
+    f.op = NULL; // Breakpoint for bitfield
     for (day = Monday - 1; day <= kNumDays + 1; day++)
     {
         printf("day as int is %i\n", (int)day); // Set break point at this line.
Index: packages/Python/lldbsuite/test/lang/c/enum_types/TestEnumTypes.py
===================================================================
--- packages/Python/lldbsuite/test/lang/c/enum_types/TestEnumTypes.py
+++ packages/Python/lldbsuite/test/lang/c/enum_types/TestEnumTypes.py
@@ -25,11 +25,35 @@
         exe = self.getBuildArtifact("a.out")
         self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
 
+        lldbutil.run_to_source_breakpoint(
+            self, '// Breakpoint for bitfield', lldb.SBFileSpec("main.c"))
+
+        self.expect("fr var a", DATA_TYPES_DISPLAYED_CORRECTLY,
+                    patterns=[' = A$'])
+        self.expect("fr var b", DATA_TYPES_DISPLAYED_CORRECTLY,
+                    patterns=[' = B$'])
+        self.expect("fr var c", DATA_TYPES_DISPLAYED_CORRECTLY,
+                    patterns=[' = C$'])
+        self.expect("fr var ab", DATA_TYPES_DISPLAYED_CORRECTLY,
+                    patterns=[' = AB$'])
+        self.expect("fr var ac", DATA_TYPES_DISPLAYED_CORRECTLY,
+                    patterns=[' = A | C$'])
+        self.expect("fr var all", DATA_TYPES_DISPLAYED_CORRECTLY,
+                    patterns=[' = ALL$'])
+        # Test that an enum that doesn't match the heuristic we use in
+        # ClabgASTContext::DumpEnumValue, gets printed as a raw integer.
+        self.expect("fr var omega", DATA_TYPES_DISPLAYED_CORRECTLY,
+                    patterns=[' = 7$'])
+        # Test the behavior in case have a variable of a type considered
+        # 'bitfield' by the heuristic, but the value isn't actually fully
+        # covered by the enumerators.
+        self.expect("p (enum bitfield)nonsense", DATA_TYPES_DISPLAYED_CORRECTLY,
+                    patterns=[' = B | C | 0x10$'])
+
         # Break inside the main.
         bkpt_id = lldbutil.run_break_set_by_file_and_line(
             self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
-
-        self.runCmd("run", RUN_SUCCEEDED)
+        self.runCmd("c", RUN_SUCCEEDED)
 
         # The stop reason of the thread should be breakpoint.
         self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,
Index: lit/SymbolFile/DWARF/debug-types-missing-signature.test
===================================================================
--- lit/SymbolFile/DWARF/debug-types-missing-signature.test
+++ lit/SymbolFile/DWARF/debug-types-missing-signature.test
@@ -22,5 +22,5 @@
 
 RUN: %lldb %t -b -o "target variable a e ec" | FileCheck --check-prefix=VARS %s
 VARS: (const (anonymous struct)) a = {}
-VARS: (const (anonymous enum)) e = 1
-VARS: (const (anonymous enum)) ec = 1
+VARS: (const (anonymous enum)) e = 0x1
+VARS: (const (anonymous enum)) ec = 0x1
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to