1/****************************************************************************
2**
3** Copyright (C) 2016 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the QtQml module of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:LGPL$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU Lesser General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU Lesser
19** General Public License version 3 as published by the Free Software
20** Foundation and appearing in the file LICENSE.LGPL3 included in the
21** packaging of this file. Please review the following information to
22** ensure the GNU Lesser General Public License version 3 requirements
23** will be met: https://www.gnu.org/licenses/lgpl-3.0.html.
24**
25** GNU General Public License Usage
26** Alternatively, this file may be used under the terms of the GNU
27** General Public License version 2.0 or (at your option) the GNU General
28** Public license version 3 or any later version approved by the KDE Free
29** Qt Foundation. The licenses are as published by the Free Software
30** Foundation and appearing in the file LICENSE.GPL2 and LICENSE.GPL3
31** included in the packaging of this file. Please review the following
32** information to ensure the GNU General Public License requirements will
33** be met: https://www.gnu.org/licenses/gpl-2.0.html and
34** https://www.gnu.org/licenses/gpl-3.0.html.
35**
36** $QT_END_LICENSE$
37**
38****************************************************************************/
39
40#include "qqmlerror.h"
41#include "qqmlfile.h"
42#include "qqmlsourcecoordinate_p.h"
43#include <private/qqmljsdiagnosticmessage_p.h>
44
45#include <QtCore/qdebug.h>
46#include <QtCore/qfile.h>
47#include <QtCore/qstringlist.h>
48#include <QtCore/qvector.h>
49
50#include <QtCore/qobject.h>
51#include <QtCore/qpointer.h>
52
53QT_BEGIN_NAMESPACE
54
55/*!
56 \class QQmlError
57 \since 5.0
58 \inmodule QtQml
59 \brief The QQmlError class encapsulates a QML error.
60
61 QQmlError includes a textual description of the error, as well
62 as location information (the file, line, and column). The toString()
63 method creates a single-line, human-readable string containing all of
64 this information, for example:
65 \code
66 file:///home/user/test.qml:7:8: Invalid property assignment: double expected
67 \endcode
68
69 You can use qDebug(), qInfo(), or qWarning() to output errors to the console.
70 This method will attempt to open the file indicated by the error
71 and include additional contextual information.
72 \code
73 file:///home/user/test.qml:7:8: Invalid property assignment: double expected
74 y: "hello"
75 ^
76 \endcode
77
78 \sa QQuickView::errors(), QQmlComponent::errors()
79*/
80class QQmlErrorPrivate
81{
82public:
83 QUrl url;
84 QPointer<QObject> object;
85 QString message;
86 QtMsgType type = QtWarningMsg;
87 int line = -1;
88 int column = -1;
89};
90
91/*!
92 Creates an empty error object.
93*/
94QQmlError::QQmlError()
95: d(nullptr)
96{
97}
98
99/*!
100 Creates a copy of \a other.
101*/
102QQmlError::QQmlError(const QQmlError &other)
103: d(nullptr)
104{
105 *this = other;
106}
107
108/*!
109 Assigns \a other to this error object.
110*/
111QQmlError &QQmlError::operator=(const QQmlError &other)
112{
113 if (!other.d) {
114 delete d;
115 d = nullptr;
116 } else {
117 if (!d)
118 d = new QQmlErrorPrivate;
119 d->url = other.d->url;
120 d->message = other.d->message;
121 d->line = other.d->line;
122 d->column = other.d->column;
123 d->object = other.d->object;
124 d->type = other.d->type;
125 }
126 return *this;
127}
128
129/*!
130 \internal
131*/
132QQmlError::~QQmlError()
133{
134 delete d; d = nullptr;
135}
136
137/*!
138 Returns true if this error is valid, otherwise false.
139*/
140bool QQmlError::isValid() const
141{
142 return d != nullptr;
143}
144
145/*!
146 Returns the url for the file that caused this error.
147*/
148QUrl QQmlError::url() const
149{
150 if (d)
151 return d->url;
152 return QUrl();
153}
154
155/*!
156 Sets the \a url for the file that caused this error.
157*/
158void QQmlError::setUrl(const QUrl &url)
159{
160 if (!d)
161 d = new QQmlErrorPrivate;
162 d->url = url;
163}
164
165/*!
166 Returns the error description.
167*/
168QString QQmlError::description() const
169{
170 if (d)
171 return d->message;
172 return QString();
173}
174
175/*!
176 Sets the error \a description.
177*/
178void QQmlError::setDescription(const QString &description)
179{
180 if (!d)
181 d = new QQmlErrorPrivate;
182 d->message = description;
183}
184
185/*!
186 Returns the error line number.
187*/
188int QQmlError::line() const
189{
190 if (d)
191 return d->line;
192 return -1;
193}
194
195/*!
196 Sets the error \a line number.
197*/
198void QQmlError::setLine(int line)
199{
200 if (!d)
201 d = new QQmlErrorPrivate;
202 d->line = line;
203}
204
205/*!
206 Returns the error column number.
207*/
208int QQmlError::column() const
209{
210 if (d)
211 return d->column;
212 return -1;
213}
214
215/*!
216 Sets the error \a column number.
217*/
218void QQmlError::setColumn(int column)
219{
220 if (!d)
221 d = new QQmlErrorPrivate;
222 d->column = column;
223}
224
225/*!
226 Returns the nearest object where this error occurred.
227 Exceptions in bound property expressions set this to the object
228 to which the property belongs. It will be 0 for all
229 other exceptions.
230 */
231QObject *QQmlError::object() const
232{
233 if (d)
234 return d->object;
235 return nullptr;
236}
237
238/*!
239 Sets the nearest \a object where this error occurred.
240 */
241void QQmlError::setObject(QObject *object)
242{
243 if (!d)
244 d = new QQmlErrorPrivate;
245 d->object = object;
246}
247
248/*!
249 \since 5.9
250
251 Returns the message type.
252 */
253QtMsgType QQmlError::messageType() const
254{
255 if (d)
256 return d->type;
257 return QtMsgType::QtWarningMsg;
258}
259
260/*!
261 \since 5.9
262
263 Sets the \a messageType for this message. The message type determines which
264 QDebug handlers are responsible for receiving the message.
265 */
266void QQmlError::setMessageType(QtMsgType messageType)
267{
268 if (!d)
269 d = new QQmlErrorPrivate;
270 d->type = messageType;
271}
272
273/*!
274 Returns the error as a human readable string.
275*/
276QString QQmlError::toString() const
277{
278 QString rv;
279
280 QUrl u(url());
281 int l(line());
282
283 if (u.isEmpty() || (u.isLocalFile() && u.path().isEmpty()))
284 rv += QLatin1String("<Unknown File>");
285 else
286 rv += u.toString();
287
288 if (l != -1) {
289 rv += QLatin1Char(':') + QString::number(l);
290
291 int c(column());
292 if (c != -1)
293 rv += QLatin1Char(':') + QString::number(c);
294 }
295
296 rv += QLatin1String(": ") + description();
297
298 return rv;
299}
300
301/*!
302 \relates QQmlError
303 \fn QDebug operator<<(QDebug debug, const QQmlError &error)
304
305 Outputs a human readable version of \a error to \a debug.
306*/
307
308QDebug operator<<(QDebug debug, const QQmlError &error)
309{
310 debug << qPrintable(error.toString());
311
312 QUrl url = error.url();
313
314 if (error.line() > 0 && (url.scheme() == QLatin1String("file") || url.scheme() == QLatin1String("qrc"))) {
315 QString file = QQmlFile::urlToLocalFileOrQrc(url);
316 QFile f(file);
317 if (f.open(flags: QIODevice::ReadOnly)) {
318 QByteArray data = f.readAll();
319 QTextStream stream(data, QIODevice::ReadOnly);
320#if QT_CONFIG(textcodec)
321 stream.setCodec("UTF-8");
322#endif
323 const QString code = stream.readAll();
324 const auto lines = code.splitRef(sep: QLatin1Char('\n'));
325
326 if (lines.count() >= error.line()) {
327 const QStringRef &line = lines.at(i: error.line() - 1);
328 debug << "\n " << line.toLocal8Bit().constData();
329
330 if(error.column() > 0) {
331 int column = qMax(a: 0, b: error.column() - 1);
332 column = qMin(a: column, b: line.length());
333
334 QByteArray ind;
335 ind.reserve(asize: column);
336 for (int i = 0; i < column; ++i) {
337 const QChar ch = line.at(i);
338 if (ch.isSpace())
339 ind.append(c: ch.unicode());
340 else
341 ind.append(c: ' ');
342 }
343 ind.append(c: '^');
344 debug << "\n " << ind.constData();
345 }
346 }
347 }
348 }
349 return debug;
350}
351
352QT_END_NAMESPACE
353

source code of qtdeclarative/src/qml/qml/qqmlerror.cpp