1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
3
4#include "qqmljsloggingutils_p.h"
5
6#include <QtQmlToolingSettings/private/qqmltoolingsettings_p.h>
7#include <QtCore/qcommandlineparser.h>
8
9QT_BEGIN_NAMESPACE
10
11using namespace Qt::StringLiterals;
12
13/*!
14 \class QQmlSA::LoggerWarningId
15 \inmodule QtQmlCompiler
16
17 \brief A wrapper around a string literal to uniquely identify
18 warning categories in the \c{QQmlSA} framework.
19*/
20
21/*!
22 \fn QQmlSA::LoggerWarningId::LoggerWarningId(QAnyStringView name)
23 Constructs a LoggerWarningId object with logging catergory name \a name.
24*/
25
26/*!
27 \fn QAnyStringView QQmlSA::LoggerWarningId::name() const
28 Returns the name of the wrapped warning category.
29*/
30
31namespace QQmlJS {
32
33LoggerCategory::LoggerCategory() : d_ptr{ new LoggerCategoryPrivate } { }
34
35LoggerCategory::LoggerCategory(QString name, QString settingsName, QString description,
36 QtMsgType level, bool ignored, bool isDefault)
37 : d_ptr{ new LoggerCategoryPrivate }
38{
39 Q_D(LoggerCategory);
40 d->m_name = name;
41 d->m_settingsName = settingsName;
42 d->m_description = description;
43 d->m_level = level;
44 d->m_ignored = ignored;
45 d->m_isDefault = isDefault;
46}
47
48LoggerCategory::LoggerCategory(const LoggerCategory &other)
49 : d_ptr{ new LoggerCategoryPrivate{ *other.d_func() } }
50{
51}
52
53LoggerCategory::LoggerCategory(LoggerCategory &&) noexcept = default;
54
55LoggerCategory &LoggerCategory::operator=(const LoggerCategory &other)
56{
57 *d_func() = *other.d_func();
58 return *this;
59}
60
61LoggerCategory &LoggerCategory::operator=(LoggerCategory &&) noexcept = default;
62
63LoggerCategory::~LoggerCategory() = default;
64
65QString LoggerCategory::name() const
66{
67 Q_D(const LoggerCategory);
68 return d->m_name;
69}
70
71QString LoggerCategory::settingsName() const
72{
73 Q_D(const LoggerCategory);
74 return d->m_settingsName;
75}
76
77QString LoggerCategory::description() const
78{
79 Q_D(const LoggerCategory);
80 return d->m_description;
81}
82
83QtMsgType LoggerCategory::level() const
84{
85 Q_D(const LoggerCategory);
86 return d->m_level;
87}
88
89bool LoggerCategory::isIgnored() const
90{
91 Q_D(const LoggerCategory);
92 return d->m_ignored;
93}
94
95bool LoggerCategory::isDefault() const
96{
97 Q_D(const LoggerCategory);
98 return d->m_isDefault;
99}
100
101LoggerWarningId LoggerCategory::id() const
102{
103 Q_D(const LoggerCategory);
104 return d->id();
105}
106
107void LoggerCategory::setLevel(QtMsgType type)
108{
109 Q_D(LoggerCategory);
110 d->setLevel(type);
111}
112
113void LoggerCategoryPrivate::setLevel(QtMsgType type)
114{
115 if (m_level == type)
116 return;
117
118 m_level = type;
119 m_changed = true;
120}
121
122void LoggerCategory::setIgnored(bool isIgnored)
123{
124 Q_D(LoggerCategory);
125 d->setIgnored(isIgnored);
126}
127
128void LoggerCategoryPrivate::setIgnored(bool isIgnored)
129{
130 if (m_ignored == isIgnored)
131 return;
132
133 m_ignored = isIgnored;
134 m_changed = true;
135}
136
137bool LoggerCategoryPrivate::hasChanged() const
138{
139 return m_changed;
140}
141
142LoggerCategoryPrivate *LoggerCategoryPrivate::get(LoggerCategory *loggerCategory)
143{
144 Q_ASSERT(loggerCategory);
145 return loggerCategory->d_func();
146}
147
148namespace LoggingUtils {
149
150QString levelToString(const QQmlJS::LoggerCategory &category)
151{
152 Q_ASSERT(category.isIgnored() || category.level() != QtCriticalMsg);
153 if (category.isIgnored())
154 return QStringLiteral("disable");
155
156 switch (category.level()) {
157 case QtInfoMsg:
158 return QStringLiteral("info");
159 case QtWarningMsg:
160 return QStringLiteral("warning");
161 default:
162 Q_UNREACHABLE();
163 break;
164 }
165};
166
167/*!
168\internal
169Sets the category levels from a settings file and an optional parser.
170Calls \c {parser->showHelp(-1)} for invalid logging levels.
171*/
172void updateLogLevels(QList<LoggerCategory> &categories,
173 const QQmlToolingSettings &settings,
174 QCommandLineParser *parser)
175{
176 bool success = true;
177 for (auto &category : categories) {
178 if (category.isDefault())
179 continue;
180
181 const QString value = [&] () {
182 const QString key = category.id().name().toString();
183 if (parser && parser->isSet(name: key))
184 return parser->value(name: key);
185
186 // Do not try to set the levels if it's due to a default config option.
187 // This way we can tell which options have actually been overwritten by the user.
188 const QString settingsName = QStringLiteral("Warnings/") + category.settingsName();
189 const QString value = settings.value(name: settingsName).toString();
190 if (levelToString(category) == value)
191 return QString();
192
193 return value;
194 }();
195 if (value.isEmpty())
196 continue;
197
198 if (value == "disable"_L1) {
199 category.setLevel(QtCriticalMsg);
200 category.setIgnored(true);
201 } else if (value == "info"_L1) {
202 category.setLevel(QtInfoMsg);
203 category.setIgnored(false);
204 } else if (value == "warning"_L1) {
205 category.setLevel(QtWarningMsg);
206 category.setIgnored(false);
207 } else {
208 qWarning() << "Invalid logging level" << value << "provided for"
209 << category.id().name().toString()
210 << "(allowed are: disable, info, warning)";
211 success = false;
212
213 }
214 }
215 if (!success && parser)
216 parser->showHelp(exitCode: -1);
217}
218} // namespace LoggingUtils
219
220} // namespace QQmlJS
221
222QT_END_NAMESPACE
223

source code of qtdeclarative/src/qmlcompiler/qqmljsloggingutils.cpp