mib updated this revision to Diff 472475. mib added a comment. Address @JDevlieghere comments:
- Fix indentation bug on nested structures - Add tests - Use string literals for expected string in tests CHANGES SINCE LAST ACTION https://reviews.llvm.org/D135547/new/ https://reviews.llvm.org/D135547 Files: 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/Inputs/StructuredData-empty.json lldb/unittests/Utility/Inputs/StructuredData-full.json lldb/unittests/Utility/Inputs/StructuredData-nested.json lldb/unittests/Utility/StructuredDataTest.cpp
Index: lldb/unittests/Utility/StructuredDataTest.cpp =================================================================== --- lldb/unittests/Utility/StructuredDataTest.cpp +++ lldb/unittests/Utility/StructuredDataTest.cpp @@ -31,6 +31,80 @@ } } +TEST(StructuredDataTest, GetDescriptionEmpty) { + Status status; + std::string input = GetInputFilePath("StructuredData-empty.json"); + auto object_sp = StructuredData::ParseJSONFromFile(FileSpec(input), status); + 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 = R"( + [0]: 1 + [1]: 2 + [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 = R"( + my_dict: + [0]: + three: 3 + two: 2 + [1]: + four: + val: 4 + [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 = R"( + Array: + [0]: 3.140000 + [1]: + key: val + Dictionary: + FalseBool: False + Integer: 1 + Null: NULL + String: value + TrueBool: True + )"; + + StreamString S; + object_sp->GetDescription(S); + EXPECT_EQ(expected, S.GetString()); +} + TEST(StructuredDataTest, ParseJSONFromFile) { Status status; auto object_sp = StructuredData::ParseJSONFromFile( Index: lldb/unittests/Utility/Inputs/StructuredData-nested.json =================================================================== --- /dev/null +++ lldb/unittests/Utility/Inputs/StructuredData-nested.json @@ -0,0 +1,14 @@ +{ + "my_dict": [ + { + "three": 3, + "two": 2 + }, + { + "four": { + "val": 4 + } + }, + 1 + ] +} Index: lldb/unittests/Utility/Inputs/StructuredData-full.json =================================================================== --- /dev/null +++ lldb/unittests/Utility/Inputs/StructuredData-full.json @@ -0,0 +1,13 @@ +{ + "Array": [ + 3.14, + 1.234 + ], + "Dictionary": { + "FalseBool": false + }, + "Integer": 1, + "Null": null, + "String": "value", + "TrueBool": true +} Index: lldb/unittests/Utility/Inputs/StructuredData-empty.json =================================================================== --- /dev/null +++ lldb/unittests/Utility/Inputs/StructuredData-empty.json @@ -0,0 +1 @@ +{} Index: lldb/unittests/Utility/CMakeLists.txt =================================================================== --- lldb/unittests/Utility/CMakeLists.txt +++ lldb/unittests/Utility/CMakeLists.txt @@ -54,6 +54,9 @@ Support ) -add_unittest_inputs(UtilityTests +set(test_inputs StructuredData-basic.json + StructuredData-full.json ) + +add_unittest_inputs(UtilityTests "${test_inputs}") Index: lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py =================================================================== --- lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py +++ lldb/test/API/functionalities/process_crash_info/TestProcessCrashInfo.py @@ -37,7 +37,9 @@ 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. Index: lldb/source/Utility/StructuredData.cpp =================================================================== --- lldb/source/Utility/StructuredData.cpp +++ lldb/source/Utility/StructuredData.cpp @@ -50,6 +50,11 @@ 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::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); +} Index: lldb/source/Commands/CommandObjectProcess.cpp =================================================================== --- lldb/source/Commands/CommandObjectProcess.cpp +++ lldb/source/Commands/CommandObjectProcess.cpp @@ -1537,8 +1537,9 @@ 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); } } Index: lldb/include/lldb/Utility/StructuredData.h =================================================================== --- lldb/include/lldb/Utility/StructuredData.h +++ lldb/include/lldb/Utility/StructuredData.h @@ -158,6 +158,12 @@ 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 @@ 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 @@ 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 @@ void Serialize(llvm::json::OStream &s) const override; + void GetDescription(lldb_private::Stream &s) const override; + protected: double m_value; }; @@ -329,6 +341,8 @@ void Serialize(llvm::json::OStream &s) const override; + void GetDescription(lldb_private::Stream &s) const override; + protected: bool m_value; }; @@ -345,6 +359,8 @@ 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 @@ 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 @@ 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 @@ 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 Index: lldb/include/lldb/Core/StructuredDataImpl.h =================================================================== --- lldb/include/lldb/Core/StructuredDataImpl.h +++ lldb/include/lldb/Core/StructuredDataImpl.h @@ -80,7 +80,7 @@ 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.
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits