Skip to content

[lldb] Change interface of StructuredData::Array::GetItemAtIndexAsDictionary #71961

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 1 commit into from
Nov 10, 2023

Conversation

bulbazord
Copy link
Member

Similar to my previous patch (#71613) where I changed GetItemAtIndexAsString, this patch makes the same change to GetItemAtIndexAsDictionary.

GetItemAtIndexAsDictionary now returns a std::optional that is either std::nullopt or is a valid pointer. Therefore, if the optional is populated, we consider the pointer to always be valid (i.e. no need to check pointer validity).

…tionary

Similar to my previous patch (llvm#71613) where I changed
`GetItemAtIndexAsString`, this patch makes the same change to
`GetItemAtIndexAsDictionary`.

`GetItemAtIndexAsDictionary` now returns a std::optional that is either
`std::nullopt` or is a valid pointer. Therefore, if the optional is
populated, we consider the pointer to always be valid (i.e. no need to
check pointer validity).
@llvmbot
Copy link
Member

llvmbot commented Nov 10, 2023

@llvm/pr-subscribers-lldb

Author: Alex Langford (bulbazord)

Changes

Similar to my previous patch (#71613) where I changed GetItemAtIndexAsString, this patch makes the same change to GetItemAtIndexAsDictionary.

GetItemAtIndexAsDictionary now returns a std::optional that is either std::nullopt or is a valid pointer. Therefore, if the optional is populated, we consider the pointer to always be valid (i.e. no need to check pointer validity).


Full diff: https://github.com/llvm/llvm-project/pull/71961.diff

6 Files Affected:

  • (modified) lldb/include/lldb/Utility/StructuredData.h (+17-7)
  • (modified) lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp (+4-2)
  • (modified) lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp (+4-2)
  • (modified) lldb/source/Plugins/Process/scripted/ScriptedThread.cpp (+4-2)
  • (modified) lldb/source/Target/DynamicRegisterInfo.cpp (+4-2)
  • (modified) lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp (+4-3)
diff --git a/lldb/include/lldb/Utility/StructuredData.h b/lldb/include/lldb/Utility/StructuredData.h
index 6e39bcff2c0af0b..8d0ae372f43c6bf 100644
--- a/lldb/include/lldb/Utility/StructuredData.h
+++ b/lldb/include/lldb/Utility/StructuredData.h
@@ -256,14 +256,24 @@ class StructuredData {
       return {};
     }
 
-    bool GetItemAtIndexAsDictionary(size_t idx, Dictionary *&result) const {
-      result = nullptr;
-      ObjectSP value_sp = GetItemAtIndex(idx);
-      if (value_sp.get()) {
-        result = value_sp->GetAsDictionary();
-        return (result != nullptr);
+    /// Retrieves the element at index \a idx from a StructuredData::Array if it
+    /// is a Dictionary.
+    ///
+    /// \param[in] idx
+    ///   The index of the element to retrieve.
+    ///
+    /// \return
+    ///   If the element at index \a idx is a Dictionary, this method returns a
+    ///   valid pointer to the Dictionary wrapped in a std::optional. If the
+    ///   element is not a Dictionary or the index is invalid, this returns
+    ///   std::nullopt. Note that the underlying Dictionary pointer is never
+    ///   nullptr.
+    std::optional<Dictionary *> GetItemAtIndexAsDictionary(size_t idx) const {
+      if (auto item_sp = GetItemAtIndex(idx)) {
+        if (auto *dict = item_sp->GetAsDictionary())
+          return dict;
       }
-      return false;
+      return {};
     }
 
     bool GetItemAtIndexAsArray(size_t idx, Array *&result) const {
diff --git a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
index 3714e37ec5c57d0..1ea4f649427727f 100644
--- a/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
+++ b/lldb/source/Plugins/ObjectFile/Mach-O/ObjectFileMachO.cpp
@@ -5688,14 +5688,16 @@ bool ObjectFileMachO::GetCorefileThreadExtraInfos(std::vector<tid_t> &tids) {
       }
       const size_t num_threads = threads->GetSize();
       for (size_t i = 0; i < num_threads; i++) {
-        StructuredData::Dictionary *thread;
-        if (!threads->GetItemAtIndexAsDictionary(i, thread) || !thread) {
+        std::optional<StructuredData::Dictionary *> maybe_thread =
+            threads->GetItemAtIndexAsDictionary(i);
+        if (!maybe_thread) {
           LLDB_LOGF(log,
                     "Unable to read 'process metadata' LC_NOTE, threads "
                     "array does not have a dictionary at index %zu.",
                     i);
           return false;
         }
+        StructuredData::Dictionary *thread = *maybe_thread;
         tid_t tid = LLDB_INVALID_THREAD_ID;
         if (thread->GetValueForKeyAsInteger<tid_t>("thread_id", tid))
           if (tid == 0)
diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
index 04d98b96acd6839..2cf8c29bf9d2fe9 100644
--- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
+++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationClient.cpp
@@ -2649,10 +2649,12 @@ size_t GDBRemoteCommunicationClient::QueryGDBServer(
     return 0;
 
   for (size_t i = 0, count = array->GetSize(); i < count; ++i) {
-    StructuredData::Dictionary *element = nullptr;
-    if (!array->GetItemAtIndexAsDictionary(i, element))
+    std::optional<StructuredData::Dictionary *> maybe_element =
+        array->GetItemAtIndexAsDictionary(i);
+    if (!maybe_element)
       continue;
 
+    StructuredData::Dictionary *element = *maybe_element;
     uint16_t port = 0;
     if (StructuredData::ObjectSP port_osp =
             element->GetValueForKey(llvm::StringRef("port")))
diff --git a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
index aa2796db15cd00a..88a4ca3b0389fb9 100644
--- a/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
+++ b/lldb/source/Plugins/Process/scripted/ScriptedThread.cpp
@@ -176,8 +176,9 @@ bool ScriptedThread::LoadArtificialStackFrames() {
   StackFrameListSP frames = GetStackFrameList();
 
   for (size_t idx = 0; idx < arr_size; idx++) {
-    StructuredData::Dictionary *dict;
-    if (!arr_sp->GetItemAtIndexAsDictionary(idx, dict) || !dict)
+    std::optional<StructuredData::Dictionary *> maybe_dict =
+        arr_sp->GetItemAtIndexAsDictionary(idx);
+    if (!maybe_dict)
       return ScriptedInterface::ErrorWithMessage<bool>(
           LLVM_PRETTY_FUNCTION,
           llvm::Twine(
@@ -185,6 +186,7 @@ bool ScriptedThread::LoadArtificialStackFrames() {
               llvm::Twine(idx) + llvm::Twine(") from stackframe array."))
               .str(),
           error, LLDBLog::Thread);
+    StructuredData::Dictionary *dict = *maybe_dict;
 
     lldb::addr_t pc;
     if (!dict->GetValueForKeyAsInteger("pc", pc))
diff --git a/lldb/source/Target/DynamicRegisterInfo.cpp b/lldb/source/Target/DynamicRegisterInfo.cpp
index cc2df5b97940fed..7469c1d4259afc2 100644
--- a/lldb/source/Target/DynamicRegisterInfo.cpp
+++ b/lldb/source/Target/DynamicRegisterInfo.cpp
@@ -231,13 +231,15 @@ DynamicRegisterInfo::SetRegisterInfo(const StructuredData::Dictionary &dict,
   //        InvalidateNameMap;
   //        InvalidateNameMap invalidate_map;
   for (uint32_t i = 0; i < num_regs; ++i) {
-    StructuredData::Dictionary *reg_info_dict = nullptr;
-    if (!regs->GetItemAtIndexAsDictionary(i, reg_info_dict)) {
+    std::optional<StructuredData::Dictionary *> maybe_reg_info_dict =
+        regs->GetItemAtIndexAsDictionary(i);
+    if (!maybe_reg_info_dict) {
       Clear();
       printf("error: items in the 'registers' array must be dictionaries\n");
       regs->DumpToStdout();
       return 0;
     }
+    StructuredData::Dictionary *reg_info_dict = *maybe_reg_info_dict;
 
     // { 'name':'rcx'       , 'bitsize' :  64, 'offset' :  16,
     // 'encoding':'uint' , 'format':'hex'         , 'set': 0, 'ehframe' : 2,
diff --git a/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp b/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp
index ed1c8b92b3db74d..32833920ffc57f6 100644
--- a/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp
+++ b/lldb/unittests/tools/lldb-server/tests/MessageObjects.cpp
@@ -106,11 +106,12 @@ Expected<JThreadsInfo> JThreadsInfo::create(StringRef Response,
     return make_parsing_error("JThreadsInfo: JSON array");
 
   for (size_t i = 0; i < array->GetSize(); i++) {
-    StructuredData::Dictionary *thread_info;
-    array->GetItemAtIndexAsDictionary(i, thread_info);
-    if (!thread_info)
+    std::optional<StructuredData::Dictionary *> maybe_thread_info =
+        array->GetItemAtIndexAsDictionary(i);
+    if (!maybe_thread_info)
       return make_parsing_error("JThreadsInfo: JSON obj at {0}", i);
 
+    StructuredData::Dictionary *thread_info = *maybe_thread_info;
     StringRef name, reason;
     thread_info->GetValueForKeyAsString("name", name);
     thread_info->GetValueForKeyAsString("reason", reason);

Copy link
Member

@medismailben medismailben left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

@clayborg
Copy link
Collaborator

A great future patch would be to have StructuredData backed by the llvm::json stuff instead of our own custom version of this a JSON style object hiearchy

@bulbazord
Copy link
Member Author

A great future patch would be to have StructuredData backed by the llvm::json stuff instead of our own custom version of this a JSON style object hiearchy

I think that I agree. Unfortunately I don't have time to drive that right now and it might appear to not make sense why I'm doing these interface changes now if I think we should refactor this class more thoroughly in the future. That being said, part of my goal in refactoring these interfaces is to force folks to think about error handling more explicitly. The other goal is so I can do other refactors in a safer/nicer way. 🙂

@bulbazord bulbazord merged commit 133bcac into llvm:main Nov 10, 2023
@bulbazord bulbazord deleted the get-item-at-index-as-dictionary branch November 10, 2023 20:47
bulbazord added a commit to bulbazord/llvm-project that referenced this pull request Nov 10, 2023
zahiraam pushed a commit to zahiraam/llvm-project that referenced this pull request Nov 20, 2023
…tionary (llvm#71961)

Similar to my previous patch (llvm#71613) where I changed
`GetItemAtIndexAsString`, this patch makes the same change to
`GetItemAtIndexAsDictionary`.

`GetItemAtIndexAsDictionary` now returns a std::optional that is either
`std::nullopt` or is a valid pointer. Therefore, if the optional is
populated, we consider the pointer to always be valid (i.e. no need to
check pointer validity).
bulbazord added a commit that referenced this pull request Jan 8, 2024
justinfargnoli pushed a commit to justinfargnoli/llvm-project that referenced this pull request Jan 28, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants