[Lldb-commits] [lldb] [lldb-vscode] Display a more descriptive summary for containers and pointers (PR #65514)

Greg Clayton via lldb-commits lldb-commits at lists.llvm.org
Mon Sep 25 17:07:34 PDT 2023


================
@@ -132,6 +132,84 @@ std::vector<std::string> GetStrings(const llvm::json::Object *obj,
   return strs;
 }
 
+/// Create a short summary for a container that contains the summary of its
+/// first children, so that the user can get a glimpse of its contents at a
+/// glance.
+static std::optional<std::string>
+GetSyntheticSummaryForContainer(lldb::SBValue &v) {
+  if (v.TypeIsPointerType() || !v.MightHaveChildren())
+    return std::nullopt;
+  /// As this operation can be potentially slow, we limit the total time spent
+  /// fetching children to a few ms.
+  const auto max_evaluation_time = std::chrono::milliseconds(10);
+  /// We don't want to generate a extremely long summary string, so we limit its
+  /// length.
+  const size_t max_length = 32;
+
+  auto start = std::chrono::steady_clock::now();
+  std::string summary;
+  llvm::raw_string_ostream os(summary);
+  os << "{";
+
+  llvm::StringRef separator = "";
+
+  for (size_t i = 0, e = v.GetNumChildren(); i < e; ++i) {
----------------
clayborg wrote:

> I'm not sure I understand. `v.GetNumChildren()` wouldn't need to do any more work for a case with "10 class pointer variables", right? 

correct. that is a problem. This API is asking any variable how many children it has. So if we have a CompilerType in LLDB that represents a class, it starts off as a forward declaration and it can complete itself through the external AST support in clang. As soon as we call GetNumChildren, we need to complete the type as some of the children of a type might come from base classes, but only if they have fields or other base classes that contain fields. Empty base classes do not show up in the variable view. And then we need to count the number of fields that the class actaully has as well so we can show them as children, so as soon as we call "v.GetNumChildren()" we must complete the type.

> You can determine how many children this type has (10) without completing the types those pointers point to?

Correct yes, that is what I meant by "layout type". LLDB has the ability to say "get me a version of this type that is needed to layout this current class". So if a class has 10 ivars that are all pointers, we don't need to complete those classes. If we have 10 ivars that are class instances, then we do need to complete the type since we assist in the clang AST context in laying out the type with the help of the DWARF info. This is needed because of "-flimit-debug-info". If we have class A that inherits from class B, and there is no class B definition in the DWARF, then we have to have the DWARF help us laying out the type. What we do is start and end a definition for class B and we attach. metadata saying "this class should have been complete but wasn't", and the layout support that clang has allows us to specify the offsets of all fields and base classes so we can always show the variable correctly to people. The layout stuff is needed because DWARF doesn't encode many things, one being the current pragma pack settings and other things that can affect the layout of the type.

> Or is it later code (like line 168, etc) that try to get the summary of those pointer member variables that are an issue? (though getting the summary of a pointer shouldn't automatically dereference the pointer/complete its pointed-to type, should it?)

Any summary code that needs to access children to make up the summary string can be expensive and cause the type to need to be completed due to above explanation. If we have a "Foo *", the value of the variable will show as the pointer value, but if the type that is being pointed to has a summary, we do end up showing that for pointers and for references. This is because users expect it from the GDB days and due to the way we expand variables. If we have a "Point *" and we expand it in a GUI, we don't expect it to expand to a "Point" and then for it to need to be expanded yet again to see the "x" and "y" values, we expect to directly see the "x" and "y" right away. If the pointee is a simple type, like an "int *", we exand and show the "int", but if we have a class pointer, then we immediately show the children of the class. Many users complained when we initially did it where a "Point *" would expand to a "Point" object, so we changed lldb.




https://github.com/llvm/llvm-project/pull/65514


More information about the lldb-commits mailing list