LLDB mainline
StructuredData.cpp
Go to the documentation of this file.
1//===-- StructuredData.cpp ------------------------------------------------===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8
11#include "lldb/Utility/Status.h"
12#include "llvm/ADT/StringExtras.h"
13#include "llvm/Support/MemoryBuffer.h"
14#include <cerrno>
15#include <cinttypes>
16#include <cstdlib>
17
18using namespace lldb_private;
19using namespace llvm;
20
21static StructuredData::ObjectSP ParseJSONObject(const json::Object &object);
22static StructuredData::ObjectSP ParseJSONArray(const json::Array &array);
23
25 llvm::Expected<json::Value> value = json::parse(json_text);
26 if (!value) {
27 llvm::consumeError(value.takeError());
28 return nullptr;
29 }
30 return ParseJSONValue(*value);
31}
32
36
37 auto buffer_or_error = llvm::MemoryBuffer::getFile(input_spec.GetPath());
38 if (!buffer_or_error) {
40 "could not open input file: {0} - {1}.", input_spec.GetPath(),
41 buffer_or_error.getError().message());
42 return return_sp;
43 }
44 llvm::Expected<json::Value> value =
45 json::parse(buffer_or_error.get()->getBuffer().str());
46 if (value)
47 return ParseJSONValue(*value);
48 error = Status::FromError(value.takeError());
50}
51
53 return object_sp->GetType() == lldb::eStructuredDataTypeArray ||
54 object_sp->GetType() == lldb::eStructuredDataTypeDictionary;
55}
56
58StructuredData::ParseJSONValue(const json::Value &value) {
59 if (const json::Object *O = value.getAsObject())
60 return ParseJSONObject(*O);
61
62 if (const json::Array *A = value.getAsArray())
63 return ParseJSONArray(*A);
64
65 if (auto s = value.getAsString())
66 return std::make_shared<StructuredData::String>(*s);
67
68 if (auto b = value.getAsBoolean())
69 return std::make_shared<StructuredData::Boolean>(*b);
70
71 if (auto u = value.getAsUINT64())
72 return std::make_shared<StructuredData::UnsignedInteger>(*u);
73
74 if (auto i = value.getAsInteger())
75 return std::make_shared<StructuredData::SignedInteger>(*i);
76
77 if (auto d = value.getAsNumber())
78 return std::make_shared<StructuredData::Float>(*d);
79
80 if (auto n = value.getAsNull())
81 return std::make_shared<StructuredData::Null>();
82
84}
85
86static StructuredData::ObjectSP ParseJSONObject(const json::Object &object) {
87 auto dict_up = std::make_unique<StructuredData::Dictionary>();
88 for (const auto &[key, value] : object) {
89 if (auto value_sp = StructuredData::ParseJSONValue(value))
90 dict_up->AddItem(key, value_sp);
91 }
92 return std::move(dict_up);
93}
94
95static StructuredData::ObjectSP ParseJSONArray(const json::Array &array) {
96 auto array_up = std::make_unique<StructuredData::Array>();
97 for (const json::Value &value : array) {
98 if (auto value_sp = StructuredData::ParseJSONValue(value))
99 array_up->AddItem(value_sp);
100 }
101 return std::move(array_up);
102}
103
107 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('.');
108 llvm::StringRef key = match.first;
110 if (!value)
111 return {};
112
113 // Do we have additional words to descend? If not, return the value
114 // we're at right now.
115 if (match.second.empty())
116 return value;
117
118 return value->GetObjectForDotSeparatedPath(match.second);
119 }
120
122 std::pair<llvm::StringRef, llvm::StringRef> match = path.split('[');
123 if (match.second.empty())
124 return shared_from_this();
125
126 uint64_t val = 0;
127 if (!llvm::to_integer(match.second, val, /* Base = */ 10))
128 return {};
129
130 return GetAsArray()->GetItemAtIndex(val);
131 }
132
133 return shared_from_this();
134}
135
136void StructuredData::Object::DumpToStdout(bool pretty_print) const {
137 json::OStream stream(llvm::outs(), pretty_print ? 2 : 0);
138 Serialize(stream);
139}
140
141void StructuredData::Array::Serialize(json::OStream &s) const {
142 s.arrayBegin();
143 for (const auto &item_sp : m_items) {
144 item_sp->Serialize(s);
145 }
146 s.arrayEnd();
147}
148
149void StructuredData::Float::Serialize(json::OStream &s) const {
150 s.value(m_value);
151}
152
153void StructuredData::Boolean::Serialize(json::OStream &s) const {
154 s.value(m_value);
155}
156
157void StructuredData::String::Serialize(json::OStream &s) const {
158 s.value(m_value);
159}
160
161void StructuredData::Dictionary::Serialize(json::OStream &s) const {
162 s.objectBegin();
163 ForEachSorted([&s](llvm::StringRef key, Object *object) {
164 s.attributeBegin(key);
165 object->Serialize(s);
166 s.attributeEnd();
167 return true;
168 });
169 s.objectEnd();
170}
171
172void StructuredData::Null::Serialize(json::OStream &s) const {
173 s.value(nullptr);
174}
175
176void StructuredData::Generic::Serialize(json::OStream &s) const {
177 s.value(llvm::formatv("{0:X}", m_object));
178}
179
183
185 s.Printf(m_value ? "True" : "False");
186}
187
189 s.PutCString(m_value.empty() ? "\"\"" : m_value.c_str());
190}
191
193 size_t index = 0;
194 size_t indentation_level = s.GetIndentLevel();
195 for (const auto &item_sp : m_items) {
196 // Sanitize.
197 if (!item_sp)
198 continue;
199
200 // Reset original indentation level.
201 s.SetIndentLevel(indentation_level);
202 s.Indent();
203
204 // Print key
205 s.Printf("[%zu]:", index++);
206
207 // Return to new line and increase indentation if value is record type.
208 // Otherwise add spacing.
209 bool should_indent = IsRecordType(item_sp);
210 if (should_indent) {
211 s.EOL();
212 s.IndentMore();
213 } else {
214 s.PutChar(' ');
215 }
216
217 // Print value and new line if now last pair.
218 item_sp->GetDescription(s);
219 if (item_sp != *(--m_items.end()))
220 s.EOL();
221
222 // Reset indentation level if it was incremented previously.
223 if (should_indent)
224 s.IndentLess();
225 }
226}
227
229 size_t indentation_level = s.GetIndentLevel();
230 const size_t num_entries = GetSize();
231 size_t entry_index = 0;
232
233 ForEachSorted([&](llvm::StringRef key, Object *object) {
234 const bool is_last = ++entry_index == num_entries;
235
236 // Sanitize.
237 if (key.empty() || !object)
238 return true;
239
240 // Reset original indentation level.
241 s.SetIndentLevel(indentation_level);
242 s.Indent();
243
244 // Print key.
245 s.Format("{0}:", key);
246
247 // Return to new line and increase indentation if value is record type.
248 // Otherwise add spacing.
249 bool should_indent = IsRecordType(object->shared_from_this());
250 if (should_indent) {
251 s.EOL();
252 s.IndentMore();
253 } else {
254 s.PutChar(' ');
255 }
256
257 // Print value and new line if now last pair.
258 object->GetDescription(s);
259 if (!is_last)
260 s.EOL();
261
262 // Reset indentation level if it was incremented previously.
263 if (should_indent)
264 s.IndentLess();
265 return true;
266 });
267}
268
272
static llvm::raw_ostream & error(Stream &strm)
static StructuredData::ObjectSP ParseJSONObject(const json::Object &object)
static StructuredData::ObjectSP ParseJSONArray(const json::Array &array)
A file utility class.
Definition FileSpec.h:56
size_t GetPath(char *path, size_t max_path_length, bool denormalize=true) const
Extract the full path to the file.
Definition FileSpec.cpp:380
An error handling class.
Definition Status.h:118
static Status static Status FromErrorStringWithFormatv(const char *format, Args &&...args)
Definition Status.h:151
static Status FromError(llvm::Error error)
Avoid using this in new code. Migrate APIs to llvm::Expected instead.
Definition Status.cpp:136
A stream class that can stream formatted output to a file.
Definition Stream.h:28
void Format(const char *format, Args &&... args)
Forwards the arguments to llvm::formatv and writes to the stream.
Definition Stream.h:370
size_t Indent(llvm::StringRef s="")
Indent the current line in the stream.
Definition Stream.cpp:157
size_t Printf(const char *format,...) __attribute__((format(printf
Output printf formatted output to the stream.
Definition Stream.cpp:134
size_t PutCString(llvm::StringRef cstr)
Output a C string to the stream.
Definition Stream.cpp:63
size_t PutChar(char ch)
Definition Stream.cpp:131
void SetIndentLevel(unsigned level)
Set the current indentation level.
Definition Stream.cpp:196
size_t EOL()
Output and End of Line character to the stream.
Definition Stream.cpp:155
void IndentLess(unsigned amount=2)
Decrement the current indentation level.
Definition Stream.cpp:204
void IndentMore(unsigned amount=2)
Increment the current indentation level.
Definition Stream.cpp:201
unsigned GetIndentLevel() const
Get the current indentation level.
Definition Stream.cpp:193
void Serialize(llvm::json::OStream &s) const override
ObjectSP GetItemAtIndex(size_t idx) const
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
void ForEachSorted(std::function< bool(llvm::StringRef key, Object *object)> const &callback) const
Like ForEach, but visits the entries in key order, for stable output.
ObjectSP GetValueForKey(llvm::StringRef key) const
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
void DumpToStdout(bool pretty_print=true) const
Object(lldb::StructuredDataType t=lldb::eStructuredDataTypeInvalid)
lldb::StructuredDataType GetType() const
ObjectSP GetObjectForDotSeparatedPath(llvm::StringRef path)
void GetDescription(lldb_private::Stream &s) const override
void Serialize(llvm::json::OStream &s) const override
static ObjectSP ParseJSONValue(const llvm::json::Value &value)
static bool IsRecordType(const ObjectSP object_sp)
std::shared_ptr< Object > ObjectSP
static ObjectSP ParseJSON(llvm::StringRef json_text)
static ObjectSP ParseJSONFromFile(const FileSpec &file, Status &error)
A class that represents a running process on the host machine.
StructuredData::ObjectSP Serialize(llvm::ArrayRef< DiagnosticDetail > details)
@ eStructuredDataTypeDictionary
@ eStructuredDataTypeArray