1// Copyright (C) 2021 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qtypedjson_p.h"
5#include <QtCore/QLoggingCategory>
6#include <QtCore/qjsondocument.h>
7#include <QtCore/qjsonvalue.h>
8#include <QtCore/qjsonarray.h>
9#include <cstring>
10
11QT_BEGIN_NAMESPACE
12
13namespace QTypedJson {
14
15Q_LOGGING_CATEGORY(jsonRpcLog, "qt.jsonrpc");
16
17Reader::Reader(const QJsonValue &v)
18 : m_p(new ReaderPrivate { .valuesStack: QList({ ValueStack { .value: v, .fieldPath: QString(), .indexPath: -1, .warnLevel: 0 } }) })
19{
20}
21
22Reader::~Reader()
23{
24 for (const QString &msg : m_p->errorMessages)
25 qCWarning(jsonRpcLog) << msg;
26 delete m_p;
27}
28
29QStringList Reader::errorMessages()
30{
31 return m_p->errorMessages;
32}
33
34void Reader::clearErrorMessages()
35{
36 m_p->errorMessages.clear();
37}
38
39void Reader::handleBasic(bool &el)
40{
41 if (currentValue().isBool())
42 el = currentValue().toBool();
43 else
44 warnMissing(s: u"bool");
45}
46
47void Reader::handleBasic(QByteArray &el)
48{
49 if (currentValue().isString())
50 el = currentValue().toString().toUtf8();
51 else
52 warnMissing(s: u"string");
53}
54
55void Reader::handleBasic(int &el)
56{
57 if (currentValue().isDouble())
58 el = currentValue().toInt(defaultValue: el);
59 else
60 warnMissing(s: u"int");
61}
62
63void Reader::handleBasic(double &el)
64{
65 if (currentValue().isDouble())
66 el = currentValue().toDouble();
67 else
68 warnMissing(s: u"double");
69}
70
71void Reader::handleNullType()
72{
73 if (!currentValue().isNull() && !currentValue().isUndefined()) {
74 warnNonNull();
75 }
76}
77
78bool Reader::startField(const QString &fieldName)
79{
80 int oldWarnLevel = (m_p->valuesStack.isEmpty() ? 0 : m_p->valuesStack.last().warnLevel);
81 m_p->objectsStack.last().visitedFields.insert(value: fieldName);
82 m_p->valuesStack.append(t: ValueStack { .value: currentValue()[fieldName], .fieldPath: fieldName, .indexPath: -1,
83 .warnLevel: (oldWarnLevel ? oldWarnLevel + 1 : 0) });
84 return true;
85}
86
87bool Reader::startField(const char *fieldName)
88{
89 QString f = QString::fromUtf8(utf8: fieldName); // conversion needed just to set the fieldPath
90 return startField(fieldName: f);
91}
92
93void Reader::endField(const QString &fieldName)
94{
95 Q_ASSERT(m_p->valuesStack.last().fieldPath == fieldName);
96 m_p->valuesStack.removeLast();
97}
98
99void Reader::endField(const char *fieldName)
100{
101 QString f = QString::fromUtf8(utf8: fieldName);
102 endField(fieldName: f);
103}
104
105bool Reader::startObjectF(const char *type, ObjectOptions options, quintptr)
106{
107 if (m_p->parseStatus != ParseStatus::Normal)
108 return false;
109 if (currentValue().isUndefined()) {
110 m_p->parseStatus = ParseStatus::Failed;
111 return false;
112 }
113 m_p->objectsStack.append(t: ObjectStack { .type: type, .options: options, .visitedFields: {} });
114 return true;
115}
116
117void Reader::endObjectF(const char *type, ObjectOptions, quintptr)
118{
119 Q_ASSERT(std::strcmp(m_p->objectsStack.last().type, type) == 0);
120 m_p->objectsStack.removeLast();
121}
122
123void Reader::warnExtra(const QJsonObject &e)
124{
125 if (e.constBegin() != e.constEnd())
126 warn(QStringLiteral(u"%1 has extra fields %2")
127 .arg(args: currentPath(), args: QString::fromUtf8(ba: QJsonDocument(e).toJson())));
128}
129
130void Reader::warnInvalidSize(qint32 size, qint32 expectedSize)
131{
132 if (size != expectedSize)
133 warn(QStringLiteral(u"%1 expected %1 elements, not %2.")
134 .arg(args: currentPath(), args: QString::number(expectedSize), args: QString::number(size)));
135}
136
137void Reader::warnMissing(QStringView s)
138{
139 warn(QStringLiteral(u"%1 misses value of type %2").arg(args: currentPath(), args&: s));
140}
141
142void Reader::warnNonNull()
143{
144 QByteArray val = QJsonDocument(QJsonArray({ currentValue() })).toJson();
145 warn(QStringLiteral(u"%1 is supposed to be null, but is %2")
146 .arg(args: currentPath(), args: QString::fromUtf8(ba: val.mid(index: 1, len: val.size() - 2))));
147}
148
149void Reader::warn(const QString &msg)
150{
151 m_p->errorMessages.append(t: msg);
152 m_p->parseStatus = ParseStatus::Failed;
153}
154
155void Reader::handleJson(QJsonValue &v)
156{
157 v = currentValue();
158}
159
160void Reader::handleJson(QJsonObject &v)
161{
162 if (!currentValue().isObject() && !currentValue().isNull() && !currentValue().isUndefined()) {
163 QByteArray val = QJsonDocument(QJsonArray({ currentValue() })).toJson();
164 warn(QStringLiteral(u"Error: expected an object at %1, not %2")
165 .arg(args: currentPath(), args: QString::fromUtf8(ba: val.mid(index: 1, len: val.size() - 2))));
166 }
167 v = currentValue().toObject();
168}
169
170void Reader::handleJson(QJsonArray &v)
171{
172 if (!currentValue().isArray() && !currentValue().isNull() && !currentValue().isUndefined()) {
173 QByteArray val = QJsonDocument(QJsonArray({ currentValue() })).toJson();
174 warn(QStringLiteral(u"Error: expected an array at %1, not %2")
175 .arg(args: currentPath(), args: QString::fromUtf8(ba: val.mid(index: 1, len: val.size() - 2))));
176 }
177 v = currentValue().toArray();
178}
179
180QJsonObject Reader::getExtraFields() const
181{
182 QJsonObject extraFields;
183 QJsonObject v = currentValue().toObject();
184 auto it = v.constBegin();
185 auto end = v.constEnd();
186 auto &vField = m_p->objectsStack.last().visitedFields;
187 while (it != end) {
188 if (!vField.contains(value: it.key())) {
189 extraFields.insert(key: it.key(), value: it.value());
190 }
191 ++it;
192 }
193 return extraFields;
194}
195
196void Reader::startArrayF(qint32 &size)
197{
198 size = int(currentValue().toArray().size());
199}
200
201bool Reader::startElement(qint32 index)
202{
203 int oldWarnLevel = (m_p->valuesStack.isEmpty() ? 0 : m_p->valuesStack.last().warnLevel);
204 m_p->valuesStack.append(t: ValueStack { .value: currentValue().toArray().at(i: index), .fieldPath: QString(), .indexPath: index,
205 .warnLevel: (oldWarnLevel ? oldWarnLevel + 1 : 0) });
206 return true;
207}
208
209void Reader::endElement(qint32 index)
210{
211 Q_ASSERT(m_p->valuesStack.last().indexPath == index);
212 m_p->valuesStack.removeLast();
213}
214
215void Reader::endArrayF(qint32 &) { }
216
217QString Reader::currentPath() const
218{
219 QStringList res;
220 for (const auto &el : std::as_const(t&: m_p->valuesStack)) {
221 if (el.indexPath != -1)
222 res.append(t: QString::number(el.indexPath));
223 else
224 res.append(t: el.fieldPath);
225 }
226 return res.join(sep: u".");
227}
228
229bool Reader::startTuple(qint32 size)
230{
231 qint32 expected = qint32(currentValue().toArray().size());
232 if (size != expected) {
233 warnInvalidSize(size, expectedSize: expected);
234 return false;
235 };
236 return true;
237}
238
239void Reader::endTuple(qint32) { }
240
241void JsonBuilder::handleBasic(const bool &v)
242{
243 m_values.append(t: QJsonValue(v));
244}
245
246void JsonBuilder::handleBasic(const QByteArray &v)
247{
248 m_values.append(t: QJsonValue(QString::fromUtf8(ba: v)));
249}
250
251void JsonBuilder::handleBasic(const int &v)
252{
253 m_values.append(t: QJsonValue(v));
254}
255
256void JsonBuilder::handleBasic(const double &v)
257{
258 m_values.append(t: QJsonValue(v));
259}
260
261void JsonBuilder::handleNullType()
262{
263 m_values.append(t: QJsonValue(QJsonValue::Type::Null));
264}
265
266void JsonBuilder::handleMissingOptional()
267{
268 if (m_fieldLevel.isEmpty() || m_fieldLevel.last() != m_values.size())
269 handleNullType();
270}
271
272bool JsonBuilder::startField(const QString &)
273{
274 m_fieldLevel.append(t: m_values.size());
275 return true;
276}
277
278bool JsonBuilder::startField(const char *)
279{
280 m_fieldLevel.append(t: m_values.size());
281 return true;
282}
283
284void JsonBuilder::endField(const QString &v)
285{
286 Q_ASSERT(!m_fieldLevel.isEmpty());
287 if (m_fieldLevel.last() < m_values.size()) {
288 Q_ASSERT(m_values.size() > 1);
289 if (QJsonObject *o = std::get_if<QJsonObject>(ptr: &m_values[m_values.size() - 2])) {
290 o->insert(key: v, value: popLastValue());
291 } else {
292 Q_ASSERT(false);
293 }
294 }
295 Q_ASSERT(!m_fieldLevel.isEmpty() && m_fieldLevel.last() == m_values.size());
296 m_fieldLevel.removeLast();
297}
298
299void JsonBuilder::endField(const char *v)
300{
301 endField(v: QString::fromUtf8(utf8: v));
302}
303
304bool JsonBuilder::startObjectF(const char *, ObjectOptions, quintptr)
305{
306 m_values.append(t: QJsonObject());
307 return true;
308}
309
310void JsonBuilder::endObjectF(const char *, ObjectOptions, quintptr) { }
311
312bool JsonBuilder::startArrayF(qint32 &)
313{
314 m_values.append(t: QJsonArray());
315 m_arrayLevel.append(t: m_values.size());
316 return true;
317}
318
319bool JsonBuilder::startElement(qint32)
320{
321 return true;
322}
323
324void JsonBuilder::endElement(qint32)
325{
326 Q_ASSERT(m_values.size() > 1);
327 if (QJsonArray *a = std::get_if<QJsonArray>(ptr: &m_values[m_values.size() - 2])) {
328 a->append(value: popLastValue());
329 } else {
330 Q_ASSERT(false);
331 }
332}
333
334void JsonBuilder::endArrayF(qint32 &)
335{
336 Q_ASSERT(!m_arrayLevel.isEmpty() && m_arrayLevel.last() == m_values.size());
337 m_arrayLevel.removeLast();
338}
339
340void JsonBuilder::handleJson(QJsonValue &v)
341{
342 m_values.append(t: v);
343}
344
345void JsonBuilder::handleJson(QJsonObject &v)
346{
347 m_values.append(t: v);
348}
349
350void JsonBuilder::handleJson(QJsonArray &v)
351{
352 m_values.append(t: v);
353}
354
355QJsonValue JsonBuilder::popLastValue()
356{
357 if (m_values.isEmpty())
358 return QJsonValue(QJsonValue::Type::Undefined);
359 QJsonValue res = std::visit(visitor: [](auto &v) { return QJsonValue(v); }, variants&: m_values.last());
360 m_values.removeLast();
361 return res;
362}
363
364bool JsonBuilder::startTuple(qint32 size)
365{
366 return startArrayF(size);
367}
368
369void JsonBuilder::endTuple(qint32 size)
370{
371 endArrayF(size);
372}
373
374} // namespace QTypedJson
375
376QT_END_NAMESPACE
377

Provided by KDAB

Privacy Policy
Start learning QML with our Intro Training
Find out more

source code of qtlanguageserver/src/jsonrpc/qtypedjson.cpp