[Lldb-commits] [lldb] e861d05 - [lldb/Utility] Add GetDescription(Stream&) to StructureData::*
Med Ismail Bennani via lldb-commits
lldb-commits at lists.llvm.org
Thu Nov 3 14:45:25 PDT 2022
Author: Med Ismail Bennani
Date: 2022-11-03T14:44:53-07:00
New Revision: e861d053dd43f2e5a63f150ee2f9d1d643ea29c1
URL: https://github.com/llvm/llvm-project/commit/e861d053dd43f2e5a63f150ee2f9d1d643ea29c1
DIFF: https://github.com/llvm/llvm-project/commit/e861d053dd43f2e5a63f150ee2f9d1d643ea29c1.diff
LOG: [lldb/Utility] Add GetDescription(Stream&) to StructureData::*
This patch improves the StructuredData classes to provide a
GetDescription(lldb_private::Stream&) affordance.
This is very convenient compared to the Dump method because this try to
pretty print the structure instead of just serializing it into a JSON.
This patch also updates some parts of lldb (i.e. extended crash info) to
use this new affordance instead of StructuredData::Dump.
Differential Revision: https://reviews.llvm.org/D135547
Signed-off-by: Med Ismail Bennani <medismail.bennani at gmail.com>
Added:
lldb/unittests/Utility/Inputs/StructuredData-full.json
lldb/unittests/Utility/Inputs/StructuredData-nested.json
Modified:
lldb/include/lldb/Core/StructuredDataImpl.h
lldb/include/lldb/Utility/StructuredData.h
lldb/source/Commands/CommandObjectProcess.cpp
lldb/source/Utility/StructuredData.cpp
lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py
lldb/unittests/Utility/CMakeLists.txt
lldb/unittests/Utility/StructuredDataTest.cpp
Removed:
################################################################################
diff --git a/lldb/include/lldb/Core/StructuredDataImpl.h b/lldb/include/lldb/Core/StructuredDataImpl.h
index e755c53aaa9f6..16dbc5263b285 100644
--- a/lldb/include/lldb/Core/StructuredDataImpl.h
+++ b/lldb/include/lldb/Core/StructuredDataImpl.h
@@ -80,7 +80,7 @@ class StructuredDataImpl {
error.SetErrorString("No data to describe.");
return error;
}
- m_data_sp->Dump(stream, true);
+ m_data_sp->GetDescription(stream);
return error;
}
// Get the data's description.
diff --git a/lldb/include/lldb/Utility/StructuredData.h b/lldb/include/lldb/Utility/StructuredData.h
index 9f6300f4f115b..5420c0dcf8d5a 100644
--- a/lldb/include/lldb/Utility/StructuredData.h
+++ b/lldb/include/lldb/Utility/StructuredData.h
@@ -158,6 +158,12 @@ class StructuredData {
Serialize(jso);
}
+ virtual void GetDescription(lldb_private::Stream &s) const {
+ s.IndentMore();
+ Dump(s, false);
+ s.IndentLess();
+ }
+
private:
lldb::StructuredDataType m_type;
};
@@ -277,6 +283,8 @@ class StructuredData {
void Serialize(llvm::json::OStream &s) const override;
+ void GetDescription(lldb_private::Stream &s) const override;
+
protected:
typedef std::vector<ObjectSP> collection;
collection m_items;
@@ -295,6 +303,8 @@ class StructuredData {
void Serialize(llvm::json::OStream &s) const override;
+ void GetDescription(lldb_private::Stream &s) const override;
+
protected:
uint64_t m_value;
};
@@ -312,6 +322,8 @@ class StructuredData {
void Serialize(llvm::json::OStream &s) const override;
+ void GetDescription(lldb_private::Stream &s) const override;
+
protected:
double m_value;
};
@@ -329,6 +341,8 @@ class StructuredData {
void Serialize(llvm::json::OStream &s) const override;
+ void GetDescription(lldb_private::Stream &s) const override;
+
protected:
bool m_value;
};
@@ -345,6 +359,8 @@ class StructuredData {
void Serialize(llvm::json::OStream &s) const override;
+ void GetDescription(lldb_private::Stream &s) const override;
+
protected:
std::string m_value;
};
@@ -524,6 +540,8 @@ class StructuredData {
void Serialize(llvm::json::OStream &s) const override;
+ void GetDescription(lldb_private::Stream &s) const override;
+
protected:
typedef std::map<ConstString, ObjectSP> collection;
collection m_dict;
@@ -538,6 +556,8 @@ class StructuredData {
bool IsValid() const override { return false; }
void Serialize(llvm::json::OStream &s) const override;
+
+ void GetDescription(lldb_private::Stream &s) const override;
};
class Generic : public Object {
@@ -553,12 +573,15 @@ class StructuredData {
void Serialize(llvm::json::OStream &s) const override;
+ void GetDescription(lldb_private::Stream &s) const override;
+
private:
void *m_object;
};
static ObjectSP ParseJSON(const std::string &json_text);
static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error);
+ static bool IsRecordType(const ObjectSP object_sp);
};
} // namespace lldb_private
diff --git a/lldb/source/Commands/CommandObjectProcess.cpp b/lldb/source/Commands/CommandObjectProcess.cpp
index 28a99ea3d94a5..92544c564e532 100644
--- a/lldb/source/Commands/CommandObjectProcess.cpp
+++ b/lldb/source/Commands/CommandObjectProcess.cpp
@@ -1537,8 +1537,9 @@ class CommandObjectProcessStatus : public CommandObjectParsed {
StructuredData::DictionarySP crash_info_sp = *expected_crash_info;
if (crash_info_sp) {
+ strm.EOL();
strm.PutCString("Extended Crash Information:\n");
- crash_info_sp->Dump(strm);
+ crash_info_sp->GetDescription(strm);
}
}
diff --git a/lldb/source/Utility/StructuredData.cpp b/lldb/source/Utility/StructuredData.cpp
index 2e023344f3ddb..acc09289e6b98 100644
--- a/lldb/source/Utility/StructuredData.cpp
+++ b/lldb/source/Utility/StructuredData.cpp
@@ -50,6 +50,11 @@ StructuredData::ParseJSONFromFile(const FileSpec &input_spec, Status &error) {
return StructuredData::ObjectSP();
}
+bool StructuredData::IsRecordType(const ObjectSP object_sp) {
+ return object_sp->GetType() == lldb::eStructuredDataTypeArray ||
+ object_sp->GetType() == lldb::eStructuredDataTypeDictionary;
+}
+
static StructuredData::ObjectSP ParseJSONValue(json::Value &value) {
if (json::Object *O = value.getAsObject())
return ParseJSONObject(O);
@@ -175,3 +180,98 @@ void StructuredData::Null::Serialize(json::OStream &s) const {
void StructuredData::Generic::Serialize(json::OStream &s) const {
s.value(llvm::formatv("{0:X}", m_object));
}
+
+void StructuredData::Integer::GetDescription(lldb_private::Stream &s) const {
+ s.Printf("%" PRId64, static_cast<int64_t>(m_value));
+}
+
+void StructuredData::Float::GetDescription(lldb_private::Stream &s) const {
+ s.Printf("%f", m_value);
+}
+
+void StructuredData::Boolean::GetDescription(lldb_private::Stream &s) const {
+ s.Printf(m_value ? "True" : "False");
+}
+
+void StructuredData::String::GetDescription(lldb_private::Stream &s) const {
+ s.Printf("%s", m_value.empty() ? "\"\"" : m_value.c_str());
+}
+
+void StructuredData::Array::GetDescription(lldb_private::Stream &s) const {
+ size_t index = 0;
+ size_t indentation_level = s.GetIndentLevel();
+ for (const auto &item_sp : m_items) {
+ // Sanitize.
+ if (!item_sp)
+ continue;
+
+ // Reset original indentation level.
+ s.SetIndentLevel(indentation_level);
+ s.Indent();
+
+ // Print key
+ s.Printf("[%zu]:", index++);
+
+ // Return to new line and increase indentation if value is record type.
+ // Otherwise add spacing.
+ bool should_indent = IsRecordType(item_sp);
+ if (should_indent) {
+ s.EOL();
+ s.IndentMore();
+ } else {
+ s.PutChar(' ');
+ }
+
+ // Print value and new line if now last pair.
+ item_sp->GetDescription(s);
+ if (item_sp != *(--m_items.end()))
+ s.EOL();
+
+ // Reset indentation level if it was incremented previously.
+ if (should_indent)
+ s.IndentLess();
+ }
+}
+
+void StructuredData::Dictionary::GetDescription(lldb_private::Stream &s) const {
+ size_t indentation_level = s.GetIndentLevel();
+ for (const auto &pair : m_dict) {
+ // Sanitize.
+ if (pair.first.IsNull() || pair.first.IsEmpty() || !pair.second)
+ continue;
+
+ // Reset original indentation level.
+ s.SetIndentLevel(indentation_level);
+ s.Indent();
+
+ // Print key.
+ s.Printf("%s:", pair.first.AsCString());
+
+ // Return to new line and increase indentation if value is record type.
+ // Otherwise add spacing.
+ bool should_indent = IsRecordType(pair.second);
+ if (should_indent) {
+ s.EOL();
+ s.IndentMore();
+ } else {
+ s.PutChar(' ');
+ }
+
+ // Print value and new line if now last pair.
+ pair.second->GetDescription(s);
+ if (pair != *(--m_dict.end()))
+ s.EOL();
+
+ // Reset indentation level if it was incremented previously.
+ if (should_indent)
+ s.IndentLess();
+ }
+}
+
+void StructuredData::Null::GetDescription(lldb_private::Stream &s) const {
+ s.Printf("NULL");
+}
+
+void StructuredData::Generic::GetDescription(lldb_private::Stream &s) const {
+ s.Printf("%p", m_object);
+}
diff --git a/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py b/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py
index 30190e7c4df9b..659539c28a795 100644
--- a/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py
+++ b/lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py
@@ -37,7 +37,9 @@ def test_cli(self):
patterns=["Process .* launched: .*a.out"])
self.expect('process status --verbose',
- patterns=["\"message\".*pointer being freed was not allocated"])
+ patterns=["Extended Crash Information",
+ "crash-info annotations",
+ "pointer being freed was not allocated"])
@skipIfAsan # The test process intentionally hits a memory bug.
diff --git a/lldb/unittests/Utility/CMakeLists.txt b/lldb/unittests/Utility/CMakeLists.txt
index d697464600ff5..848a36215aa67 100644
--- a/lldb/unittests/Utility/CMakeLists.txt
+++ b/lldb/unittests/Utility/CMakeLists.txt
@@ -54,6 +54,10 @@ add_lldb_unittest(UtilityTests
Support
)
-add_unittest_inputs(UtilityTests
+set(test_inputs
StructuredData-basic.json
+ StructuredData-nested.json
+ StructuredData-full.json
)
+
+add_unittest_inputs(UtilityTests "${test_inputs}")
diff --git a/lldb/unittests/Utility/Inputs/StructuredData-full.json b/lldb/unittests/Utility/Inputs/StructuredData-full.json
new file mode 100644
index 0000000000000..4e4945cd6a280
--- /dev/null
+++ b/lldb/unittests/Utility/Inputs/StructuredData-full.json
@@ -0,0 +1,15 @@
+{
+ "Array": [
+ 3.14,
+ {
+ "key": "val"
+ }
+ ],
+ "Dictionary": {
+ "FalseBool": false
+ },
+ "Integer": 1,
+ "Null": null,
+ "String": "value",
+ "TrueBool": true
+}
diff --git a/lldb/unittests/Utility/Inputs/StructuredData-nested.json b/lldb/unittests/Utility/Inputs/StructuredData-nested.json
new file mode 100644
index 0000000000000..facf461bb6c1f
--- /dev/null
+++ b/lldb/unittests/Utility/Inputs/StructuredData-nested.json
@@ -0,0 +1,14 @@
+{
+ "my_dict": [
+ {
+ "three": 3,
+ "two": 2
+ },
+ {
+ "four": {
+ "val": 4
+ }
+ },
+ 1
+ ]
+}
diff --git a/lldb/unittests/Utility/StructuredDataTest.cpp b/lldb/unittests/Utility/StructuredDataTest.cpp
index cb5e418cd958e..e732016fe43db 100644
--- a/lldb/unittests/Utility/StructuredDataTest.cpp
+++ b/lldb/unittests/Utility/StructuredDataTest.cpp
@@ -31,6 +31,73 @@ TEST(StructuredDataTest, StringDump) {
}
}
+TEST(StructuredDataTest, GetDescriptionEmpty) {
+ Status status;
+ auto object_sp = StructuredData::ParseJSON("{}");
+ ASSERT_NE(nullptr, object_sp);
+
+ StreamString S;
+ object_sp->GetDescription(S);
+ EXPECT_EQ(0, S.GetSize());
+}
+
+TEST(StructuredDataTest, GetDescriptionBasic) {
+ Status status;
+ std::string input = GetInputFilePath("StructuredData-basic.json");
+ auto object_sp = StructuredData::ParseJSONFromFile(FileSpec(input), status);
+ ASSERT_NE(nullptr, object_sp);
+
+ const std::string expected = "[0]: 1\n"
+ "[1]: 2\n"
+ "[2]: 3";
+
+ StreamString S;
+ object_sp->GetDescription(S);
+ EXPECT_EQ(expected, S.GetString());
+}
+
+TEST(StructuredDataTest, GetDescriptionNested) {
+ Status status;
+ std::string input = GetInputFilePath("StructuredData-nested.json");
+ auto object_sp = StructuredData::ParseJSONFromFile(FileSpec(input), status);
+ ASSERT_NE(nullptr, object_sp);
+
+ const std::string expected = "my_dict:\n"
+ " [0]:\n"
+ " three: 3\n"
+ " two: 2\n"
+ " [1]:\n"
+ " four:\n"
+ " val: 4\n"
+ " [2]: 1";
+
+ StreamString S;
+ object_sp->GetDescription(S);
+ EXPECT_EQ(expected, S.GetString());
+}
+
+TEST(StructuredDataTest, GetDescriptionFull) {
+ Status status;
+ std::string input = GetInputFilePath("StructuredData-full.json");
+ auto object_sp = StructuredData::ParseJSONFromFile(FileSpec(input), status);
+ ASSERT_NE(nullptr, object_sp);
+
+ const std::string expected = "Array:\n"
+ " [0]: 3.140000\n"
+ " [1]:\n"
+ " key: val\n"
+ "Dictionary:\n"
+ " FalseBool: False\n"
+ "Integer: 1\n"
+ "Null: NULL\n"
+ "String: value\n"
+ "TrueBool: True";
+
+ StreamString S;
+ object_sp->GetDescription(S);
+ EXPECT_EQ(expected, S.GetString());
+}
+
TEST(StructuredDataTest, ParseJSONFromFile) {
Status status;
auto object_sp = StructuredData::ParseJSONFromFile(
More information about the lldb-commits
mailing list