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 return false;
111 m_p->objectsStack.append(t: ObjectStack { .type: type, .options: options, .visitedFields: {} });
112 return true;
113}
114
115void Reader::endObjectF(const char *type, ObjectOptions, quintptr)
116{
117 Q_ASSERT(std::strcmp(m_p->objectsStack.last().type, type) == 0);
118 m_p->objectsStack.removeLast();
119}
120
121void Reader::warnExtra(const QJsonObject &e)
122{
123 if (e.constBegin() != e.constEnd())
124 warn(QStringLiteral(u"%1 has extra fields %2")
125 .arg(args: currentPath(), args: QString::fromUtf8(ba: QJsonDocument(e).toJson())));
126}
127
128void Reader::warnInvalidSize(qint32 size, qint32 expectedSize)
129{
130 if (size != expectedSize)
131 warn(QStringLiteral(u"%1 expected %1 elements, not %2.")
132 .arg(args: currentPath(), args: QString::number(expectedSize), args: QString::number(size)));
133}
134
135void Reader::warnMissing(QStringView s)
136{
137 warn(QStringLiteral(u"%1 misses value of type %2").arg(args: currentPath(), args&: s));
138}
139
140void Reader::warnNonNull()
141{
142 QByteArray val = QJsonDocument(QJsonArray({ currentValue() })).toJson();
143 warn(QStringLiteral(u"%1 is supposed to be null, but is %2")
144 .arg(args: currentPath(), args: QString::fromUtf8(ba: val.mid(index: 1, len: val.size() - 2))));
145}
146
147void Reader::warn(const QString &msg)
148{
149 m_p->errorMessages.append(t: msg);
150 m_p->parseStatus = ParseStatus::Failed;
151}
152
153void Reader::handleJson(QJsonValue &v)
154{
155 v = currentValue();
156}
157
158void Reader::handleJson(QJsonObject &v)
159{
160 if (!currentValue().isObject() && !currentValue().isNull() && !currentValue().isUndefined()) {
161 QByteArray val = QJsonDocument(QJsonArray({ currentValue() })).toJson();
162 warn(QStringLiteral(u"Error: expected an object at %1, not %2")
163 .arg(args: currentPath(), args: QString::fromUtf8(ba: val.mid(index: 1, len: val.size() - 2))));
164 }
165 v = currentValue().toObject();
166}
167
168void Reader::handleJson(QJsonArray &v)
169{
170 if (!currentValue().isArray() && !currentValue().isNull() && !currentValue().isUndefined()) {
171 QByteArray val = QJsonDocument(QJsonArray({ currentValue() })).toJson();
172 warn(QStringLiteral(u"Error: expected an array at %1, not %2")
173 .arg(args: currentPath(), args: QString::fromUtf8(ba: val.mid(index: 1, len: val.size() - 2))));
174 }
175 v = currentValue().toArray();
176}
177
178QJsonObject Reader::getExtraFields() const
179{
180 QJsonObject extraFields;
181 QJsonObject v = currentValue().toObject();
182 auto it = v.constBegin();
183 auto end = v.constEnd();
184 auto &vField = m_p->objectsStack.last().visitedFields;
185 while (it != end) {
186 if (!vField.contains(value: it.key())) {
187 extraFields.insert(key: it.key(), value: it.value());
188 }
189 ++it;
190 }
191 return extraFields;
192}
193
194void Reader::startArrayF(qint32 &size)
195{
196 size = int(currentValue().toArray().size());
197}
198
199bool Reader::startElement(qint32 index)
200{
201 int oldWarnLevel = (m_p->valuesStack.isEmpty() ? 0 : m_p->valuesStack.last().warnLevel);
202 m_p->valuesStack.append(t: ValueStack { .value: currentValue().toArray().at(i: index), .fieldPath: QString(), .indexPath: index,
203 .warnLevel: (oldWarnLevel ? oldWarnLevel + 1 : 0) });
204 return true;
205}
206
207void Reader::endElement(qint32 index)
208{
209 Q_ASSERT(m_p->valuesStack.last().indexPath == index);
210 m_p->valuesStack.removeLast();
211}
212
213void Reader::endArrayF(qint32 &) { }
214
215QString Reader::currentPath() const
216{
217 QStringList res;
218 for (const auto &el : std::as_const(t&: m_p->valuesStack)) {
219 if (el.indexPath != -1)
220 res.append(t: QString::number(el.indexPath));
221 else
222 res.append(t: el.fieldPath);
223 }
224 return res.join(sep: u".");
225}
226
227bool Reader::startTuple(qint32 size)
228{
229 qint32 expected = qint32(currentValue().toArray().size());
230 if (size != expected) {
231 warnInvalidSize(size, expectedSize: expected);
232 return false;
233 };
234 return true;
235}
236
237void Reader::endTuple(qint32) { }
238
239void JsonBuilder::handleBasic(const bool &v)
240{
241 m_values.append(t: QJsonValue(v));
242}
243
244void JsonBuilder::handleBasic(const QByteArray &v)
245{
246 m_values.append(t: QJsonValue(QString::fromUtf8(ba: v)));
247}
248
249void JsonBuilder::handleBasic(const int &v)
250{
251 m_values.append(t: QJsonValue(v));
252}
253
254void JsonBuilder::handleBasic(const double &v)
255{
256 m_values.append(t: QJsonValue(v));
257}
258
259void JsonBuilder::handleNullType()
260{
261 m_values.append(t: QJsonValue(QJsonValue::Type::Null));
262}
263
264void JsonBuilder::handleMissingOptional()
265{
266 if (m_fieldLevel.isEmpty() || m_fieldLevel.last() != m_values.size())
267 handleNullType();
268}
269
270bool JsonBuilder::startField(const QString &)
271{
272 m_fieldLevel.append(t: m_values.size());
273 return true;
274}
275
276bool JsonBuilder::startField(const char *)
277{
278 m_fieldLevel.append(t: m_values.size());
279 return true;
280}
281
282void JsonBuilder::endField(const QString &v)
283{
284 Q_ASSERT(!m_fieldLevel.isEmpty());
285 if (m_fieldLevel.last() < m_values.size()) {
286 Q_ASSERT(m_values.size() > 1);
287 if (QJsonObject *o = std::get_if<QJsonObject>(ptr: &m_values[m_values.size() - 2])) {
288 o->insert(key: v, value: popLastValue());
289 } else {
290 Q_ASSERT(false);
291 }
292 }
293 Q_ASSERT(!m_fieldLevel.isEmpty() && m_fieldLevel.last() == m_values.size());
294 m_fieldLevel.removeLast();
295}
296
297void JsonBuilder::endField(const char *v)
298{
299 endField(v: QString::fromUtf8(utf8: v));
300}
301
302bool JsonBuilder::startObjectF(const char *, ObjectOptions, quintptr)
303{
304 m_values.append(t: QJsonObject());
305 return true;
306}
307
308void JsonBuilder::endObjectF(const char *, ObjectOptions, quintptr) { }
309
310bool JsonBuilder::startArrayF(qint32 &)
311{
312 m_values.append(t: QJsonArray());
313 m_arrayLevel.append(t: m_values.size());
314 return true;
315}
316
317bool JsonBuilder::startElement(qint32)
318{
319 return true;
320}
321
322void JsonBuilder::endElement(qint32)
323{
324 Q_ASSERT(m_values.size() > 1);
325 if (QJsonArray *a = std::get_if<QJsonArray>(ptr: &m_values[m_values.size() - 2])) {
326 a->append(value: popLastValue());
327 } else {
328 Q_ASSERT(false);
329 }
330}
331
332void JsonBuilder::endArrayF(qint32 &)
333{
334 Q_ASSERT(!m_arrayLevel.isEmpty() && m_arrayLevel.last() == m_values.size());
335 m_arrayLevel.removeLast();
336}
337
338void JsonBuilder::handleJson(QJsonValue &v)
339{
340 m_values.append(t: v);
341}
342
343void JsonBuilder::handleJson(QJsonObject &v)
344{
345 m_values.append(t: v);
346}
347
348void JsonBuilder::handleJson(QJsonArray &v)
349{
350 m_values.append(t: v);
351}
352
353QJsonValue JsonBuilder::popLastValue()
354{
355 if (m_values.isEmpty())
356 return QJsonValue(QJsonValue::Type::Undefined);
357 QJsonValue res = std::visit(visitor: [](auto &v) { return QJsonValue(v); }, variants&: m_values.last());
358 m_values.removeLast();
359 return res;
360}
361
362bool JsonBuilder::startTuple(qint32 size)
363{
364 return startArrayF(size);
365}
366
367void JsonBuilder::endTuple(qint32 size)
368{
369 endArrayF(size);
370}
371
372} // namespace QTypedJson
373
374QT_END_NAMESPACE
375

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