2021-03-25 14:34:42 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Copyright (C) 2021 The Qt Company Ltd.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
|
|
|
**
|
|
|
|
** This file is part of the tools applications of the Qt Toolkit.
|
|
|
|
**
|
|
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
**
|
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "qqmljslogger_p.h"
|
|
|
|
|
2021-03-30 10:58:26 +00:00
|
|
|
const QMap<QString, QQmlJSLogger::Option> &QQmlJSLogger::options() {
|
|
|
|
static QMap<QString, QQmlJSLogger::Option> optionsMap = {
|
2021-04-19 14:54:45 +00:00
|
|
|
{ QStringLiteral("required"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_Required, QStringLiteral("RequiredProperty"),
|
2021-07-01 15:30:42 +00:00
|
|
|
QStringLiteral("Warn about required properties"), QtInfoMsg) },
|
2021-04-19 14:54:45 +00:00
|
|
|
{ QStringLiteral("alias"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_Alias, QStringLiteral("PropertyAlias"),
|
2021-07-01 15:30:42 +00:00
|
|
|
QStringLiteral("Warn about alias errors"), QtInfoMsg) },
|
2021-04-19 14:54:45 +00:00
|
|
|
{ QStringLiteral("import"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_Import, QStringLiteral("ImportFailure"),
|
2021-04-19 14:54:45 +00:00
|
|
|
QStringLiteral("Warn about failing imports and deprecated qmltypes"),
|
|
|
|
QtWarningMsg) },
|
|
|
|
{ QStringLiteral("with"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_WithStatement, QStringLiteral("WithStatement"),
|
2021-04-19 14:54:45 +00:00
|
|
|
QStringLiteral("Warn about with statements as they can cause false "
|
|
|
|
"positives when checking for unqualified access"),
|
|
|
|
QtWarningMsg) },
|
|
|
|
{ QStringLiteral("inheritance-cycle"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_InheritanceCycle, QStringLiteral("InheritanceCycle"),
|
2021-07-01 15:30:42 +00:00
|
|
|
QStringLiteral("Warn about inheritance cycles"), QtInfoMsg) },
|
2021-04-19 14:54:45 +00:00
|
|
|
{ QStringLiteral("deprecated"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_Deprecation, QStringLiteral("Deprecated"),
|
2021-04-19 14:54:45 +00:00
|
|
|
QStringLiteral("Warn about deprecated properties and types"),
|
|
|
|
QtWarningMsg) },
|
|
|
|
{ QStringLiteral("signal"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_Signal, QStringLiteral("BadSignalHandler"),
|
2021-04-19 14:54:45 +00:00
|
|
|
QStringLiteral("Warn about bad signal handler parameters"),
|
|
|
|
QtWarningMsg) },
|
|
|
|
{ QStringLiteral("type"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_Type, QStringLiteral("TypeError"),
|
2021-04-19 14:54:45 +00:00
|
|
|
QStringLiteral("Warn about unresolvable types and type mismatches"),
|
|
|
|
QtWarningMsg) },
|
|
|
|
{ QStringLiteral("property"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_Property, QStringLiteral("UnknownProperty"),
|
2021-07-01 15:30:42 +00:00
|
|
|
QStringLiteral("Warn about unknown properties"), QtInfoMsg) },
|
2021-04-19 14:54:45 +00:00
|
|
|
{ QStringLiteral("unqualified"),
|
|
|
|
QQmlJSLogger::Option(
|
2021-05-12 16:32:57 +00:00
|
|
|
Log_UnqualifiedAccess, QStringLiteral("UnqualifiedAccess"),
|
2021-04-19 14:54:45 +00:00
|
|
|
QStringLiteral("Warn about unqualified identifiers and how to fix them"),
|
|
|
|
QtWarningMsg) },
|
|
|
|
{ QStringLiteral("unused-imports"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_UnusedImport, QStringLiteral("UnusedImports"),
|
2021-07-01 15:30:42 +00:00
|
|
|
QStringLiteral("Warn about unused imports"), QtInfoMsg, false) },
|
2021-04-19 14:54:45 +00:00
|
|
|
{ QStringLiteral("multiline-strings"),
|
2021-05-12 16:32:57 +00:00
|
|
|
QQmlJSLogger::Option(Log_MultilineString, QStringLiteral("MultilineStrings"),
|
2021-07-05 10:48:49 +00:00
|
|
|
QStringLiteral("Warn about multiline strings"), QtInfoMsg, false) },
|
|
|
|
{ QStringLiteral("compiler"),
|
|
|
|
QQmlJSLogger::Option(Log_Compiler, QStringLiteral("CompilerWarnings"),
|
2021-09-23 10:18:17 +00:00
|
|
|
QStringLiteral("Warn about compiler issues"), QtCriticalMsg,
|
|
|
|
false) },
|
|
|
|
{ QStringLiteral("controls-sanity"),
|
|
|
|
QQmlJSLogger::Option(
|
|
|
|
Log_ControlsSanity, QStringLiteral("ControlsSanity"),
|
|
|
|
QStringLiteral("Performance checks used for QuickControl's implementation"),
|
|
|
|
QtCriticalMsg, false) }
|
2021-04-19 14:54:45 +00:00
|
|
|
};
|
2021-03-30 10:58:26 +00:00
|
|
|
|
|
|
|
return optionsMap;
|
|
|
|
}
|
|
|
|
|
2021-03-25 14:34:42 +00:00
|
|
|
QQmlJSLogger::QQmlJSLogger(const QString &fileName, const QString &code, bool silent) : m_fileName(fileName), m_code(code), m_output(silent)
|
|
|
|
{
|
2021-03-30 10:58:26 +00:00
|
|
|
const auto &opt = options();
|
|
|
|
for (auto it = opt.cbegin(); it != opt.cend(); ++it) {
|
|
|
|
m_categoryLevels[it.value().m_category] = it.value().m_level;
|
2021-07-01 15:30:42 +00:00
|
|
|
m_categoryError[it.value().m_category] = it.value().m_error;
|
2021-03-30 10:58:26 +00:00
|
|
|
}
|
|
|
|
|
2021-05-11 15:36:08 +00:00
|
|
|
// These have to be set up manually since we don't expose it as an option
|
2021-07-01 15:30:42 +00:00
|
|
|
m_categoryLevels[Log_RecursionDepthError] = QtInfoMsg;
|
|
|
|
m_categoryError[Log_RecursionDepthError] = true;
|
|
|
|
m_categoryLevels[Log_Syntax] = QtInfoMsg;
|
|
|
|
m_categoryError[Log_Syntax] = true;
|
2021-03-25 14:34:42 +00:00
|
|
|
|
|
|
|
// setup color output
|
|
|
|
m_output.insertMapping(QtCriticalMsg, QColorOutput::RedForeground);
|
|
|
|
m_output.insertMapping(QtWarningMsg, QColorOutput::PurpleForeground);
|
|
|
|
m_output.insertMapping(QtInfoMsg, QColorOutput::BlueForeground);
|
|
|
|
m_output.insertMapping(QtDebugMsg, QColorOutput::GreenForeground);
|
|
|
|
}
|
|
|
|
|
2021-07-01 15:30:42 +00:00
|
|
|
static bool isMsgTypeLess(QtMsgType a, QtMsgType b)
|
2021-03-25 14:34:42 +00:00
|
|
|
{
|
2021-07-01 15:30:42 +00:00
|
|
|
static QHash<QtMsgType, int> level = { { QtDebugMsg, 0 },
|
|
|
|
{ QtInfoMsg, 1 },
|
|
|
|
{ QtWarningMsg, 2 },
|
|
|
|
{ QtCriticalMsg, 3 },
|
|
|
|
{ QtFatalMsg, 4 } };
|
|
|
|
return level[a] < level[b];
|
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSLogger::log(const QString &message, QQmlJSLoggerCategory category,
|
|
|
|
const QQmlJS::SourceLocation &srcLocation, QtMsgType type, bool showContext,
|
|
|
|
bool showFileName)
|
|
|
|
{
|
|
|
|
if (isMsgTypeLess(type, m_categoryLevels[category]))
|
2021-03-25 14:34:42 +00:00
|
|
|
return;
|
|
|
|
|
2021-05-27 12:32:43 +00:00
|
|
|
if (srcLocation.isValid() && m_ignoredWarnings[srcLocation.startLine].contains(category))
|
|
|
|
return;
|
|
|
|
|
2021-03-25 14:34:42 +00:00
|
|
|
QString prefix;
|
|
|
|
|
2021-03-30 08:16:03 +00:00
|
|
|
if (!m_fileName.isEmpty() && showFileName)
|
2021-03-25 14:34:42 +00:00
|
|
|
prefix = m_fileName + QStringLiteral(":");
|
|
|
|
|
|
|
|
if (srcLocation.isValid())
|
|
|
|
prefix += QStringLiteral("%1:%2:").arg(srcLocation.startLine).arg(srcLocation.startColumn);
|
|
|
|
|
|
|
|
if (!prefix.isEmpty())
|
|
|
|
prefix.append(QLatin1Char(' '));
|
|
|
|
|
2021-07-01 15:30:42 +00:00
|
|
|
m_output.writePrefixedMessage(prefix + message, type);
|
|
|
|
|
|
|
|
QtMsgType machineType = isMsgTypeLess(QtWarningMsg, type) ? QtCriticalMsg : QtInfoMsg;
|
|
|
|
|
|
|
|
// If this is a category that produces error codes, we need to up all the messages to at least a
|
|
|
|
// warning level
|
|
|
|
if (isCategoryError(category)) {
|
|
|
|
if (isMsgTypeLess(type, QtWarningMsg))
|
|
|
|
machineType = QtWarningMsg;
|
|
|
|
else
|
|
|
|
machineType = type;
|
|
|
|
}
|
2021-03-25 14:34:42 +00:00
|
|
|
|
|
|
|
QQmlJS::DiagnosticMessage diagMsg;
|
|
|
|
diagMsg.message = message;
|
|
|
|
diagMsg.loc = srcLocation;
|
2021-07-01 15:30:42 +00:00
|
|
|
diagMsg.type = machineType;
|
2021-03-25 14:34:42 +00:00
|
|
|
|
2021-07-01 15:30:42 +00:00
|
|
|
switch (machineType) {
|
2021-03-25 14:34:42 +00:00
|
|
|
case QtWarningMsg: m_warnings.push_back(diagMsg); break;
|
|
|
|
case QtCriticalMsg: m_errors.push_back(diagMsg); break;
|
|
|
|
case QtInfoMsg: m_infos.push_back(diagMsg); break;
|
|
|
|
default: break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (srcLocation.isValid() && !m_code.isEmpty() && showContext)
|
|
|
|
printContext(srcLocation);
|
|
|
|
}
|
|
|
|
|
2021-07-01 11:55:11 +00:00
|
|
|
void QQmlJSLogger::suggestFix(const FixSuggestion &fix)
|
|
|
|
{
|
2021-07-01 15:30:42 +00:00
|
|
|
if (isMsgTypeLess(fix.level, m_categoryLevels[fix.category]))
|
2021-07-01 11:55:11 +00:00
|
|
|
return;
|
|
|
|
printFix(fix);
|
|
|
|
}
|
|
|
|
|
2021-07-01 15:30:42 +00:00
|
|
|
void QQmlJSLogger::processMessages(const QList<QQmlJS::DiagnosticMessage> &messages,
|
|
|
|
QtMsgType level, QQmlJSLoggerCategory category)
|
2021-03-25 14:34:42 +00:00
|
|
|
{
|
2021-07-01 15:30:42 +00:00
|
|
|
if (isMsgTypeLess(level, m_categoryLevels[category]) || messages.isEmpty())
|
2021-03-30 08:16:03 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
m_output.write(QStringLiteral("---\n"));
|
|
|
|
|
2021-03-25 14:34:42 +00:00
|
|
|
for (const QQmlJS::DiagnosticMessage &message : messages)
|
2021-07-01 15:30:42 +00:00
|
|
|
logWarning(message.message, category, QQmlJS::SourceLocation(), false, false);
|
2021-03-30 08:16:03 +00:00
|
|
|
|
|
|
|
m_output.write(QStringLiteral("---\n\n"));
|
2021-03-25 14:34:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void QQmlJSLogger::printContext(const QQmlJS::SourceLocation &location)
|
|
|
|
{
|
|
|
|
IssueLocationWithContext issueLocationWithContext { m_code, location };
|
|
|
|
if (const QStringView beforeText = issueLocationWithContext.beforeText(); !beforeText.isEmpty())
|
|
|
|
m_output.write(beforeText);
|
2021-04-19 14:54:45 +00:00
|
|
|
|
|
|
|
bool locationMultiline = issueLocationWithContext.issueText().contains(QLatin1Char('\n'));
|
|
|
|
|
2021-07-05 10:48:49 +00:00
|
|
|
if (!issueLocationWithContext.issueText().isEmpty())
|
|
|
|
m_output.write(issueLocationWithContext.issueText().toString(), QtCriticalMsg);
|
2021-08-13 07:44:42 +00:00
|
|
|
m_output.write(issueLocationWithContext.afterText().toString() + QLatin1Char('\n'));
|
2021-04-19 14:54:45 +00:00
|
|
|
|
|
|
|
// Do not draw location indicator for multiline locations
|
|
|
|
if (locationMultiline)
|
|
|
|
return;
|
|
|
|
|
2021-03-25 14:34:42 +00:00
|
|
|
int tabCount = issueLocationWithContext.beforeText().count(QLatin1Char('\t'));
|
2021-07-05 10:48:49 +00:00
|
|
|
int locationLength = location.length == 0 ? 1 : location.length;
|
|
|
|
m_output.write(QString::fromLatin1(" ").repeated(issueLocationWithContext.beforeText().length()
|
|
|
|
- tabCount)
|
|
|
|
+ QString::fromLatin1("\t").repeated(tabCount)
|
|
|
|
+ QString::fromLatin1("^").repeated(locationLength) + QLatin1Char('\n'));
|
2021-03-25 14:34:42 +00:00
|
|
|
}
|
2021-07-01 11:55:11 +00:00
|
|
|
|
|
|
|
void QQmlJSLogger::printFix(const FixSuggestion &fix)
|
|
|
|
{
|
|
|
|
for (const auto &fixItem : fix.fixes) {
|
|
|
|
m_output.writePrefixedMessage(fixItem.message, fixItem.type);
|
|
|
|
|
|
|
|
if (!fixItem.cutLocation.isValid())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
IssueLocationWithContext issueLocationWithContext { m_code, fixItem.cutLocation };
|
|
|
|
|
|
|
|
if (const QStringView beforeText = issueLocationWithContext.beforeText();
|
|
|
|
!beforeText.isEmpty()) {
|
|
|
|
m_output.write(beforeText);
|
|
|
|
}
|
|
|
|
|
|
|
|
m_output.write(fixItem.replacementString, QtDebugMsg);
|
2021-08-13 07:44:42 +00:00
|
|
|
m_output.write(issueLocationWithContext.afterText().toString() + u'\n');
|
2021-07-01 11:55:11 +00:00
|
|
|
|
|
|
|
int tabCount = issueLocationWithContext.beforeText().count(u'\t');
|
|
|
|
m_output.write(u" "_qs.repeated(
|
|
|
|
issueLocationWithContext.beforeText().length() - tabCount)
|
|
|
|
+ u"\t"_qs.repeated(tabCount)
|
|
|
|
+ u"^"_qs.repeated(fixItem.replacementString.length())
|
|
|
|
+ u'\n');
|
|
|
|
}
|
|
|
|
}
|