aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2022-05-30 14:52:03 +0200
committerMaximilian Goldstein <max.goldstein@qt.io>2022-06-30 11:23:36 +0200
commita9038a6cc6ba79feefa38213b89d9b5ce73cb12d (patch)
tree280ccc9682fc37d6914cf58130b4f728dc5fb236
parent10fa5f6bfe07c26e33e9284bdec753fde0436fc2 (diff)
QQmlJSLogger: Switch to an ID based system
This change makes qmljslogger use an ID based system for categorizing logging entries instead of using an enum. This allows plugins to register their own logging categories after the fact. It's also necessary for us to later show the warning ID when printing warnings and for creating documentation for each ID entry. Currently not every ID maps cleanly to only one type of warning, this has to be cleaned up in a follow-up change. Task-number: QTBUG-103453 Change-Id: I4cac6be7ca165b938e0ea032d077823bf17baf75 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
-rw-r--r--src/plugins/qmllint/quick/plugin.json30
-rw-r--r--src/plugins/qmllint/quick/quicklintplugin.cpp26
-rw-r--r--src/qmlcompiler/qqmljscompiler.cpp6
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp103
-rw-r--r--src/qmlcompiler/qqmljslinter.cpp88
-rw-r--r--src/qmlcompiler/qqmljslinter_p.h13
-rw-r--r--src/qmlcompiler/qqmljsliteralbindingcheck.cpp10
-rw-r--r--src/qmlcompiler/qqmljslogger.cpp209
-rw-r--r--src/qmlcompiler/qqmljslogger_p.h171
-rw-r--r--src/qmlcompiler/qqmljstypepropagator.cpp39
-rw-r--r--src/qmlcompiler/qqmljstyperesolver.cpp12
-rw-r--r--src/qmlcompiler/qqmlsa.cpp18
-rw-r--r--src/qmlcompiler/qqmlsa_p.h3
-rw-r--r--tests/auto/qml/qmllint/lintplugin.cpp17
-rw-r--r--tests/auto/qml/qmllint/testPlugin.json10
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp49
-rw-r--r--tests/auto/quickcontrols2/sanity/tst_sanity.cpp22
-rw-r--r--tools/qmlcachegen/qmlcachegen.cpp8
-rw-r--r--tools/qmllint/main.cpp80
-rw-r--r--tools/qmlls/qmllintsuggestions.cpp4
-rw-r--r--tools/qmltc/main.cpp19
-rw-r--r--tools/qmltc/qmltccompiler.h8
-rw-r--r--tools/qmltc/qmltcvisitor.cpp10
23 files changed, 576 insertions, 379 deletions
diff --git a/src/plugins/qmllint/quick/plugin.json b/src/plugins/qmllint/quick/plugin.json
index 2e8bf8219c..442a693b7b 100644
--- a/src/plugins/qmllint/quick/plugin.json
+++ b/src/plugins/qmllint/quick/plugin.json
@@ -2,5 +2,33 @@
"name": "Quick",
"author": "Qt",
"description": "Warns about QtQuick best practices",
- "version": "1.0"
+ "version": "1.0",
+ "isInternal": true,
+ "loggingCategories": [
+ {
+ "name": "layout-positioning",
+ "settingsName": "LayoutsPositioning",
+ "description": "Warn about using the wrong kind of positioning in layouts"
+ },
+ {
+ "name": "attached-property-type",
+ "settingsName": "AttachedPropertyType",
+ "description": "Warn about attached properties being used in the wrong type"
+ },
+ {
+ "name": "anchor-combinations",
+ "settingsName": "Anchors",
+ "description": "Warn about invalid anchor combinations"
+ },
+ {
+ "name": "controls-native-customize",
+ "settingsName": "ControlsNativeCustomize",
+ "description": "Warn about unsupported customizing of native controls"
+ },
+ {
+ "name": "unexpected-var-type",
+ "settingsName": "UnexpectedVarType",
+ "description": "Warn about incompatible types being set on var properties"
+ }
+ ]
}
diff --git a/src/plugins/qmllint/quick/quicklintplugin.cpp b/src/plugins/qmllint/quick/quicklintplugin.cpp
index 253249cf8b..49db324b28 100644
--- a/src/plugins/qmllint/quick/quicklintplugin.cpp
+++ b/src/plugins/qmllint/quick/quicklintplugin.cpp
@@ -3,10 +3,18 @@
#include "quicklintplugin.h"
+#include <QtQmlCompiler/private/qqmljslogger_p.h>
+
QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
+static constexpr LoggerWarningId quickLayoutPositioning { "Quick.layout-positioning" };
+static constexpr LoggerWarningId quickAttachedPropertyType { "Quick.attached-property-type" };
+static constexpr LoggerWarningId quickControlsNativeCustomize { "Quick.controls-native-customize" };
+static constexpr LoggerWarningId quickAnchorCombinations { "Quick.anchor-combinations" };
+static constexpr LoggerWarningId quickUnexpectedVarType { "Quick.unexpected-var-type" };
+
ForbiddenChildrenPropertyValidatorPass::ForbiddenChildrenPropertyValidatorPass(
QQmlSA::PassManager *manager)
: QQmlSA::ElementPass(manager)
@@ -49,7 +57,7 @@ void ForbiddenChildrenPropertyValidatorPass::run(const QQmlSA::Element &element)
auto bindings = element->ownPropertyBindings(warning.propertyName);
- emitWarning(warning.message, bindings.first->sourceLocation());
+ emitWarning(warning.message, quickLayoutPositioning, bindings.first->sourceLocation());
}
break;
}
@@ -114,7 +122,7 @@ void AttachedPropertyTypeValidatorPass::checkWarnings(const QQmlSA::Element &ele
}
}
- emitWarning(warning->message, location);
+ emitWarning(warning->message, quickAttachedPropertyType, location);
}
void AttachedPropertyTypeValidatorPass::onBinding(const QQmlSA::Element &element,
@@ -231,7 +239,7 @@ void ControlsNativeValidatorPass::run(const QQmlSA::Element &element)
"qtquickcontrols2-customize.html#customization-"
"reference for more information.")
.arg(propertyName),
- element->sourceLocation());
+ quickControlsNativeCustomize, element->sourceLocation());
}
}
// Since all the different types we have rules for don't inherit from each other (except
@@ -312,7 +320,7 @@ void AnchorsValidatorPass::run(const QQmlSA::Element &element)
if (warnLoc.isValid()) {
emitWarning(
"Cannot specify left, right, and horizontalCenter anchors at the same time.",
- warnLoc);
+ quickAnchorCombinations, warnLoc);
}
}
@@ -321,7 +329,7 @@ void AnchorsValidatorPass::run(const QQmlSA::Element &element)
ownSourceLocation({ u"top"_s, u"bottom"_s, u"verticalCenter"_s });
if (warnLoc.isValid()) {
emitWarning("Cannot specify top, bottom, and verticalCenter anchors at the same time.",
- warnLoc);
+ quickAnchorCombinations, warnLoc);
}
}
@@ -332,7 +340,7 @@ void AnchorsValidatorPass::run(const QQmlSA::Element &element)
if (warnLoc.isValid()) {
emitWarning("Baseline anchor cannot be used in conjunction with top, bottom, or "
"verticalCenter anchors.",
- warnLoc);
+ quickAnchorCombinations, warnLoc);
}
}
}
@@ -375,7 +383,7 @@ void ControlsSwipeDelegateValidatorPass::run(const QQmlSA::Element &element)
emitWarning(
u"SwipeDelegate: Cannot use horizontal anchors with %1; unable to layout the item."_s
.arg(property),
- location);
+ quickAnchorCombinations, location);
break;
}
}
@@ -406,7 +414,7 @@ void ControlsSwipeDelegateValidatorPass::run(const QQmlSA::Element &element)
if (group->hasPropertyBindings(u"behind"_s)
&& (group->hasPropertyBindings(u"right"_s) || group->hasPropertyBindings(u"left"_s))) {
emitWarning("SwipeDelegate: Cannot set both behind and left/right properties",
- ownBindingIterator->first->sourceLocation());
+ quickAnchorCombinations, ownBindingIterator->first->sourceLocation());
}
}
@@ -484,7 +492,7 @@ void VarBindingTypeValidatorPass::onBinding(const QQmlSA::Element &element,
emitWarning(u"Unexpected type for property \"%1\" expected %2 got %3"_s.arg(
propertyName, expectedTypeNames.join(u", "_s), bindingTypeName),
- binding.sourceLocation());
+ quickUnexpectedVarType, binding.sourceLocation());
}
}
diff --git a/src/qmlcompiler/qqmljscompiler.cpp b/src/qmlcompiler/qqmljscompiler.cpp
index 227966bed2..af60aa8dbb 100644
--- a/src/qmlcompiler/qqmljscompiler.cpp
+++ b/src/qmlcompiler/qqmljscompiler.cpp
@@ -649,8 +649,8 @@ QQmlJS::DiagnosticMessage QQmlJSAotCompiler::diagnose(
{
if (isStrict(m_document)
&& (type == QtWarningMsg || type == QtCriticalMsg || type == QtFatalMsg)
- && !m_logger->isCategoryIgnored(Log_Compiler)
- && m_logger->categoryLevel(Log_Compiler) == QtCriticalMsg) {
+ && !m_logger->isCategoryIgnored(qmlCompiler)
+ && m_logger->categoryLevel(qmlCompiler) == QtCriticalMsg) {
qFatal("%s:%d: (strict mode) %s",
qPrintable(QFileInfo(m_resourcePath).fileName()),
location.startLine, qPrintable(message));
@@ -658,7 +658,7 @@ QQmlJS::DiagnosticMessage QQmlJSAotCompiler::diagnose(
// TODO: this is a special place that explicitly sets the severity through
// logger's private function
- m_logger->log(message, Log_Compiler, location, type);
+ m_logger->log(message, qmlCompiler, location, type);
return QQmlJS::DiagnosticMessage {
message,
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 89a69c4400..9b2ad45086 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -171,7 +171,7 @@ bool QQmlJSImportVisitor::isTypeResolved(const QQmlJSScope::ConstPtr &type)
const auto handleUnresolvedType = [this](const QQmlJSScope::ConstPtr &type) {
m_logger->log(QStringLiteral("Type %1 is used but it is not resolved")
.arg(getScopeName(type, type->scopeType())),
- Log_Type, type->sourceLocation());
+ qmlType, type->sourceLocation());
};
return isTypeResolved(type, handleUnresolvedType);
}
@@ -238,11 +238,11 @@ void QQmlJSImportVisitor::resolveAliasesAndIds()
if (foundProperty) {
m_logger->log(QStringLiteral("Cannot deduce type of alias \"%1\"")
.arg(property.propertyName()),
- Log_Alias, object->sourceLocation());
+ qmlAlias, object->sourceLocation());
} else {
m_logger->log(QStringLiteral("Cannot resolve alias \"%1\"")
.arg(property.propertyName()),
- Log_Alias, object->sourceLocation());
+ qmlAlias, object->sourceLocation());
}
} else {
property.setType(type);
@@ -297,7 +297,7 @@ void QQmlJSImportVisitor::resolveAliasesAndIds()
continue;
m_logger->log(QStringLiteral("Alias \"%1\" is part of an alias cycle")
.arg(property.propertyName()),
- Log_Alias, object->sourceLocation());
+ qmlAlias, object->sourceLocation());
}
}
}
@@ -326,9 +326,9 @@ void QQmlJSImportVisitor::processImportWarnings(
if (warnings.isEmpty())
return;
- m_logger->log(QStringLiteral("Warnings occurred while importing %1:").arg(what), Log_Import,
+ m_logger->log(QStringLiteral("Warnings occurred while importing %1:").arg(what), qmlImport,
srcLocation);
- m_logger->processMessages(warnings, Log_Import);
+ m_logger->processMessages(warnings, qmlImport);
}
void QQmlJSImportVisitor::importBaseModules()
@@ -427,7 +427,7 @@ void QQmlJSImportVisitor::endVisit(UiProgram *)
.arg(m_logger->fileName())
.arg(import.startLine)
.arg(import.startColumn),
- Log_UnusedImport, import);
+ qmlUnusedImports, import);
}
populateRuntimeFunctionIndicesForDocument();
@@ -490,7 +490,7 @@ void QQmlJSImportVisitor::setAllBindings()
if (!type->isInCustomParserParent()) { // special otherwise
m_logger->log(QStringLiteral("'%1' is used but it is not resolved")
.arg(getScopeName(type, type->scopeType())),
- Log_Type, type->sourceLocation());
+ qmlType, type->sourceLocation());
}
continue;
}
@@ -539,7 +539,7 @@ void QQmlJSImportVisitor::processDefaultProperties()
if (!isComponent) {
m_logger->log(QStringLiteral("Cannot assign to non-existent default property"),
- Log_Property, it.value().constFirst()->sourceLocation());
+ qmlProperty, it.value().constFirst()->sourceLocation());
}
continue;
@@ -550,7 +550,7 @@ void QQmlJSImportVisitor::processDefaultProperties()
if (it.value().length() > 1 && !defaultProp.isList()) {
m_logger->log(
QStringLiteral("Cannot assign multiple objects to a default non-list property"),
- Log_Property, it.value().constFirst()->sourceLocation());
+ qmlProperty, it.value().constFirst()->sourceLocation());
}
auto propType = defaultProp.type();
@@ -560,7 +560,7 @@ void QQmlJSImportVisitor::processDefaultProperties()
"missing an import.")
.arg(defaultPropertyName)
.arg(defaultProp.typeName()),
- Log_Property, it.value().constFirst()->sourceLocation());
+ qmlProperty, it.value().constFirst()->sourceLocation());
};
if (propType.isNull()) {
handleUnresolvedDefaultProperty(propType);
@@ -583,7 +583,7 @@ void QQmlJSImportVisitor::processDefaultProperties()
}
m_logger->log(QStringLiteral("Cannot assign to default property of incompatible type"),
- Log_Property, scope->sourceLocation());
+ qmlProperty, scope->sourceLocation());
}
}
}
@@ -601,7 +601,7 @@ void QQmlJSImportVisitor::processPropertyTypes()
} else {
m_logger->log(property.typeName()
+ QStringLiteral(" was not found. Did you add all import paths?"),
- Log_Import, type.location);
+ qmlImport, type.location);
}
}
}
@@ -652,7 +652,7 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
if (!property.isValid()) {
m_logger->log(QStringLiteral("Property \"%1\" is invalid or does not exist")
.arg(propertyName),
- Log_Property, objectBinding.location);
+ qmlProperty, objectBinding.location);
continue;
}
const auto handleUnresolvedProperty = [&](const QQmlJSScope::ConstPtr &) {
@@ -661,7 +661,7 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
"missing an import.")
.arg(propertyName)
.arg(property.typeName()),
- Log_Property, objectBinding.location);
+ qmlProperty, objectBinding.location);
};
if (property.type().isNull()) {
handleUnresolvedProperty(property.type());
@@ -681,7 +681,7 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
.arg(propertyName)
.arg(property.typeName())
.arg(getScopeName(childScope, QQmlJSScope::QMLScope)),
- Log_Property, objectBinding.location);
+ qmlProperty, objectBinding.location);
continue;
}
@@ -697,7 +697,7 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
if (foundInterceptors.contains(uniqueBindingId)) {
m_logger->log(QStringLiteral("Duplicate interceptor on property \"%1\"")
.arg(propertyName),
- Log_Property, objectBinding.location);
+ qmlProperty, objectBinding.location);
} else {
foundInterceptors.insert(uniqueBindingId);
}
@@ -705,13 +705,13 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
if (foundValueSources.contains(uniqueBindingId)) {
m_logger->log(QStringLiteral("Duplicate value source on property \"%1\"")
.arg(propertyName),
- Log_Property, objectBinding.location);
+ qmlProperty, objectBinding.location);
} else if (foundObjects.contains(uniqueBindingId)
|| foundLiterals.contains(uniqueBindingId)) {
m_logger->log(QStringLiteral("Cannot combine value source and binding on "
"property \"%1\"")
.arg(propertyName),
- Log_Property, objectBinding.location);
+ qmlProperty, objectBinding.location);
} else {
foundValueSources.insert(uniqueBindingId);
}
@@ -719,7 +719,7 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
m_logger->log(QStringLiteral("On-binding for property \"%1\" has wrong type \"%2\"")
.arg(propertyName)
.arg(typeName),
- Log_Property, objectBinding.location);
+ qmlProperty, objectBinding.location);
}
} else {
// TODO: Warn here if binding.hasValue() is true
@@ -727,7 +727,7 @@ void QQmlJSImportVisitor::processPropertyBindingObjects()
m_logger->log(
QStringLiteral("Cannot combine value source and binding on property \"%1\"")
.arg(propertyName),
- Log_Property, objectBinding.location);
+ qmlProperty, objectBinding.location);
} else {
foundObjects.insert(uniqueBindingId);
}
@@ -742,7 +742,7 @@ void QQmlJSImportVisitor::checkRequiredProperties()
m_logger->log(
QStringLiteral("Property \"%1\" was marked as required but does not exist.")
.arg(required.name),
- Log_Required, required.location);
+ qmlRequired, required.location);
}
}
@@ -830,7 +830,7 @@ void QQmlJSImportVisitor::checkRequiredProperties()
}
}
- m_logger->log(message, Log_Required, defScope->sourceLocation(), true,
+ m_logger->log(message, qmlRequired, defScope->sourceLocation(), true,
true, suggestion);
}
}
@@ -869,7 +869,7 @@ void QQmlJSImportVisitor::processPropertyBindings()
m_logger->log(QStringLiteral("Binding assigned to \"%1\", but no property \"%1\" "
"exists in the current element.")
.arg(name),
- Log_Type, location, true, true, fixSuggestion);
+ qmlType, location, true, true, fixSuggestion);
continue;
}
@@ -879,7 +879,7 @@ void QQmlJSImportVisitor::processPropertyBindings()
"to a missing import statement or incomplete "
"qmltypes files.")
.arg(name),
- Log_Type, location);
+ qmlType, location);
}
const auto &annotations = property.annotations();
@@ -897,7 +897,7 @@ void QQmlJSImportVisitor::processPropertyBindings()
if (!deprecation.reason.isEmpty())
message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
- m_logger->log(message, Log_Deprecation, location);
+ m_logger->log(message, qmlDeprecated, location);
}
}
}
@@ -964,7 +964,7 @@ void QQmlJSImportVisitor::checkSignals()
m_logger->log(QStringLiteral("no matching signal found for handler \"%1\"")
.arg(pair.first),
- Log_UnqualifiedAccess, location, true, true, fix);
+ qmlUnqualified, location, true, true, fix);
continue;
}
@@ -975,7 +975,7 @@ void QQmlJSImportVisitor::checkSignals()
m_logger->log(QStringLiteral("Signal handler for \"%2\" has more formal"
" parameters than the signal it handles.")
.arg(pair.first),
- Log_Signal, location);
+ qmlSignal, location);
continue;
}
@@ -991,7 +991,7 @@ void QQmlJSImportVisitor::checkSignals()
.arg(i + 1)
.arg(pair.first, handlerParameter)
.arg(j + 1),
- Log_Signal, location);
+ qmlSignal, location);
}
}
}
@@ -1051,7 +1051,7 @@ void QQmlJSImportVisitor::breakInheritanceCycles(const QQmlJSScope::Ptr &origina
const QString message = QStringLiteral("%1 is part of an inheritance cycle: %2")
.arg(scope->internalName(), inheritenceCycle);
- m_logger->log(message, Log_InheritanceCycle, scope->sourceLocation());
+ m_logger->log(message, qmlInheritanceCycle, scope->sourceLocation());
originalScope->clearBaseType();
originalScope->setBaseTypeError(message);
break;
@@ -1064,11 +1064,11 @@ void QQmlJSImportVisitor::breakInheritanceCycles(const QQmlJSScope::Ptr &origina
const QString error = scope->baseTypeError();
const QString name = scope->baseTypeName();
if (!error.isEmpty()) {
- m_logger->log(error, Log_Import, scope->sourceLocation(), true, true);
+ m_logger->log(error, qmlImport, scope->sourceLocation(), true, true);
} else if (!name.isEmpty()) {
m_logger->log(
name + QStringLiteral(" was not found. Did you add all import paths?"),
- Log_Import, scope->sourceLocation(), true, true,
+ qmlImport, scope->sourceLocation(), true, true,
QQmlJSUtils::didYouMean(scope->baseTypeName(), m_rootScopeImports.keys(),
scope->sourceLocation()));
}
@@ -1091,7 +1091,7 @@ void QQmlJSImportVisitor::checkDeprecation(const QQmlJSScope::ConstPtr &original
if (!deprecation.reason.isEmpty())
message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
- m_logger->log(message, Log_Deprecation, originalScope->sourceLocation());
+ m_logger->log(message, qmlDeprecated, originalScope->sourceLocation());
}
}
}
@@ -1117,7 +1117,7 @@ void QQmlJSImportVisitor::checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr sc
? QStringLiteral("grouped")
: QStringLiteral("attached"),
childScope->internalName()),
- Log_UnqualifiedAccess, childScope->sourceLocation());
+ qmlUnqualified, childScope->sourceLocation());
}
children.append(childScope->childScopes());
default:
@@ -1299,7 +1299,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::StringLiteral *sl)
QString(), false } } };
m_logger->log(QStringLiteral("String contains unescaped line terminator which is "
"deprecated."),
- Log_MultilineString, sl->literalToken, true, true, suggestion);
+ qmlMultilineStrings, sl->literalToken, true, true, suggestion);
}
return true;
@@ -1359,7 +1359,7 @@ void QQmlJSImportVisitor::endVisit(UiObjectDefinition *)
bool QQmlJSImportVisitor::visit(UiInlineComponent *component)
{
if (!m_inlineComponentName.isNull()) {
- m_logger->log(u"Nested inline components are not supported"_s, Log_Syntax,
+ m_logger->log(u"Nested inline components are not supported"_s, qmlSyntax,
component->firstSourceLocation());
return true;
}
@@ -1410,7 +1410,7 @@ bool QQmlJSImportVisitor::visit(UiPublicMember *publicMember)
} else {
m_logger->log(QStringLiteral("Invalid alias expression. Only IDs and field "
"member expressions can be aliased."),
- Log_Alias, expression->firstSourceLocation());
+ qmlAlias, expression->firstSourceLocation());
}
} else {
const QString name = buildName(publicMember->memberType);
@@ -1582,7 +1582,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiSourceElement *srcElement)
bool QQmlJSImportVisitor::visit(QQmlJS::AST::FunctionDeclaration *fdecl)
{
- m_logger->log(u"Declared function \"%1\""_s.arg(fdecl->name), Log_ControlsSanity,
+ m_logger->log(u"Declared function \"%1\""_s.arg(fdecl->name), qmlControlsSanity,
fdecl->firstSourceLocation());
visitFunctionExpressionHelper(fdecl);
return true;
@@ -1750,11 +1750,11 @@ void QQmlJSImportVisitor::handleIdDeclaration(QQmlJS::AST::UiScriptBinding *scri
if (const auto *idExpression = cast<IdentifierExpression *>(statement->expression))
return idExpression->name.toString();
else if (const auto *idString = cast<StringLiteral *>(statement->expression)) {
- m_logger->log(u"ids do not need quotation marks"_s, Log_SyntaxIdQuotation,
+ m_logger->log(u"ids do not need quotation marks"_s, qmlSyntaxIdQuotation,
idString->firstSourceLocation());
return idString->value.toString();
}
- m_logger->log(u"Failed to parse id"_s, Log_Syntax,
+ m_logger->log(u"Failed to parse id"_s, qmlSyntax,
statement->expression->firstSourceLocation());
return QString();
@@ -1770,7 +1770,7 @@ void QQmlJSImportVisitor::handleIdDeclaration(QQmlJS::AST::UiScriptBinding *scri
m_logger->log(u"Found a duplicated id. id %1 was first declared at %2:%3"_s.arg(
name, QString::number(otherLocation.startLine),
QString::number(otherLocation.startColumn)),
- Log_Syntax, // ??
+ qmlSyntaxDuplicateIds, // ??
scriptBinding->firstSourceLocation());
}
}
@@ -1858,7 +1858,7 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
auto name = group->name;
if (id && id->name.toString() == u"anchors")
- m_logger->log(u"Using anchors here"_s, Log_ControlsSanity,
+ m_logger->log(u"Using anchors here"_s, qmlControlsSanity,
scriptBinding->firstSourceLocation());
const auto signal = QQmlJSUtils::signalName(name);
@@ -1880,7 +1880,7 @@ bool QQmlJSImportVisitor::visit(UiScriptBinding *scriptBinding)
}
}
- m_logger->log(u"Declared signal handler \"%1\""_s.arg(name), Log_ControlsSanity,
+ m_logger->log(u"Declared signal handler \"%1\""_s.arg(name), qmlControlsSanity,
scriptBinding->firstSourceLocation());
m_signals[m_currentScope].append({ m_savedBindingOuterScope, group->firstSourceLocation(),
@@ -2101,10 +2101,10 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiPragma *pragma)
// If a file uses pragma Strict, it expects to be compiled, so automatically
// enable compiler warnings unless the level is set explicitly already (e.g.
// by the user).
- if (pragma->name == u"Strict"_s && !m_logger->wasCategoryChanged(Log_Compiler)) {
+ if (pragma->name == u"Strict"_s && !m_logger->wasCategoryChanged(qmlCompiler)) {
// TODO: the logic here is rather complicated and may be buggy
- m_logger->setCategoryLevel(Log_Compiler, QtWarningMsg);
- m_logger->setCategoryIgnored(Log_Compiler, false);
+ m_logger->setCategoryLevel(qmlCompiler, QtWarningMsg);
+ m_logger->setCategoryIgnored(qmlCompiler, false);
}
if (pragma->name == u"Singleton")
@@ -2116,8 +2116,9 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiPragma *pragma)
} else if (pragma->value == u"Unbound") {
m_scopesById.setComponentsAreBound(false);
} else {
- m_logger->log(u"Unkonwn argument \"%s\" to pragma ComponentBehavior"_s
- .arg(pragma->value), Log_Syntax, pragma->firstSourceLocation());
+ m_logger->log(
+ u"Unkonwn argument \"%s\" to pragma ComponentBehavior"_s.arg(pragma->value),
+ qmlSyntax, pragma->firstSourceLocation());
}
}
@@ -2127,7 +2128,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiPragma *pragma)
void QQmlJSImportVisitor::throwRecursionDepthError()
{
m_logger->log(QStringLiteral("Maximum statement or expression depth exceeded"),
- Log_RecursionDepthError, QQmlJS::SourceLocation());
+ qmlRecursionDepthErrors, QQmlJS::SourceLocation());
}
bool QQmlJSImportVisitor::visit(QQmlJS::AST::ClassDeclaration *ast)
@@ -2219,7 +2220,7 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::WithStatement *ast)
m_logger->log(QStringLiteral("with statements are strongly discouraged in QML "
"and might cause false positives when analysing unqualified "
"identifiers"),
- Log_WithStatement, ast->firstSourceLocation());
+ qmlWith, ast->firstSourceLocation());
return true;
}
@@ -2363,7 +2364,7 @@ void QQmlJSImportVisitor::endVisit(QQmlJS::AST::UiObjectBinding *uiob)
m_logger->log(
u"Cannot defer property assignment to \"%1\". Assigning an id to an object or one of its sub-objects bound to a deferred property will make the assignment immediate."_s
.arg(propertyName),
- Log_DeferredPropertyId, uiob->firstSourceLocation());
+ qmlDeferredPropertyId, uiob->firstSourceLocation());
}
}
diff --git a/src/qmlcompiler/qqmljslinter.cpp b/src/qmlcompiler/qqmljslinter.cpp
index 03eb481f5a..414ce1fc00 100644
--- a/src/qmlcompiler/qqmljslinter.cpp
+++ b/src/qmlcompiler/qqmljslinter.cpp
@@ -52,7 +52,7 @@ public:
.arg(name)
.arg(declarationLocation.startLine)
.arg(declarationLocation.startColumn),
- Log_Type, accessLocation);
+ qmlType, accessLocation);
}
private:
@@ -83,6 +83,8 @@ QQmlJSLinter::Plugin::Plugin(QQmlJSLinter::Plugin &&plugin) noexcept
m_loader = plugin.m_loader;
m_isValid = plugin.m_isValid;
m_isBuiltin = plugin.m_isBuiltin;
+ m_isInternal = plugin.m_isInternal;
+ m_categories = plugin.m_categories;
// Mark the old Plugin as invalid and make sure it doesn't delete the loader
plugin.m_loader = nullptr;
@@ -140,7 +142,8 @@ bool QQmlJSLinter::Plugin::parseMetaData(const QJsonObject &metaData, QString pl
QJsonObject pluginMetaData = metaData[u"MetaData"].toObject();
- for (const QString &requiredKey : { u"name"_s, u"version"_s, u"author"_s }) {
+ for (const QString &requiredKey :
+ { u"name"_s, u"version"_s, u"author"_s, u"loggingCategories"_s }) {
if (!pluginMetaData.contains(requiredKey)) {
qWarning() << pluginName << "is missing the required " << requiredKey
<< "metadata, skipping";
@@ -152,6 +155,36 @@ bool QQmlJSLinter::Plugin::parseMetaData(const QJsonObject &metaData, QString pl
m_author = pluginMetaData[u"author"].toString();
m_version = pluginMetaData[u"version"].toString();
m_description = pluginMetaData[u"description"].toString(u"-/-"_s);
+ m_isInternal = pluginMetaData[u"isInternal"].toBool(false);
+
+ if (!pluginMetaData[u"loggingCategories"].isArray()) {
+ qWarning() << pluginName << "has loggingCategories which are not an array, skipping";
+ return false;
+ }
+
+ QJsonArray categories = pluginMetaData[u"loggingCategories"].toArray();
+
+ for (const QJsonValue &value : categories) {
+ if (!value.isObject()) {
+ qWarning() << pluginName << "has invalid loggingCategories entries, skipping";
+ return false;
+ }
+
+ QJsonObject object = value.toObject();
+
+ for (const QString &requiredKey : { u"name"_s, u"description"_s }) {
+ if (!object.contains(requiredKey)) {
+ qWarning() << pluginName << " logging category is missing the required "
+ << requiredKey << "metadata, skipping";
+ return false;
+ }
+ }
+
+ const QString categoryId =
+ (m_isInternal ? u""_s : u"Plugin."_s) + m_name + u'.' + object[u"name"].toString();
+ m_categories << QQmlJSLogger::Category { categoryId, categoryId,
+ object[u"description"].toString(), QtWarningMsg };
+ }
return true;
}
@@ -211,9 +244,9 @@ std::vector<QQmlJSLinter::Plugin> QQmlJSLinter::loadPlugins(QStringList paths)
void QQmlJSLinter::parseComments(QQmlJSLogger *logger,
const QList<QQmlJS::SourceLocation> &comments)
{
- QHash<int, QSet<QQmlJSLoggerCategory>> disablesPerLine;
- QHash<int, QSet<QQmlJSLoggerCategory>> enablesPerLine;
- QHash<int, QSet<QQmlJSLoggerCategory>> oneLineDisablesPerLine;
+ QHash<int, QSet<QString>> disablesPerLine;
+ QHash<int, QSet<QString>> enablesPerLine;
+ QHash<int, QSet<QString>> oneLineDisablesPerLine;
const QString code = logger->code();
const QStringList lines = code.split(u'\n');
@@ -229,20 +262,24 @@ void QQmlJSLinter::parseComments(QQmlJSLogger *logger,
const QString command = words.at(1);
- QSet<QQmlJSLoggerCategory> categories;
+ QSet<QString> categories;
for (qsizetype i = 2; i < words.size(); i++) {
const QString category = words.at(i);
- const auto option = logger->options().constFind(category);
- if (option != logger->options().constEnd())
- categories << option->m_category;
+ const auto loggerCategories = logger->categories();
+ const auto categoryExists = std::any_of(
+ loggerCategories.cbegin(), loggerCategories.cend(),
+ [&](const QQmlJSLogger::Category &cat) { return cat.id().name() == category; });
+
+ if (categoryExists)
+ categories << category;
else
logger->log(u"qmllint directive on unknown category \"%1\""_s.arg(category),
- Log_Syntax, loc);
+ qmlSyntax, loc);
}
if (categories.isEmpty()) {
- for (const auto &option : logger->options())
- categories << option.m_category;
+ for (const auto &option : logger->categories())
+ categories << option.id().name().toString();
}
if (command == u"disable"_s) {
@@ -264,7 +301,7 @@ void QQmlJSLinter::parseComments(QQmlJSLogger *logger,
} else if (command == u"enable"_s) {
enablesPerLine[loc.startLine + 1] |= categories;
} else {
- logger->log(u"Invalid qmllint directive \"%1\" provided"_s.arg(command), Log_Syntax,
+ logger->log(u"Invalid qmllint directive \"%1\" provided"_s.arg(command), qmlSyntax,
loc);
}
}
@@ -272,7 +309,7 @@ void QQmlJSLinter::parseComments(QQmlJSLogger *logger,
if (disablesPerLine.isEmpty() && oneLineDisablesPerLine.isEmpty())
return;
- QSet<QQmlJSLoggerCategory> currentlyDisabled;
+ QSet<QString> currentlyDisabled;
for (qsizetype i = 1; i <= lines.length(); i++) {
currentlyDisabled.unite(disablesPerLine[i]).subtract(enablesPerLine[i]);
@@ -290,7 +327,7 @@ QQmlJSLinter::LintResult QQmlJSLinter::lintFile(const QString &filename,
QJsonArray *json, const QStringList &qmlImportPaths,
const QStringList &qmldirFiles,
const QStringList &resourceFiles,
- const QMap<QString, QQmlJSLogger::Option> &options)
+ const QList<QQmlJSLogger::Category> &categories)
{
// Make sure that we don't expose an old logger if we return before a new one is created.
m_logger.reset();
@@ -452,16 +489,23 @@ QQmlJSLinter::LintResult QQmlJSLinter::lintFile(const QString &filename,
m_logger->fileName(), m_importer.resourceFileMapper()),
qmldirFiles };
- parseComments(m_logger.get(), engine.comments());
+ if (m_enablePlugins) {
+ for (const Plugin &plugin : m_plugins) {
+ for (const QQmlJSLogger::Category &category : plugin.categories())
+ m_logger->registerCategory(category);
+ }
+ }
- for (auto it = options.cbegin(); it != options.cend(); ++it) {
- if (!it.value().m_changed)
+ for (auto it = categories.cbegin(); it != categories.cend(); ++it) {
+ if (!it->changed)
continue;
- m_logger->setCategoryIgnored(it.value().m_category, it.value().m_ignored);
- m_logger->setCategoryLevel(it.value().m_category, it.value().m_level);
+ m_logger->setCategoryIgnored(it->id(), it->ignored);
+ m_logger->setCategoryLevel(it->id(), it->level);
}
+ parseComments(m_logger.get(), engine.comments());
+
QQmlJSTypeResolver typeResolver(&m_importer);
// Type resolving is using document parent mode here so that it produces fewer false
@@ -533,8 +577,8 @@ QQmlJSLinter::LintResult QQmlJSLinter::lintFile(const QString &filename,
if (!warnings.isEmpty()) {
m_logger->log(QStringLiteral("Type warnings occurred while evaluating file:"),
- Log_Import, QQmlJS::SourceLocation());
- m_logger->processMessages(warnings, Log_Import);
+ qmlImport, QQmlJS::SourceLocation());
+ m_logger->processMessages(warnings, qmlImport);
}
success &= !m_logger->hasWarnings() && !m_logger->hasErrors();
diff --git a/src/qmlcompiler/qqmljslinter_p.h b/src/qmlcompiler/qqmljslinter_p.h
index 7cc023b8ef..4cd068f968 100644
--- a/src/qmlcompiler/qqmljslinter_p.h
+++ b/src/qmlcompiler/qqmljslinter_p.h
@@ -65,8 +65,16 @@ public:
const QString &description() const { return m_description; }
const QString &version() const { return m_version; }
const QString &author() const { return m_author; }
+ const QList<QQmlJSLogger::Category> categories() const
+ {
+ return m_categories;
+ }
bool isBuiltin() const { return m_isBuiltin; }
bool isValid() const { return m_isValid; }
+ bool isInternal() const
+ {
+ return m_isInternal;
+ }
bool isEnabled() const
{
@@ -87,9 +95,12 @@ public:
QString m_version;
QString m_author;
+ QList<QQmlJSLogger::Category> m_categories;
QQmlSA::LintPlugin *m_instance;
QPluginLoader *m_loader = nullptr;
bool m_isBuiltin;
+ bool m_isInternal =
+ false; // Internal plugins are those developed and maintained inside the Qt project
bool m_isValid = false;
bool m_isEnabled = true;
};
@@ -100,7 +111,7 @@ public:
LintResult lintFile(const QString &filename, const QString *fileContents, const bool silent,
QJsonArray *json, const QStringList &qmlImportPaths,
const QStringList &qmldirFiles, const QStringList &resourceFiles,
- const QMap<QString, QQmlJSLogger::Option> &options);
+ const QList<QQmlJSLogger::Category> &categories);
FixResult applyFixes(QString *fixedCode, bool silent);
diff --git a/src/qmlcompiler/qqmljsliteralbindingcheck.cpp b/src/qmlcompiler/qqmljsliteralbindingcheck.cpp
index d56333414f..1be1805f6d 100644
--- a/src/qmlcompiler/qqmljsliteralbindingcheck.cpp
+++ b/src/qmlcompiler/qqmljsliteralbindingcheck.cpp
@@ -29,8 +29,8 @@ void QQmlJSLiteralBindingCheck::run(QQmlJSImportVisitor *visitor, QQmlJSTypeReso
// If the property is defined in the same scope where it is set,
// we are in fact allowed to set it, even if it's not writable.
if (!property.isWritable() && !scope->hasOwnProperty(propertyName)) {
- logger->log(u"Cannot assign to read-only property %1"_s.arg(propertyName),
- Log_Type, binding.sourceLocation());
+ logger->log(u"Cannot assign to read-only property %1"_s.arg(propertyName), qmlType,
+ binding.sourceLocation());
continue;
}
@@ -38,14 +38,14 @@ void QQmlJSLiteralBindingCheck::run(QQmlJSImportVisitor *visitor, QQmlJSTypeReso
logger->log(u"Cannot assign binding of type %1 to %2"_s.arg(
QQmlJSScope::prettyName(binding.literalTypeName()),
QQmlJSScope::prettyName(property.typeName())),
- Log_Type, binding.sourceLocation());
+ qmlType, binding.sourceLocation());
continue;
}
if (resolver->equals(property.type(), resolver->stringType())
&& resolver->isNumeric(binding.literalType(resolver))) {
- logger->log(u"Cannot assign a numeric constant to a string property"_s,
- Log_Type, binding.sourceLocation());
+ logger->log(u"Cannot assign a numeric constant to a string property"_s, qmlType,
+ binding.sourceLocation());
}
}
}
diff --git a/src/qmlcompiler/qqmljslogger.cpp b/src/qmlcompiler/qqmljslogger.cpp
index d8b1fe096f..f15b5cf31a 100644
--- a/src/qmlcompiler/qqmljslogger.cpp
+++ b/src/qmlcompiler/qqmljslogger.cpp
@@ -21,93 +21,127 @@ QT_BEGIN_NAMESPACE
using namespace Qt::StringLiterals;
-const QMap<QString, QQmlJSLogger::Option> &QQmlJSLogger::options() {
- static QMap<QString, QQmlJSLogger::Option> optionsMap = {
- { QStringLiteral("required"),
- QQmlJSLogger::Option(Log_Required, QStringLiteral("RequiredProperty"),
- QStringLiteral("Warn about required properties"), QtWarningMsg) },
- { QStringLiteral("alias"),
- QQmlJSLogger::Option(Log_Alias, QStringLiteral("PropertyAlias"),
- QStringLiteral("Warn about alias errors"), QtWarningMsg) },
- { QStringLiteral("import"),
- QQmlJSLogger::Option(Log_Import, QStringLiteral("ImportFailure"),
- QStringLiteral("Warn about failing imports and deprecated qmltypes"),
- QtWarningMsg) },
- { QStringLiteral("with"),
- QQmlJSLogger::Option(Log_WithStatement, QStringLiteral("WithStatement"),
- QStringLiteral("Warn about with statements as they can cause false "
- "positives when checking for unqualified access"),
- QtWarningMsg) },
- { QStringLiteral("inheritance-cycle"),
- QQmlJSLogger::Option(Log_InheritanceCycle, QStringLiteral("InheritanceCycle"),
- QStringLiteral("Warn about inheritance cycles"), QtWarningMsg) },
- { QStringLiteral("deprecated"),
- QQmlJSLogger::Option(Log_Deprecation, QStringLiteral("Deprecated"),
- QStringLiteral("Warn about deprecated properties and types"),
- QtWarningMsg) },
- { QStringLiteral("signal"),
- QQmlJSLogger::Option(Log_Signal, QStringLiteral("BadSignalHandler"),
- QStringLiteral("Warn about bad signal handler parameters"),
- QtWarningMsg) },
- { QStringLiteral("type"),
- QQmlJSLogger::Option(Log_Type, QStringLiteral("TypeError"),
- QStringLiteral("Warn about unresolvable types and type mismatches"),
- QtWarningMsg) },
- { QStringLiteral("property"),
- QQmlJSLogger::Option(Log_Property, QStringLiteral("UnknownProperty"),
- QStringLiteral("Warn about unknown properties"), QtWarningMsg) },
- { QStringLiteral("deferred-property-id"),
- QQmlJSLogger::Option(
- Log_DeferredPropertyId, QStringLiteral("DeferredPropertyId"),
- QStringLiteral(
- "Warn about making deferred properties immediate by giving them an id."),
- QtWarningMsg) },
- { QStringLiteral("unqualified"),
- QQmlJSLogger::Option(
- Log_UnqualifiedAccess, QStringLiteral("UnqualifiedAccess"),
- QStringLiteral("Warn about unqualified identifiers and how to fix them"),
- QtWarningMsg) },
- { QStringLiteral("unused-imports"),
- QQmlJSLogger::Option(Log_UnusedImport, QStringLiteral("UnusedImports"),
- QStringLiteral("Warn about unused imports"), QtInfoMsg) },
- { QStringLiteral("multiline-strings"),
- QQmlJSLogger::Option(Log_MultilineString, QStringLiteral("MultilineStrings"),
- QStringLiteral("Warn about multiline strings"), QtInfoMsg) },
- { QStringLiteral("compiler"),
- QQmlJSLogger::Option(Log_Compiler, QStringLiteral("CompilerWarnings"),
- QStringLiteral("Warn about compiler issues"), QtCriticalMsg, true) },
- { QStringLiteral("controls-sanity"),
- QQmlJSLogger::Option(
- Log_ControlsSanity, QStringLiteral("ControlsSanity"),
- QStringLiteral("Performance checks used for QuickControl's implementation"),
- QtCriticalMsg, true) },
- { QStringLiteral("multiple-attached-objects"),
- QQmlJSLogger::Option(
- Log_AttachedPropertyReuse, QStringLiteral("AttachedPropertyReuse"),
- QStringLiteral("Warn if attached types from parent components aren't reused"),
- QtCriticalMsg, true) },
- { QStringLiteral("plugin"),
- QQmlJSLogger::Option(Log_Plugin, QStringLiteral("LintPluginWarnings"),
- QStringLiteral("Warn if a qmllint plugin finds an issue"),
- QtWarningMsg) }
+const LoggerWarningId qmlRequired { "required" };
+const LoggerWarningId qmlAlias { "alias" };
+const LoggerWarningId qmlImport { "import" };
+const LoggerWarningId qmlRecursionDepthErrors { "recursion-depth-errors" };
+const LoggerWarningId qmlWith { "with" };
+const LoggerWarningId qmlInheritanceCycle { "inheritance-cycle" };
+const LoggerWarningId qmlDeprecated { "deprecated" };
+const LoggerWarningId qmlSignal { "signal" };
+const LoggerWarningId qmlType { "type" };
+const LoggerWarningId qmlProperty { "property" };
+const LoggerWarningId qmlDeferredPropertyId { "deferred-property-id" };
+const LoggerWarningId qmlUnqualified { "unqualified" };
+const LoggerWarningId qmlUnusedImports { "unused-imports" };
+const LoggerWarningId qmlMultilineStrings { "multiline-strings" };
+const LoggerWarningId qmlSyntax { "syntax" };
+const LoggerWarningId qmlSyntaxIdQuotation { "syntax.id-quotation" };
+const LoggerWarningId qmlSyntaxDuplicateIds { "syntax.duplicate-ids" };
+const LoggerWarningId qmlCompiler { "compiler" };
+const LoggerWarningId qmlControlsSanity { "controls-sanity" };
+const LoggerWarningId qmlAttachedPropertyReuse { "attached-property-reuse" };
+const LoggerWarningId qmlPlugin { "plugin" };
+
+const QList<QQmlJSLogger::Category> &QQmlJSLogger::defaultCategories()
+{
+ static const QList<QQmlJSLogger::Category> cats = {
+ QQmlJSLogger::Category { qmlRequired.name().toString(), QStringLiteral("RequiredProperty"),
+ QStringLiteral("Warn about required properties"), QtWarningMsg },
+ QQmlJSLogger::Category { qmlAlias.name().toString(), QStringLiteral("PropertyAlias"),
+ QStringLiteral("Warn about alias errors"), QtWarningMsg },
+ QQmlJSLogger::Category {
+ qmlImport.name().toString(), QStringLiteral("ImportFailure"),
+ QStringLiteral("Warn about failing imports and deprecated qmltypes"),
+ QtWarningMsg },
+ QQmlJSLogger::Category {
+ qmlRecursionDepthErrors.name().toString(), QStringLiteral("ImportFailure"),
+ QStringLiteral("Warn about failing imports and deprecated qmltypes"), QtWarningMsg,
+ false, true },
+ QQmlJSLogger::Category {
+ qmlWith.name().toString(), QStringLiteral("WithStatement"),
+ QStringLiteral("Warn about with statements as they can cause false "
+ "positives when checking for unqualified access"),
+ QtWarningMsg },
+ QQmlJSLogger::Category { qmlInheritanceCycle.name().toString(),
+ QStringLiteral("InheritanceCycle"),
+ QStringLiteral("Warn about inheritance cycles"), QtWarningMsg },
+ QQmlJSLogger::Category { qmlDeprecated.name().toString(), QStringLiteral("Deprecated"),
+ QStringLiteral("Warn about deprecated properties and types"),
+ QtWarningMsg },
+ QQmlJSLogger::Category { qmlSignal.name().toString(), QStringLiteral("BadSignalHandler"),
+ QStringLiteral("Warn about bad signal handler parameters"),
+ QtWarningMsg },
+ QQmlJSLogger::Category {
+ qmlType.name().toString(), QStringLiteral("TypeError"),
+ QStringLiteral("Warn about unresolvable types and type mismatches"), QtWarningMsg },
+ QQmlJSLogger::Category { qmlProperty.name().toString(), QStringLiteral("UnknownProperty"),
+ QStringLiteral("Warn about unknown properties"), QtWarningMsg },
+
+ QQmlJSLogger::Category {
+ qmlDeferredPropertyId.name().toString(), QStringLiteral("DeferredPropertyId"),
+ QStringLiteral(
+ "Warn about making deferred properties immediate by giving them an id."),
+ QtWarningMsg },
+ QQmlJSLogger::Category {
+ qmlUnqualified.name().toString(), QStringLiteral("UnqualifiedAccess"),
+ QStringLiteral("Warn about unqualified identifiers and how to fix them"),
+ QtWarningMsg },
+ QQmlJSLogger::Category { qmlUnusedImports.name().toString(),
+ QStringLiteral("UnusedImports"),
+ QStringLiteral("Warn about unused imports"), QtInfoMsg },
+ QQmlJSLogger::Category { qmlMultilineStrings.name().toString(),
+ QStringLiteral("MultilineStrings"),
+ QStringLiteral("Warn about multiline strings"), QtInfoMsg },
+ QQmlJSLogger::Category { qmlSyntax.name().toString(), QString(),
+ QStringLiteral("Syntax errors"), QtWarningMsg, false, true },
+ QQmlJSLogger::Category { qmlSyntaxIdQuotation.name().toString(), QString(),
+ QStringLiteral("ID quotation"), QtWarningMsg, false, true },
+ QQmlJSLogger::Category { qmlSyntaxDuplicateIds.name().toString(), QString(),
+ QStringLiteral("ID duplication"), QtCriticalMsg, false, true },
+ QQmlJSLogger::Category { qmlCompiler.name().toString(), QStringLiteral("CompilerWarnings"),
+ QStringLiteral("Warn about compiler issues"), QtWarningMsg, true },
+
+ QQmlJSLogger::Category {
+ qmlControlsSanity.name().toString(), QStringLiteral("ControlsSanity"),
+ QStringLiteral("Performance checks used for QuickControl's implementation"),
+ QtCriticalMsg, true },
+
+ QQmlJSLogger::Category {
+ qmlAttachedPropertyReuse.name().toString(), QStringLiteral("AttachedPropertyReuse"),
+ QStringLiteral("Warn if attached types from parent components aren't reused"),
+ QtCriticalMsg, true },
+ QQmlJSLogger::Category { qmlPlugin.name().toString(), QStringLiteral("LintPluginWarnings"),
+ QStringLiteral("Warn if a qmllint plugin finds an issue"),
+ QtWarningMsg }
};
- return optionsMap;
+ return cats;
}
-QQmlJSLogger::QQmlJSLogger()
+const QList<QQmlJSLogger::Category> QQmlJSLogger::categories() const
+{
+ return m_categories.values();
+}
+
+void QQmlJSLogger::registerCategory(const QQmlJSLogger::Category &category)
{
- const auto &opt = options();
- for (auto it = opt.cbegin(); it != opt.cend(); ++it) {
- m_categoryLevels[it.value().m_category] = it.value().m_level;
- m_categoryIgnored[it.value().m_category] = it.value().m_ignored;
+ if (m_categories.contains(category.name)) {
+ qWarning() << "Trying to re-register existing logger category" << category.name;
+ return;
}
- // These have to be set up manually since we don't expose it as an option
- m_categoryLevels[Log_RecursionDepthError] = QtCriticalMsg;
- m_categoryLevels[Log_Syntax] = QtWarningMsg; // TODO: because we usually report it as a warning!
- m_categoryLevels[Log_SyntaxIdQuotation] = QtWarningMsg;
- m_categoryLevels[Log_SyntaxDuplicateIds] = QtCriticalMsg;
+ m_categoryLevels[category.name] = category.level;
+ m_categoryIgnored[category.name] = category.ignored;
+ m_categories.insert(category.name, category);
+}
+
+QQmlJSLogger::QQmlJSLogger()
+{
+ static const QList<QQmlJSLogger::Category> cats = defaultCategories();
+
+ for (const QQmlJSLogger::Category &category : cats)
+ registerCategory(category);
// setup color output
m_output.insertMapping(QtCriticalMsg, QColorOutput::RedForeground);
@@ -126,17 +160,20 @@ static bool isMsgTypeLess(QtMsgType a, QtMsgType b)
return level[a] < level[b];
}
-void QQmlJSLogger::log(const QString &message, QQmlJSLoggerCategory category,
+void QQmlJSLogger::log(const QString &message, LoggerWarningId id,
const QQmlJS::SourceLocation &srcLocation, QtMsgType type, bool showContext,
bool showFileName, const std::optional<FixSuggestion> &suggestion,
const QString overrideFileName)
{
- if (isCategoryIgnored(category))
+ Q_ASSERT(m_categoryLevels.contains(id.name().toString()));
+
+ if (isCategoryIgnored(id))
return;
// Note: assume \a type is the type we should prefer for logging
- if (srcLocation.isValid() && m_ignoredWarnings[srcLocation.startLine].contains(category))
+ if (srcLocation.isValid()
+ && m_ignoredWarnings[srcLocation.startLine].contains(id.name().toString()))
return;
QString prefix;
@@ -180,9 +217,9 @@ void QQmlJSLogger::log(const QString &message, QQmlJSLoggerCategory category,
}
void QQmlJSLogger::processMessages(const QList<QQmlJS::DiagnosticMessage> &messages,
- QQmlJSLoggerCategory category)
+ LoggerWarningId id)
{
- if (messages.isEmpty() || isCategoryIgnored(category))
+ if (messages.isEmpty() || isCategoryIgnored(id))
return;
m_output.write(QStringLiteral("---\n"));
@@ -190,7 +227,7 @@ void QQmlJSLogger::processMessages(const QList<QQmlJS::DiagnosticMessage> &messa
// TODO: we should instead respect message's category here (potentially, it
// should hold a category instead of type)
for (const QQmlJS::DiagnosticMessage &message : messages)
- log(message.message, category, QQmlJS::SourceLocation(), false, false);
+ log(message.message, id, QQmlJS::SourceLocation(), false, false);
m_output.write(QStringLiteral("---\n\n"));
}
diff --git a/src/qmlcompiler/qqmljslogger_p.h b/src/qmlcompiler/qqmljslogger_p.h
index 0302201eaf..7f894d9f35 100644
--- a/src/qmlcompiler/qqmljslogger_p.h
+++ b/src/qmlcompiler/qqmljslogger_p.h
@@ -26,6 +26,7 @@
#include <QtCore/qstring.h>
#include <QtCore/qlist.h>
#include <QtCore/qset.h>
+#include <QtCore/QLoggingCategory>
#include <optional>
@@ -68,31 +69,6 @@ private:
QStringView m_afterText;
};
-enum QQmlJSLoggerCategory {
- Log_Required,
- Log_Alias,
- Log_Import,
- Log_RecursionDepthError,
- Log_WithStatement,
- Log_InheritanceCycle,
- Log_Deprecation,
- Log_Signal,
- Log_Type,
- Log_Property,
- Log_DeferredPropertyId,
- Log_UnqualifiedAccess,
- Log_UnusedImport,
- Log_MultilineString,
- Log_Syntax,
- Log_SyntaxIdQuotation,
- Log_SyntaxDuplicateIds,
- Log_Compiler,
- Log_ControlsSanity,
- Log_AttachedPropertyReuse,
- Log_Plugin,
- QQmlJSLoggerCategory_Last = Log_Plugin
-};
-
struct Q_QMLCOMPILER_PRIVATE_EXPORT FixSuggestion
{
struct Fix
@@ -108,6 +84,39 @@ struct Q_QMLCOMPILER_PRIVATE_EXPORT FixSuggestion
QList<Fix> fixes;
};
+class Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId
+{
+public:
+ constexpr LoggerWarningId(QAnyStringView name) : m_name(name) { }
+
+ const QAnyStringView name() const { return m_name; }
+
+private:
+ const QAnyStringView m_name;
+};
+
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlRequired;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlAlias;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlImport;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlRecursionDepthErrors;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlWith;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlInheritanceCycle;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlDeprecated;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlSignal;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlType;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlProperty;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlDeferredPropertyId;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlUnqualified;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlUnusedImports;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlMultilineStrings;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlSyntax;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlSyntaxIdQuotation;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlSyntaxDuplicateIds;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlCompiler;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlControlsSanity;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlAttachedPropertyReuse;
+extern const Q_QMLCOMPILER_PRIVATE_EXPORT LoggerWarningId qmlPlugin;
+
struct Message : public QQmlJS::DiagnosticMessage
{
std::optional<FixSuggestion> fixSuggestion;
@@ -117,32 +126,27 @@ class Q_QMLCOMPILER_PRIVATE_EXPORT QQmlJSLogger
{
Q_DISABLE_COPY_MOVE(QQmlJSLogger)
public:
- struct Option
+ struct Category
{
- Option() = default;
- Option(QQmlJSLoggerCategory category, QString settingsName, const QString &description,
- QtMsgType level, bool ignored = false)
- : m_category(category),
- m_settingsName(settingsName),
- m_description(description),
- m_level(level),
- m_ignored(ignored)
- {
- }
- QQmlJSLoggerCategory m_category;
- QString m_settingsName;
- QString m_description;
- QtMsgType m_level;
- bool m_ignored;
- bool m_changed = false;
+ QString name;
+ QString settingsName;
+ QString description;
+ QtMsgType level;
+ bool ignored = false;
+ bool isDefault = false; // Whether or not the category can be disabled
+ bool changed = false;
+
+ bool operator==(const LoggerWarningId warningId) const { return warningId.name() == name; }
+
+ LoggerWarningId id() const { return LoggerWarningId(name); }
QString levelToString() const {
- // TODO:: this only makes sense to qmllint
- Q_ASSERT(m_ignored || m_level != QtCriticalMsg);
- if (m_ignored)
+ // TODO: this only makes sense to qmllint
+ Q_ASSERT(ignored || level != QtCriticalMsg);
+ if (ignored)
return QStringLiteral("disable");
- switch (m_level) {
+ switch (level) {
case QtInfoMsg:
return QStringLiteral("info");
case QtWarningMsg:
@@ -155,24 +159,27 @@ public:
bool setLevel(const QString &level) {
if (level == QStringLiteral("disable")) {
- m_level = QtCriticalMsg; // TODO: only so for consistency with previous logic
- m_ignored = true;
+ this->level = QtCriticalMsg; // TODO: only so for consistency with previous logic
+ this->ignored = true;
} else if (level == QStringLiteral("info")) {
- m_level = QtInfoMsg;
- m_ignored = false;
+ this->level = QtInfoMsg;
+ this->ignored = false;
} else if (level == QStringLiteral("warning")) {
- m_level = QtWarningMsg;
- m_ignored = false;
+ this->level = QtWarningMsg;
+ this->ignored = false;
} else {
return false;
}
- m_changed = true;
+ this->changed = true;
return true;
}
};
- static const QMap<QString, Option> &options();
+ const QList<Category> categories() const;
+ static const QList<Category> &defaultCategories();
+
+ void registerCategory(const Category &category);
QQmlJSLogger();
~QQmlJSLogger() = default;
@@ -184,26 +191,29 @@ public:
const QList<Message> &warnings() const { return m_warnings; }
const QList<Message> &errors() const { return m_errors; }
- QtMsgType categoryLevel(QQmlJSLoggerCategory category) const { return m_categoryLevels[category]; }
- void setCategoryLevel(QQmlJSLoggerCategory category, QtMsgType level)
+ QtMsgType categoryLevel(LoggerWarningId id) const
+ {
+ return m_categoryLevels[id.name().toString()];
+ }
+ void setCategoryLevel(LoggerWarningId id, QtMsgType level)
{
- m_categoryLevels[category] = level;
- m_categoryChanged[category] = true;
+ m_categoryLevels[id.name().toString()] = level;
+ m_categoryChanged[id.name().toString()] = true;
}
- bool isCategoryIgnored(QQmlJSLoggerCategory category) const
+ bool isCategoryIgnored(LoggerWarningId id) const
{
- return m_categoryIgnored[category];
+ return m_categoryIgnored[id.name().toString()];
}
- void setCategoryIgnored(QQmlJSLoggerCategory category, bool error)
+ void setCategoryIgnored(LoggerWarningId id, bool error)
{
- m_categoryIgnored[category] = error;
- m_categoryChanged[category] = true;
+ m_categoryIgnored[id.name().toString()] = error;
+ m_categoryChanged[id.name().toString()] = true;
}
- bool wasCategoryChanged(QQmlJSLoggerCategory category) const
+ bool wasCategoryChanged(LoggerWarningId id) const
{
- return m_categoryChanged[category];
+ return m_categoryChanged[id.name().toString()];
}
/*! \internal
@@ -213,19 +223,19 @@ public:
\sa setCategoryLevel
*/
- void log(const QString &message, QQmlJSLoggerCategory category,
- const QQmlJS::SourceLocation &srcLocation, bool showContext = true,
- bool showFileName = true, const std::optional<FixSuggestion> &suggestion = {},
+ void log(const QString &message, LoggerWarningId id, const QQmlJS::SourceLocation &srcLocation,
+ bool showContext = true, bool showFileName = true,
+ const std::optional<FixSuggestion> &suggestion = {},
const QString overrideFileName = QString())
{
- log(message, category, srcLocation, m_categoryLevels[category], showContext, showFileName,
- suggestion, overrideFileName);
+ log(message, id, srcLocation, m_categoryLevels[id.name().toString()], showContext,
+ showFileName, suggestion, overrideFileName);
}
void processMessages(const QList<QQmlJS::DiagnosticMessage> &messages,
- QQmlJSLoggerCategory category);
+ const LoggerWarningId id);
- void ignoreWarnings(uint32_t line, const QSet<QQmlJSLoggerCategory> &categories)
+ void ignoreWarnings(uint32_t line, const QSet<QString> &categories)
{
m_ignoredWarnings[line] = categories;
}
@@ -240,27 +250,28 @@ public:
QString fileName() const { return m_fileName; }
private:
+ QMap<QString, Category> m_categories;
+
void printContext(const QString &overrideFileName, const QQmlJS::SourceLocation &location);
void printFix(const FixSuggestion &fix);
- void log(const QString &message, QQmlJSLoggerCategory category,
- const QQmlJS::SourceLocation &srcLocation, QtMsgType type, bool showContext,
- bool showFileName, const std::optional<FixSuggestion> &suggestion,
- const QString overrideFileName);
+ void log(const QString &message, LoggerWarningId id, const QQmlJS::SourceLocation &srcLocation,
+ QtMsgType type, bool showContext, bool showFileName,
+ const std::optional<FixSuggestion> &suggestion, const QString overrideFileName);
QString m_fileName;
QString m_code;
QColorOutput m_output;
- QtMsgType m_categoryLevels[QQmlJSLoggerCategory_Last + 1] = {};
- bool m_categoryIgnored[QQmlJSLoggerCategory_Last + 1] = {};
- bool m_categoryChanged[QQmlJSLoggerCategory_Last + 1] = {};
+ QHash<QString, QtMsgType> m_categoryLevels;
+ QHash<QString, bool> m_categoryIgnored;
+ QHash<QString, bool> m_categoryChanged;
QList<Message> m_infos;
QList<Message> m_warnings;
QList<Message> m_errors;
- QHash<uint32_t, QSet<QQmlJSLoggerCategory>> m_ignoredWarnings;
+ QHash<uint32_t, QSet<QString>> m_ignoredWarnings;
// the compiler needs private log() function at the moment
friend class QQmlJSAotCompiler;
diff --git a/src/qmlcompiler/qqmljstypepropagator.cpp b/src/qmlcompiler/qqmljstypepropagator.cpp
index 09570469a6..99f8b1e8d4 100644
--- a/src/qmlcompiler/qqmljstypepropagator.cpp
+++ b/src/qmlcompiler/qqmljstypepropagator.cpp
@@ -66,8 +66,8 @@ QQmlJSCompilePass::InstructionAnnotations QQmlJSTypePropagator::run(
return;
#define INSTR_PROLOGUE_NOT_IMPLEMENTED_IGNORE() \
- m_logger->log(u"Instruction \"%1\" not implemented"_s.arg(QString::fromUtf8(__func__)), \
- Log_Compiler, QQmlJS::SourceLocation()); \
+ m_logger->log(u"Instruction \"%1\" not implemented"_s.arg(QString::fromUtf8(__func__)), \
+ qmlCompiler, QQmlJS::SourceLocation()); \
return;
void QQmlJSTypePropagator::generate_Ret()
@@ -94,7 +94,7 @@ void QQmlJSTypePropagator::generate_Ret()
m_logger->log(u"Cannot assign binding of type %1 to %2"_s.arg(
m_typeResolver->containedTypeName(m_state.accumulatorIn(), true),
m_typeResolver->containedTypeName(m_returnType, true)),
- Log_Type, getCurrentBindingSourceLocation());
+ qmlType, getCurrentBindingSourceLocation());
return;
}
@@ -403,7 +403,7 @@ void QQmlJSTypePropagator::handleUnqualifiedAccess(const QString &name, bool isM
}
}
- m_logger->log(QLatin1String("Unqualified access"), Log_UnqualifiedAccess, location, true, true,
+ m_logger->log(QLatin1String("Unqualified access"), qmlUnqualified, location, true, true,
suggestion);
}
@@ -452,7 +452,7 @@ void QQmlJSTypePropagator::checkDeprecated(QQmlJSScope::ConstPtr scope, const QS
if (!deprecation.reason.isEmpty())
message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
- m_logger->log(message, Log_Deprecation, getCurrentSourceLocation());
+ m_logger->log(message, qmlDeprecated, getCurrentSourceLocation());
}
bool QQmlJSTypePropagator::isRestricted(const QString &propertyName) const
@@ -474,8 +474,8 @@ bool QQmlJSTypePropagator::isRestricted(const QString &propertyName) const
if (!restrictedKind.isEmpty())
m_logger->log(u"Type is %1. You cannot access \"%2\" from here."_s.arg(restrictedKind,
- propertyName),
- Log_Type, getCurrentSourceLocation());
+ propertyName),
+ qmlType, getCurrentSourceLocation());
return !restrictedKind.isEmpty();
}
@@ -499,7 +499,7 @@ bool QQmlJSTypePropagator::isMissingPropertyType(QQmlJSScope::ConstPtr scope,
m_logger->log(
u"Type \"%1\" of property \"%2\" not %3. This is likely due to a missing dependency entry or a type not being exposed declaratively."_s
.arg(property.typeName(), propertyName, errorType),
- Log_Type, getCurrentSourceLocation());
+ qmlType, getCurrentSourceLocation());
return true;
}
@@ -538,7 +538,7 @@ bool QQmlJSTypePropagator::isCallingProperty(QQmlJSScope::ConstPtr scope, const
errorType = u"not a method"_s;
}
- m_logger->log(u"%1 \"%2\" is %3"_s.arg(propertyType, name, errorType), Log_Type,
+ m_logger->log(u"%1 \"%2\" is %3"_s.arg(propertyType, name, errorType), qmlType,
getCurrentSourceLocation(), true, true, {});
return true;
@@ -598,7 +598,7 @@ void QQmlJSTypePropagator::generate_StoreNameSloppy(int nameIndex)
if (!type.isWritable() && !m_function->qmlScope->hasOwnProperty(name)) {
setError(u"Can't assign to read-only property %1"_s.arg(name));
- m_logger->log(u"Cannot assign to read-only property %1"_s.arg(name), Log_Property,
+ m_logger->log(u"Cannot assign to read-only property %1"_s.arg(name), qmlProperty,
getCurrentSourceLocation());
return;
@@ -730,7 +730,7 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName)
m_logger->log(
u"Using attached type %1 already initialized in a parent scope."_s.arg(
m_state.accumulatorIn().scopeType()->internalName()),
- Log_AttachedPropertyReuse, getCurrentSourceLocation(), true, true,
+ qmlAttachedPropertyReuse, getCurrentSourceLocation(), true, true,
suggestion);
}
}
@@ -749,10 +749,10 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName)
return;
}
if (m_state.accumulatorIn().isImportNamespace())
- m_logger->log(u"Type not found in namespace"_s, Log_Type, getCurrentSourceLocation());
+ m_logger->log(u"Type not found in namespace"_s, qmlType, getCurrentSourceLocation());
} else if (m_state.accumulatorOut().variant() == QQmlJSRegisterContent::Singleton
&& m_state.accumulatorIn().variant() == QQmlJSRegisterContent::ObjectModulePrefix) {
- m_logger->log(u"Cannot load singleton as property of object"_s, Log_Type,
+ m_logger->log(u"Cannot load singleton as property of object"_s, qmlType,
getCurrentSourceLocation());
setAccumulator(QQmlJSRegisterContent());
}
@@ -801,9 +801,8 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName)
}
}
- m_logger->log(
- u"Property \"%1\" not found on type \"%2\""_s.arg(propertyName).arg(typeName),
- Log_Type, getCurrentSourceLocation(), true, true, fixSuggestion);
+ m_logger->log(u"Property \"%1\" not found on type \"%2\""_s.arg(propertyName).arg(typeName),
+ qmlType, getCurrentSourceLocation(), true, true, fixSuggestion);
return;
}
@@ -822,8 +821,8 @@ void QQmlJSTypePropagator::propagatePropertyLookup(const QString &propertyName)
if (!m_state.accumulatorOut().property().type()) {
m_logger->log(
- QString::fromLatin1("Type of property \"%2\" not found").arg(propertyName),
- Log_Type, getCurrentSourceLocation());
+ QString::fromLatin1("Type of property \"%2\" not found").arg(propertyName),
+ qmlType, getCurrentSourceLocation());
}
}
@@ -893,7 +892,7 @@ void QQmlJSTypePropagator::generate_StoreProperty(int nameIndex, int base)
if (!property.isWritable()) {
setError(u"Can't assign to read-only property %1"_s.arg(propertyName));
- m_logger->log(u"Cannot assign to read-only property %1"_s.arg(propertyName), Log_Property,
+ m_logger->log(u"Cannot assign to read-only property %1"_s.arg(propertyName), qmlProperty,
getCurrentSourceLocation());
return;
@@ -1027,7 +1026,7 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar
m_logger->log(u"Property \"%1\" not found on type \"%2\""_s.arg(
propertyName, m_typeResolver->containedTypeName(callBase, true)),
- Log_Type, getCurrentSourceLocation(), true, true, fixSuggestion);
+ qmlType, getCurrentSourceLocation(), true, true, fixSuggestion);
return;
}
diff --git a/src/qmlcompiler/qqmljstyperesolver.cpp b/src/qmlcompiler/qqmljstyperesolver.cpp
index 533b71fcc4..395da70913 100644
--- a/src/qmlcompiler/qqmljstyperesolver.cpp
+++ b/src/qmlcompiler/qqmljstyperesolver.cpp
@@ -661,7 +661,7 @@ QQmlJSScope::ConstPtr QQmlJSTypeResolver::genericType(const QQmlJSScope::ConstPt
m_logger->log(u"Object type %1 is not derived from QObject or QQmlComponent"_s.arg(
type->internalName()),
- Log_Compiler, type->sourceLocation());
+ qmlCompiler, type->sourceLocation());
// Reference types that are not QObject or QQmlComponent are likely JavaScript objects.
// We don't want to deal with those, but m_jsValueType is the best generic option.
@@ -815,12 +815,12 @@ QQmlJSRegisterContent QQmlJSTypeResolver::scopedType(const QQmlJSScope::ConstPtr
if (!genericType(attached)) {
m_logger->log(u"Cannot resolve generic base of attached %1"_s.arg(
attached->internalName()),
- Log_Compiler, attached->sourceLocation());
+ qmlCompiler, attached->sourceLocation());
return {};
} else if (type->accessSemantics() != QQmlJSScope::AccessSemantics::Reference) {
m_logger->log(u"Cannot retrieve attached object for non-reference type %1"_s.arg(
type->internalName()),
- Log_Compiler, type->sourceLocation());
+ qmlCompiler, type->sourceLocation());
return {};
} else {
// We don't know yet whether we need the attached or the plain object. In direct
@@ -1046,12 +1046,12 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSScope::ConstPtr
if (!genericType(attached)) {
m_logger->log(u"Cannot resolve generic base of attached %1"_s.arg(
attached->internalName()),
- Log_Compiler, attached->sourceLocation());
+ qmlCompiler, attached->sourceLocation());
return {};
} else if (type->accessSemantics() != QQmlJSScope::AccessSemantics::Reference) {
m_logger->log(u"Cannot retrieve attached object for non-reference type %1"_s.arg(
type->internalName()),
- Log_Compiler, type->sourceLocation());
+ qmlCompiler, type->sourceLocation());
return {};
} else {
return QQmlJSRegisterContent::create(storedType(attached), attached,
@@ -1120,7 +1120,7 @@ QQmlJSRegisterContent QQmlJSTypeResolver::memberType(const QQmlJSRegisterContent
m_logger->log(
u"Cannot use non-reference type %1 as base of namespaced attached type"_s.arg(
type.scopeType()->internalName()),
- Log_Type, type.scopeType()->sourceLocation());
+ qmlType, type.scopeType()->sourceLocation());
return {};
}
diff --git a/src/qmlcompiler/qqmlsa.cpp b/src/qmlcompiler/qqmlsa.cpp
index e9acf3b90c..9dacef54f4 100644
--- a/src/qmlcompiler/qqmlsa.cpp
+++ b/src/qmlcompiler/qqmlsa.cpp
@@ -31,9 +31,10 @@ GenericPass::GenericPass(PassManager *manager)
d->manager = manager;
}
-void GenericPass::emitWarning(QAnyStringView message, QQmlJS::SourceLocation srcLocation)
+void GenericPass::emitWarning(QAnyStringView message, LoggerWarningId id,
+ QQmlJS::SourceLocation srcLocation)
{
- d->manager->m_visitor->logger()->log(message.toString(), Log_Plugin, srcLocation);
+ d->manager->m_visitor->logger()->log(message.toString(), id, srcLocation);
}
Element GenericPass::resolveType(QAnyStringView moduleName, QAnyStringView typeName)
@@ -226,13 +227,14 @@ QSet<PropertyPass *> PassManager::findPropertyUsePasses(const QQmlSA::Element &e
}
void DebugElementPass::run(const Element &element) {
- emitWarning(u"Type: " + element->baseTypeName());
+ emitWarning(u"Type: " + element->baseTypeName(), qmlPlugin);
if (auto bindings = element->propertyBindings(u"objectName"_s); !bindings.isEmpty()) {
- emitWarning(u"is named: " + bindings.first().stringValue());
+ emitWarning(u"is named: " + bindings.first().stringValue(), qmlPlugin);
}
if (auto defPropName = element->defaultPropertyName(); !defPropName.isEmpty()) {
emitWarning(u"binding " + QString::number(element->propertyBindings(defPropName).size())
- + u" elements to property "_s + defPropName);
+ + u" elements to property "_s + defPropName,
+ qmlPlugin);
}
}
@@ -287,7 +289,7 @@ void DebugPropertyPass::onRead(const QQmlSA::Element &element, const QString &pr
+ u' ' + propertyName + u' ' + readScope->internalName() + u' '
+ QString::number(location.startLine) + u':'
+ QString::number(location.startColumn),
- location);
+ qmlPlugin, location);
}
void DebugPropertyPass::onBinding(const QQmlSA::Element &element, const QString &propertyName,
@@ -308,7 +310,7 @@ void DebugPropertyPass::onBinding(const QQmlSA::Element &element, const QString
: bindingScope->internalName())
+ u"' "_s + QString::number(location.startLine) + u':'
+ QString::number(location.startColumn),
- location);
+ qmlPlugin, location);
}
void DebugPropertyPass::onWrite(const QQmlSA::Element &element, const QString &propertyName,
@@ -319,7 +321,7 @@ void DebugPropertyPass::onWrite(const QQmlSA::Element &element, const QString &p
+ value->internalName() + u' ' + writeScope->internalName() + u' '
+ QString::number(location.startLine) + u':'
+ QString::number(location.startColumn),
- location);
+ qmlPlugin, location);
}
}
diff --git a/src/qmlcompiler/qqmlsa_p.h b/src/qmlcompiler/qqmlsa_p.h
index 30669aec2a..67b6995b54 100644
--- a/src/qmlcompiler/qqmlsa_p.h
+++ b/src/qmlcompiler/qqmlsa_p.h
@@ -17,6 +17,7 @@
#include <qtqmlcompilerexports.h>
#include <private/qqmljsscope_p.h>
+#include <private/qqmljslogger_p.h>
#include <QtCore/qset.h>
#include <map>
@@ -45,7 +46,7 @@ public:
GenericPass(PassManager *manager);
virtual ~GenericPass();
- void emitWarning(QAnyStringView message,
+ void emitWarning(QAnyStringView message, LoggerWarningId id,
QQmlJS::SourceLocation srcLocation = QQmlJS::SourceLocation());
Element resolveType(QAnyStringView moduleName, QAnyStringView typeName); // #### TODO: revisions
Element resolveLiteralType(const QQmlJSMetaPropertyBinding &binding);
diff --git a/tests/auto/qml/qmllint/lintplugin.cpp b/tests/auto/qml/qmllint/lintplugin.cpp
index 8e04c670b4..47279adcaa 100644
--- a/tests/auto/qml/qmllint/lintplugin.cpp
+++ b/tests/auto/qml/qmllint/lintplugin.cpp
@@ -5,6 +5,8 @@
using namespace Qt::StringLiterals;
+static constexpr LoggerWarningId plugin { "testPlugin.test" };
+
class ElementTest : public QQmlSA::ElementPass
{
public:
@@ -22,17 +24,18 @@ public:
{
auto property = element->property(u"radius"_s);
if (!property.isValid() || element->property(u"radius"_s).typeName() != u"double") {
- emitWarning(u"Failed to verify radius property", element->sourceLocation());
+ emitWarning(u"Failed to verify radius property", plugin, element->sourceLocation());
return;
}
auto bindings = element->propertyBindings(u"radius"_s);
if (bindings.isEmpty() || bindings.constFirst().numberValue() != 5) {
- emitWarning(u"Failed to verify radius property binding", element->sourceLocation());
+ emitWarning(u"Failed to verify radius property binding", plugin,
+ element->sourceLocation());
return;
}
- emitWarning(u"ElementTest OK", element->sourceLocation());
+ emitWarning(u"ElementTest OK", plugin, element->sourceLocation());
}
private:
@@ -56,7 +59,7 @@ public:
: value->baseTypeName()))
.arg(binding.bindingType())
.arg(bindingScope->baseTypeName()),
- bindingScope->sourceLocation());
+ plugin, bindingScope->sourceLocation());
}
void onRead(const QQmlSA::Element &element, const QString &propertyName,
@@ -64,7 +67,7 @@ public:
{
emitWarning(u"Saw read on %1 property %2 in scope %3"_s.arg(
element->baseTypeName(), propertyName, readScope->baseTypeName()),
- location);
+ plugin, location);
}
void onWrite(const QQmlSA::Element &element, const QString &propertyName,
@@ -76,7 +79,7 @@ public:
(value->internalName().isNull() ? value->baseTypeName()
: value->internalName()),
writeScope->baseTypeName()),
- location);
+ plugin, location);
}
};
@@ -97,7 +100,7 @@ public:
void run(const QQmlSA::Element &element) override
{
Q_UNUSED(element)
- emitWarning(m_message);
+ emitWarning(m_message, plugin);
}
private:
diff --git a/tests/auto/qml/qmllint/testPlugin.json b/tests/auto/qml/qmllint/testPlugin.json
index 02bda71b0d..b6958fb753 100644
--- a/tests/auto/qml/qmllint/testPlugin.json
+++ b/tests/auto/qml/qmllint/testPlugin.json
@@ -2,5 +2,13 @@
"name": "testPlugin",
"author": "Qt",
"description": "A test plugin for tst_qmllint",
- "version": "1.0"
+ "version": "1.0",
+ "isInternal": true,
+ "loggingCategories": [
+ {
+ "name": "test",
+ "settingsName": "TestWarning",
+ "description": "A warning type used in tests"
+ }
+ ]
}
diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 44bc32f180..fe3abfc414 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -111,8 +111,7 @@ private:
QStringList importDirs = {}, QStringList qmltypesFiles = {},
QStringList resources = {},
DefaultImportOption defaultImports = UseDefaultImports,
- QMap<QString, QQmlJSLogger::Option> *options = nullptr,
- bool autoFixable = false);
+ QList<QQmlJSLogger::Category> *categories = nullptr, bool autoFixable = false);
void searchWarnings(const QJsonArray &warnings, const QString &string,
QtMsgType type = QtWarningMsg, quint32 line = 0, quint32 column = 0,
@@ -133,7 +132,7 @@ private:
void runTest(const QString &testFile, const Result &result, QStringList importDirs = {},
QStringList qmltypesFiles = {}, QStringList resources = {},
DefaultImportOption defaultImports = UseDefaultImports,
- QMap<QString, QQmlJSLogger::Option> *options = nullptr);
+ QList<QQmlJSLogger::Category> *categories = nullptr);
QString m_qmllintPath;
QString m_qmljsrootgenPath;
@@ -707,7 +706,8 @@ void TestQmllint::dirtyQmlCode_data()
QTest::newRow("duplicated id")
<< QStringLiteral("duplicateId.qml")
<< Result { { Message {
- QStringLiteral("Found a duplicated id. id root was first declared ") } } };
+ QStringLiteral("Found a duplicated id. id root was first declared "), 0, 0,
+ QtCriticalMsg } } };
QTest::newRow("string as id") << QStringLiteral("stringAsId.qml")
<< Result { { Message { QStringLiteral(
@@ -1213,12 +1213,15 @@ void TestQmllint::compilerWarnings()
QJsonArray warnings;
- auto options = QQmlJSLogger::options();
+ auto categories = QQmlJSLogger::defaultCategories();
+
+ auto category = std::find(categories.begin(), categories.end(), qmlCompiler);
+ Q_ASSERT(category != categories.end());
if (enableCompilerWarnings)
- options[u"compiler"_s].setLevel(u"warning"_s);
+ category->setLevel(u"warning"_s);
- runTest(filename, result, {}, {}, {}, UseDefaultImports, &options);
+ runTest(filename, result, {}, {}, {}, UseDefaultImports, &categories);
}
void TestQmllint::controlsSanity_data()
@@ -1242,10 +1245,14 @@ void TestQmllint::controlsSanity()
QJsonArray warnings;
- auto options = QQmlJSLogger::options();
- options[u"controls-sanity"_s].setLevel(u"warning"_s);
+ auto categories = QQmlJSLogger::defaultCategories();
+
+ auto category = std::find(categories.begin(), categories.end(), qmlControlsSanity);
+ Q_ASSERT(category != categories.end());
- runTest(filename, result, {}, {}, {}, UseDefaultImports, &options);
+ category->setLevel(u"warning"_s);
+
+ runTest(filename, result, {}, {}, {}, UseDefaultImports, &categories);
}
QString TestQmllint::runQmllint(const QString &fileToLint,
@@ -1338,7 +1345,7 @@ QString TestQmllint::runQmllint(const QString &fileToLint, bool shouldSucceed,
void TestQmllint::callQmllint(const QString &fileToLint, bool shouldSucceed, QJsonArray *warnings,
QStringList importPaths, QStringList qmldirFiles,
QStringList resources, DefaultImportOption defaultImports,
- QMap<QString, QQmlJSLogger::Option> *options, bool autoFixable)
+ QList<QQmlJSLogger::Category> *categories, bool autoFixable)
{
QJsonArray jsonOutput;
@@ -1348,7 +1355,8 @@ void TestQmllint::callQmllint(const QString &fileToLint, bool shouldSucceed, QJs
QQmlJSLinter::LintResult lintResult = m_linter.lintFile(
lintedFile, nullptr, true, warnings ? &jsonOutput : nullptr,
defaultImports == UseDefaultImports ? m_defaultImportPaths + importPaths : importPaths,
- qmldirFiles, resources, options != nullptr ? *options : QQmlJSLogger::options());
+ qmldirFiles, resources,
+ categories != nullptr ? *categories : QQmlJSLogger::defaultCategories());
bool success = lintResult == QQmlJSLinter::LintSuccess;
QVERIFY2(success == shouldSucceed, QJsonDocument(jsonOutput).toJson());
@@ -1376,7 +1384,7 @@ void TestQmllint::callQmllint(const QString &fileToLint, bool shouldSucceed, QJs
file.close();
callQmllint(QFileInfo(file).absoluteFilePath(), true, nullptr, importPaths, qmldirFiles,
- resources, defaultImports, options, false);
+ resources, defaultImports, categories, false);
const QString fixedPath = testFile(info.baseName() + u".fixed.qml"_s);
@@ -1404,11 +1412,11 @@ void TestQmllint::callQmllint(const QString &fileToLint, bool shouldSucceed, QJs
void TestQmllint::runTest(const QString &testFile, const Result &result, QStringList importDirs,
QStringList qmltypesFiles, QStringList resources,
DefaultImportOption defaultImports,
- QMap<QString, QQmlJSLogger::Option> *options)
+ QList<QQmlJSLogger::Category> *categories)
{
QJsonArray warnings;
callQmllint(testFile, result.flags.testFlag(Result::Flag::ExitsNormally), &warnings, importDirs,
- qmltypesFiles, resources, defaultImports, options,
+ qmltypesFiles, resources, defaultImports, categories,
result.flags.testFlag(Result::Flag::AutoFixable));
checkResult(warnings, result);
}
@@ -1583,15 +1591,18 @@ void TestQmllint::additionalImplicitImport()
void TestQmllint::attachedPropertyReuse()
{
- auto options = QQmlJSLogger::options();
- options[u"multiple-attached-objects"_s].setLevel(u"warning"_s);
+ auto categories = QQmlJSLogger::defaultCategories();
+ auto category = std::find(categories.begin(), categories.end(), qmlAttachedPropertyReuse);
+ Q_ASSERT(category != categories.end());
+
+ category->setLevel(u"warning"_s);
runTest("attachedPropNotReused.qml",
Result { { Message { QStringLiteral("Using attached type QQuickKeyNavigationAttached "
"already initialized in a parent "
"scope") } } },
- {}, {}, {}, UseDefaultImports, &options);
+ {}, {}, {}, UseDefaultImports, &categories);
- runTest("attachedPropEnum.qml", Result::clean(), {}, {}, {}, UseDefaultImports, &options);
+ runTest("attachedPropEnum.qml", Result::clean(), {}, {}, {}, UseDefaultImports, &categories);
}
void TestQmllint::missingBuiltinsNoCrash()
diff --git a/tests/auto/quickcontrols2/sanity/tst_sanity.cpp b/tests/auto/quickcontrols2/sanity/tst_sanity.cpp
index 70da27b104..150d38b5aa 100644
--- a/tests/auto/quickcontrols2/sanity/tst_sanity.cpp
+++ b/tests/auto/quickcontrols2/sanity/tst_sanity.cpp
@@ -11,6 +11,7 @@
#include <QtQml/private/qqmljslexer_p.h>
#include <QtQml/private/qqmljsparser_p.h>
#include <QtQml/private/qqmljsast_p.h>
+#include <QtQmlCompiler/private/qqmljslogger_p.h>
#include <QtQml/private/qqmljsastvisitor_p.h>
#include <QtQml/private/qqmlmetatype_p.h>
#include <QtQuickTestUtils/private/visualtestutils_p.h>
@@ -40,23 +41,28 @@ private:
QStringList m_importPaths;
QQmlJSLinter m_linter;
- QMap<QString, QQmlJSLogger::Option> m_options;
+ QList<QQmlJSLogger::Category> m_categories;
};
tst_Sanity::tst_Sanity()
: m_importPaths({ QLibraryInfo::path(QLibraryInfo::QmlImportsPath) }),
m_linter(m_importPaths),
- m_options(QQmlJSLogger::options())
+ m_categories(QQmlJSLogger::defaultCategories())
{
// We do not care about any warnings that aren't explicitly created by controls-sanity.
// Mainly because a lot of false positives are generated because we are linting files from
// different modules directly without their generated qmldirs.
- for (const QString &key : m_options.keys())
- m_options[key].setLevel(u"disable"_s);
- m_options[u"deferred-property-id"_s].setLevel(u"warning"_s);
- m_options[u"controls-sanity"_s].setLevel(u"warning"_s);
- m_options[u"multiple-attached-objects"_s].setLevel(u"warning"_s);
+ m_linter.setPluginsEnabled(false);
+
+ for (auto &category : m_categories) {
+ if (category == qmlDeferredPropertyId || category == qmlControlsSanity
+ || category == qmlAttachedPropertyReuse) {
+ category.setLevel(u"warning"_s);
+ } else {
+ category.setLevel(u"disable"_s);
+ }
+ }
}
void tst_Sanity::initTestCase()
@@ -109,7 +115,7 @@ void tst_Sanity::qmllint()
QJsonArray output;
bool success =
- m_linter.lintFile(filePath, nullptr, true, &output, m_importPaths, {}, {}, m_options)
+ m_linter.lintFile(filePath, nullptr, true, &output, m_importPaths, {}, {}, m_categories)
== QQmlJSLinter::LintSuccess;
QVERIFY2(success, qPrintable(QJsonDocument(output).toJson(QJsonDocument::Compact)));
diff --git a/tools/qmlcachegen/qmlcachegen.cpp b/tools/qmlcachegen/qmlcachegen.cpp
index f3fc06bec5..6ade0987f9 100644
--- a/tools/qmlcachegen/qmlcachegen.cpp
+++ b/tools/qmlcachegen/qmlcachegen.cpp
@@ -241,8 +241,8 @@ int main(int argc, char **argv)
QQmlJSLogger logger;
// Always trigger the qFatal() on "pragma Strict" violations.
- logger.setCategoryLevel(Log_Compiler, QtCriticalMsg);
- logger.setCategoryIgnored(Log_Compiler, false);
+ logger.setCategoryLevel(qmlCompiler, QtCriticalMsg);
+ logger.setCategoryIgnored(qmlCompiler, false);
// By default, we're completely silent,
// as the lcAotCompiler category default is QtFatalMsg
@@ -265,8 +265,8 @@ int main(int argc, char **argv)
if (!warnings.isEmpty()) {
logger.log(QStringLiteral("Type warnings occurred while compiling file:"),
- Log_Import, QQmlJS::SourceLocation());
- logger.processMessages(warnings, Log_Import);
+ qmlImport, QQmlJS::SourceLocation());
+ logger.processMessages(warnings, qmlImport);
}
}
} else if (inputFile.endsWith(QLatin1String(".js")) || inputFile.endsWith(QLatin1String(".mjs"))) {
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 6171d92360..a5e1361fbb 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -32,7 +32,7 @@ constexpr int JSON_LOGGING_FORMAT_REVISION = 3;
int main(int argv, char *argc[])
{
qSetGlobalQHashSeed(0);
- QMap<QString, QQmlJSLogger::Option> options = QQmlJSLogger::options();
+ QList<QQmlJSLogger::Category> categories;
QCoreApplication app(argv, argc);
QCoreApplication::setApplicationName("qmllint");
@@ -47,17 +47,6 @@ All warnings can be set to three levels:
warning - Displays the warning and leads to a non-zero exit code if encountered.
)"));
- for (auto it = options.cbegin(); it != options.cend(); ++it) {
- QCommandLineOption option(
- it.key(),
- it.value().m_description
- + QStringLiteral(" (default: %1)").arg(it.value().levelToString()),
- QStringLiteral("level"), it.value().levelToString());
- parser.addOption(option);
- settings.addOption(QStringLiteral("Warnings/") + it.value().m_settingsName,
- it.value().levelToString());
- }
-
parser.addHelpOption();
parser.addVersionOption();
@@ -156,30 +145,65 @@ All warnings can be set to three levels:
QLatin1String("directory"));
parser.addOption(pluginPathsOption);
+ auto addCategory = [&](const QQmlJSLogger::Category &category) {
+ categories.push_back(category);
+ if (category.isDefault)
+ return;
+ QCommandLineOption option(
+ category.id().name().toString(),
+ category.description
+ + QStringLiteral(" (default: %1)").arg(category.levelToString()),
+ QStringLiteral("level"), category.levelToString());
+ if (category.ignored)
+ option.setFlags(QCommandLineOption::HiddenFromHelp);
+ parser.addOption(option);
+ settings.addOption(QStringLiteral("Warnings/") + category.settingsName,
+ category.levelToString());
+ };
+
+ for (const auto &category : QQmlJSLogger::defaultCategories()) {
+ addCategory(category);
+ }
+
parser.addPositionalArgument(QLatin1String("files"),
QLatin1String("list of qml or js files to verify"));
- parser.process(app);
+ if (!parser.parse(app.arguments())) {
+ if (parser.unknownOptionNames().isEmpty()) {
+ qWarning().noquote() << parser.errorText();
+ return 1;
+ }
+ }
+
+ // Since we can't use QCommandLineParser::process(), we need to handle version and help manually
+ if (parser.isSet("version"))
+ parser.showVersion();
+
+ if (parser.isSet("help") || parser.isSet("help-all"))
+ parser.showHelp(0);
if (parser.isSet(writeDefaultsOption)) {
return settings.writeDefaults() ? 0 : 1;
}
auto updateLogLevels = [&]() {
- for (auto it = options.begin(); it != options.end(); ++it) {
- const QString &key = it.key();
- const QString &settingsName = QStringLiteral("Warnings/") + it.value().m_settingsName;
+ for (auto &category : categories) {
+ if (category.isDefault)
+ continue;
+
+ const QString &key = category.id().name().toString();
+ const QString &settingsName = QStringLiteral("Warnings/") + category.settingsName;
if (parser.isSet(key) || settings.isSet(settingsName)) {
const QString value = parser.isSet(key) ? parser.value(key)
: settings.value(settingsName).toString();
- auto &option = it.value();
// Do not try to set the levels if it's due to a default config option.
// This way we can tell which options have actually been overwritten by the user.
- if (option.levelToString() == value && !parser.isSet(key))
+ if (category.levelToString() == value && !parser.isSet(key))
continue;
- if (!option.setLevel(value)) {
- qWarning() << "Invalid logging level" << value << "provided for" << it.key()
+ if (!category.setLevel(value)) {
+ qWarning() << "Invalid logging level" << value << "provided for"
+ << category.id().name().toString()
<< "(allowed are: disable, info, warning)";
parser.showHelp(-1);
}
@@ -187,8 +211,6 @@ All warnings can be set to three levels:
}
};
- updateLogLevels();
-
bool silent = parser.isSet(silentOption);
bool useAbsolutePath = parser.isSet(absolutePath);
bool useJson = parser.isSet(jsonOption);
@@ -233,6 +255,16 @@ All warnings can be set to three levels:
QQmlJSLinter linter(qmlImportPaths, pluginPaths, useAbsolutePath);
+ for (const QQmlJSLinter::Plugin &plugin : linter.plugins()) {
+ for (const QQmlJSLogger::Category &category : plugin.categories())
+ addCategory(category);
+ }
+
+ if (!parser.unknownOptionNames().isEmpty())
+ parser.process(app);
+
+ updateLogLevels();
+
if (parser.isSet(listPluginsOption)) {
const std::vector<QQmlJSLinter::Plugin> &plugins = linter.plugins();
if (!plugins.empty()) {
@@ -244,7 +276,7 @@ All warnings can be set to three levels:
<< plugin.description();
}
} else {
- qInfo() << "No plugins installed.";
+ qWarning() << "No plugins installed.";
}
return 0;
}
@@ -319,7 +351,7 @@ All warnings can be set to three levels:
QQmlJSLinter::LintResult lintResult = linter.lintFile(
filename, nullptr, silent || isFixing, useJson ? &jsonFiles : nullptr,
- qmlImportPaths, qmldirFiles, resourceFiles, options);
+ qmlImportPaths, qmldirFiles, resourceFiles, categories);
success &= (lintResult == QQmlJSLinter::LintSuccess);
if (isFixing) {
diff --git a/tools/qmlls/qmllintsuggestions.cpp b/tools/qmlls/qmllintsuggestions.cpp
index 6f17f7a9ce..06a8970205 100644
--- a/tools/qmlls/qmllintsuggestions.cpp
+++ b/tools/qmlls/qmllintsuggestions.cpp
@@ -152,12 +152,12 @@ void QmlLintSuggestions::diagnose(const QByteArray &url)
fileContents = doc.field(Fields::code).value().toString();
QStringList qmltypesFiles;
QStringList resourceFiles;
- QMap<QString, QQmlJSLogger::Option> options;
+ QList<QQmlJSLogger::Category> categories;
QQmlJSLinter linter(imports);
linter.lintFile(filename, &fileContents, silent, nullptr, imports, qmltypesFiles,
- resourceFiles, options);
+ resourceFiles, categories);
auto addLength = [&fileContents](Position &position, int startOffset, int length) {
int i = startOffset;
int iEnd = i + length;
diff --git a/tools/qmltc/main.cpp b/tools/qmltc/main.cpp
index cf47943034..6afa5a5fc0 100644
--- a/tools/qmltc/main.cpp
+++ b/tools/qmltc/main.cpp
@@ -30,17 +30,12 @@ using namespace Qt::StringLiterals;
void setupLogger(QQmlJSLogger &logger) // prepare logger to work with compiler
{
- const QSet<QQmlJSLoggerCategory> exceptions {
- Log_ControlsSanity, // this category is just weird
- Log_UnusedImport, // not critical
- };
-
- for (int i = 0; i <= static_cast<int>(QQmlJSLoggerCategory_Last); ++i) {
- const auto c = static_cast<QQmlJSLoggerCategory>(i);
- if (exceptions.contains(c))
+ for (const QQmlJSLogger::Category &category : logger.categories()) {
+ if (category == qmlControlsSanity // this category is just weird
+ || category == qmlUnusedImports)
continue;
- logger.setCategoryLevel(c, QtCriticalMsg);
- logger.setCategoryIgnored(c, false);
+ logger.setCategoryLevel(category.id(), QtCriticalMsg);
+ logger.setCategoryIgnored(category.id(), false);
}
}
@@ -227,9 +222,9 @@ int main(int argc, char **argv)
QList<QQmlJS::DiagnosticMessage> warnings = importer.takeGlobalWarnings();
if (!warnings.isEmpty()) {
- logger.log(QStringLiteral("Type warnings occurred while compiling file:"), Log_Import,
+ logger.log(QStringLiteral("Type warnings occurred while compiling file:"), qmlImport,
QQmlJS::SourceLocation());
- logger.processMessages(warnings, Log_Import);
+ logger.processMessages(warnings, qmlImport);
// Log_Import is critical for the compiler
return EXIT_FAILURE;
}
diff --git a/tools/qmltc/qmltccompiler.h b/tools/qmltc/qmltccompiler.h
index deb9f19793..5d660ad36b 100644
--- a/tools/qmltc/qmltccompiler.h
+++ b/tools/qmltc/qmltccompiler.h
@@ -140,17 +140,17 @@ private:
bool hasErrors() const { return m_logger->hasErrors(); }
void recordError(const QQmlJS::SourceLocation &location, const QString &message,
- QQmlJSLoggerCategory category = Log_Compiler)
+ LoggerWarningId id = qmlCompiler)
{
// pretty much any compiler error is a critical error (we cannot
// generate code - compilation fails)
- m_logger->log(message, category, location);
+ m_logger->log(message, id, location);
}
void recordError(const QV4::CompiledData::Location &location, const QString &message,
- QQmlJSLoggerCategory category = Log_Compiler)
+ LoggerWarningId id = qmlCompiler)
{
recordError(QQmlJS::SourceLocation { 0, 0, location.line(), location.column() }, message,
- category);
+ id);
}
};
diff --git a/tools/qmltc/qmltcvisitor.cpp b/tools/qmltc/qmltcvisitor.cpp
index 176410ef6d..c5caa6e7b6 100644
--- a/tools/qmltc/qmltcvisitor.cpp
+++ b/tools/qmltc/qmltcvisitor.cpp
@@ -247,12 +247,12 @@ bool QmltcVisitor::visit(QQmlJS::AST::UiPublicMember *publicMember)
methods.isEmpty() ? u"no signal"_s : u"too many signals"_s;
m_logger->log(
u"internal error: %1 found for property '%2'"_s.arg(errorString, name),
- Log_Compiler, publicMember->identifierToken);
+ qmlCompiler, publicMember->identifierToken);
return false;
} else if (methods[0].methodType() != QQmlJSMetaMethod::Signal) {
m_logger->log(u"internal error: method %1 of property %2 must be a signal"_s.arg(
notifyName, name),
- Log_Compiler, publicMember->identifierToken);
+ qmlCompiler, publicMember->identifierToken);
return false;
}
}
@@ -279,7 +279,7 @@ bool QmltcVisitor::visit(QQmlJS::AST::UiInlineComponent *component)
{
if (!QQmlJSImportVisitor::visit(component))
return false;
- m_logger->log(u"Inline components are not supported"_s, Log_Compiler,
+ m_logger->log(u"Inline components are not supported"_s, qmlCompiler,
component->firstSourceLocation());
// despite the failure, return true here so that we do not assert in
// QQmlJSImportVisitor::endVisit(UiInlineComponent)
@@ -536,7 +536,7 @@ void QmltcVisitor::setupAliases()
QQmlJSUtils::AliasResolutionVisitor {});
if (result.kind == QQmlJSUtils::AliasTarget_Invalid) {
m_logger->log(QStringLiteral("Cannot resolve alias \"%1\"").arg(p.propertyName()),
- Log_Alias, current->sourceLocation());
+ qmlAlias, current->sourceLocation());
continue;
}
setAliasData(&p, result);
@@ -658,7 +658,7 @@ void QmltcVisitor::checkForNamingCollisionsWithCpp(const QQmlJSScope::ConstPtr &
if (!isReserved(name))
return;
m_logger->log(errorPrefix + u" '" + name + u"' is a reserved C++ word, consider renaming",
- Log_Compiler, type->sourceLocation());
+ qmlCompiler, type->sourceLocation());
};
const auto enums = type->ownEnumerations();