aboutsummaryrefslogtreecommitdiffstats
path: root/tools/qmllint
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2021-03-25 15:34:42 +0100
committerMaximilian Goldstein <max.goldstein@qt.io>2021-03-29 12:31:01 +0100
commit954071f372b70f3656386793e2fca382c1b0a1c0 (patch)
treeace5d46d8c00b5d96463365832eb0c14b75f812b /tools/qmllint
parentb82ae347397595241dcd4a5848ad0c6bfae4574b (diff)
qmlcompiler/qmllint: Use unified logger
Improves the logging situation greatly by allowing all logging messages to be assigned different severities, highlighting the code that caused them and by now ensuring a qmllint warning will always result in a non-zero exit code. A later patch will expose more of these options to the user. Change-Id: Id9b036fe3ba80dd18e9f8cb1b05efa891713d5a8 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tools/qmllint')
-rw-r--r--tools/qmllint/CMakeLists.txt1
-rw-r--r--tools/qmllint/checkidentifiers.cpp229
-rw-r--r--tools/qmllint/checkidentifiers.h16
-rw-r--r--tools/qmllint/findwarnings.cpp192
-rw-r--r--tools/qmllint/findwarnings.h9
-rw-r--r--tools/qmllint/main.cpp8
-rw-r--r--tools/qmllint/qcoloroutput.cpp336
-rw-r--r--tools/qmllint/qcoloroutput.h121
8 files changed, 152 insertions, 760 deletions
diff --git a/tools/qmllint/CMakeLists.txt b/tools/qmllint/CMakeLists.txt
index a133af3cb7..77e22598f3 100644
--- a/tools/qmllint/CMakeLists.txt
+++ b/tools/qmllint/CMakeLists.txt
@@ -12,7 +12,6 @@ qt_internal_add_tool(${target_name}
checkidentifiers.cpp checkidentifiers.h
findwarnings.cpp findwarnings.h
main.cpp
- qcoloroutput.cpp qcoloroutput.h
PUBLIC_LIBRARIES
Qt::CorePrivate
Qt::QmlCompilerPrivate
diff --git a/tools/qmllint/checkidentifiers.cpp b/tools/qmllint/checkidentifiers.cpp
index 2c64fd9198..a08cb9654c 100644
--- a/tools/qmllint/checkidentifiers.cpp
+++ b/tools/qmllint/checkidentifiers.cpp
@@ -27,49 +27,13 @@
****************************************************************************/
#include "checkidentifiers.h"
-#include "qcoloroutput.h"
+
+#include <QtQmlCompiler/private/qcoloroutput_p.h>
#include <QtCore/qqueue.h>
#include <QtCore/qsharedpointer.h>
#include <stack>
-/*!
- \internal
- Used to print the the line containing the location of a certain error
- */
-class IssueLocationWithContext
-{
-public:
- /*!
- \internal
- \param code: The whole text of a translation unit
- \param location: The location where an error occurred.
- */
- IssueLocationWithContext(QStringView code, const QQmlJS::SourceLocation &location) {
- int before = qMax(0,code.lastIndexOf(QLatin1Char('\n'), location.offset));
-
- if (before != 0) before++;
-
- m_beforeText = code.mid(before, location.offset - before);
- m_issueText = code.mid(location.offset, location.length);
- int after = code.indexOf(QLatin1Char('\n'), location.offset + location.length);
- m_afterText = code.mid(location.offset + location.length,
- after - (location.offset+location.length));
- }
-
- // returns start of the line till first character of location
- QStringView beforeText() const { return m_beforeText; }
- // returns the text at location
- QStringView issueText() const { return m_issueText; }
- // returns any text after location until the end of the line is reached
- QStringView afterText() const { return m_afterText; }
-
-private:
- QStringView m_beforeText;
- QStringView m_issueText;
- QStringView m_afterText;
-};
-
static const QStringList unknownBuiltins = {
QStringLiteral("alias"), // TODO: we cannot properly resolve aliases, yet
QStringLiteral("QJSValue"), // We cannot say anything intelligent about untyped JS values.
@@ -79,23 +43,6 @@ static const QStringList unknownBuiltins = {
QStringLiteral("var")
};
-void CheckIdentifiers::printContext(
- const QString &code, ColorOutput *output, const QQmlJS::SourceLocation &location)
-{
- IssueLocationWithContext issueLocationWithContext { code, location };
- if (const QStringView beforeText = issueLocationWithContext.beforeText(); !beforeText.isEmpty())
- output->write(beforeText, Normal);
- output->write(issueLocationWithContext.issueText(), Error);
- if (const QStringView afterText = issueLocationWithContext.afterText(); !afterText.isEmpty())
- output->write(afterText + QLatin1Char('\n'), Normal);
- int tabCount = issueLocationWithContext.beforeText().count(QLatin1Char('\t'));
- output->write(QString::fromLatin1(" ").repeated(
- issueLocationWithContext.beforeText().length() - tabCount)
- + QString::fromLatin1("\t").repeated(tabCount)
- + QString::fromLatin1("^").repeated(location.length)
- + QLatin1Char('\n'), Normal);
-}
-
template<typename Visitor>
static bool walkRelatedScopes(QQmlJSScope::ConstPtr rootType, const Visitor &visit)
{
@@ -125,7 +72,7 @@ static bool walkRelatedScopes(QQmlJSScope::ConstPtr rootType, const Visitor &vis
return false;
}
-bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
+void CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
const QQmlJSScope::ConstPtr &outerScope,
const QQmlJSMetaProperty *prop) const
{
@@ -144,16 +91,12 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
const FieldMember &access = members.at(i);
if (scope.isNull()) {
- m_colorOut->writePrefixedMessage(
- QString::fromLatin1("Type \"%1\" of base \"%2\" not found when accessing member \"%3\" at %4:%5:%6.\n")
+ m_logger->log(
+ QString::fromLatin1("Type \"%1\" of base \"%2\" not found when accessing member \"%3\"")
.arg(detectedRestrictiveKind)
.arg(detectedRestrictiveName)
- .arg(access.m_name)
- .arg(m_fileName)
- .arg(access.m_location.startLine)
- .arg(access.m_location.startColumn), Warning);
- printContext(m_code, m_colorOut, access.m_location);
- return false;
+ .arg(access.m_name), Log_Type, access.m_location);
+ return;
}
if (!detectedRestrictiveKind.isEmpty()) {
@@ -162,16 +105,12 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
continue;
}
- m_colorOut->writePrefixedMessage(QString::fromLatin1(
- "\"%1\" is a %2. You cannot access \"%3\" on it at %4:%5:%6\n")
- .arg(detectedRestrictiveName)
- .arg(detectedRestrictiveKind)
- .arg(access.m_name)
- .arg(m_fileName)
- .arg(access.m_location.startLine)
- .arg(access.m_location.startColumn), Warning);
- printContext(m_code, m_colorOut, access.m_location);
- return false;
+ m_logger->log(
+ QLatin1String("\"%1\" is a %2. You cannot access \"%3\" it from here")
+ .arg(detectedRestrictiveName)
+ .arg(detectedRestrictiveKind)
+ .arg(access.m_name), Log_Type, access.m_location);
+ return;
}
const auto property = scope->property(access.m_name);
@@ -204,7 +143,7 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
}
if (unknownBuiltins.contains(typeName))
- return true;
+ return;
const auto it = m_types.find(typeName);
if (it == m_types.end()) {
@@ -219,7 +158,7 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
}
if (scope->hasMethod(access.m_name))
- return true; // Access to property of JS function
+ return; // Access to property of JS function
auto checkEnums = [&](const QQmlJSScope::ConstPtr &scope) {
if (scope->hasEnumeration(access.m_name)) {
@@ -294,29 +233,21 @@ bool CheckIdentifiers::checkMemberAccess(const QVector<FieldMember> &members,
}
}
- m_colorOut->writePrefixedMessage(QString::fromLatin1(
- "Property \"%1\" not found on type \"%2\" at %3:%4:%5\n")
- .arg(access.m_name)
- .arg(scope->internalName().isEmpty()
- ? scope->baseTypeName() : scope->internalName())
- .arg(m_fileName)
- .arg(access.m_location.startLine)
- .arg(access.m_location.startColumn), Warning);
- printContext(m_code, m_colorOut, access.m_location);
- return false;
+ m_logger->log(QLatin1String(
+ "Property \"%1\" not found on type \"%2\"")
+ .arg(access.m_name)
+ .arg(scope->internalName().isEmpty()
+ ? scope->baseTypeName() : scope->internalName()), Log_Type, access.m_location);
+ return;
}
-
- return true;
}
-bool CheckIdentifiers::operator()(
+void CheckIdentifiers::operator()(
const QHash<QString, QQmlJSScope::ConstPtr> &qmlIDs,
const QHash<QQmlJS::SourceLocation, SignalHandler> &signalHandlers,
const MemberAccessChains &memberAccessChains,
const QQmlJSScope::ConstPtr &root, const QString &rootId) const
{
- bool identifiersClean = true;
-
// revisit all scopes
QQueue<QQmlJSScope::ConstPtr> workQueue;
workQueue.enqueue(root);
@@ -332,17 +263,14 @@ bool CheckIdentifiers::operator()(
const auto jsId = currentScope->findJSIdentifier(memberAccessBase.m_name);
if (jsId.has_value() && jsId->kind != QQmlJSScope::JavaScriptIdentifier::Injected) {
if (memberAccessBase.m_location.end() < jsId->location.begin()) {
- m_colorOut->writePrefixedMessage(
+ // TODO: Is there a more fitting category?
+ m_logger->log(
QStringLiteral(
- "Variable \"%1\" is used before its declaration at %2:%3. "
+ "Variable \"%1\" is used here before its declaration. "
"The declaration is at %4:%5.\n")
- .arg(memberAccessBase.m_name)
- .arg(memberAccessBase.m_location.startLine)
- .arg(memberAccessBase.m_location.startColumn)
- .arg(jsId->location.startLine)
- .arg(jsId->location.startColumn), Warning);
- printContext(m_code, m_colorOut, memberAccessBase.m_location);
- identifiersClean = false;
+ .arg(memberAccessBase.m_name)
+ .arg(jsId->location.startLine)
+ .arg(jsId->location.startColumn), Log_Type, memberAccessBase.m_location);
}
continue;
}
@@ -350,8 +278,7 @@ bool CheckIdentifiers::operator()(
auto it = qmlIDs.find(memberAccessBase.m_name);
if (it != qmlIDs.end()) {
if (!it->isNull()) {
- if (!checkMemberAccess(memberAccessChain, *it))
- identifiersClean = false;
+ checkMemberAccess(memberAccessChain, *it);
continue;
} else if (!memberAccessChain.isEmpty()) {
// It could be a qualified type name
@@ -362,8 +289,7 @@ bool CheckIdentifiers::operator()(
const auto typeIt = m_types.find(qualified);
if (typeIt != m_types.end()) {
memberAccessChain.takeFirst();
- if (!checkMemberAccess(memberAccessChain, *typeIt))
- identifiersClean = false;
+ checkMemberAccess(memberAccessChain, *typeIt);
continue;
}
}
@@ -388,14 +314,7 @@ bool CheckIdentifiers::operator()(
if (!deprecation.reason.isEmpty())
message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
- message.append(QStringLiteral(" at %2:%3:%4")
- .arg(m_fileName)
- .arg(memberAccessBase.m_location.startLine)
- .arg(memberAccessBase.m_location.startColumn)
- );
-
- m_colorOut->writePrefixedMessage(message, Warning);
- identifiersClean = false;
+ m_logger->log(message, Log_Deprecation, memberAccessBase.m_location);
}
}
@@ -403,16 +322,11 @@ bool CheckIdentifiers::operator()(
continue;
if (!property.type()) {
- m_colorOut->writePrefixedMessage(QString::fromLatin1(
- "Type of property \"%2\" not found at %3:%4:%5\n")
- .arg(memberAccessBase.m_name)
- .arg(m_fileName)
- .arg(memberAccessBase.m_location.startLine)
- .arg(memberAccessBase.m_location.startColumn), Warning);
- printContext(m_code, m_colorOut, memberAccessBase.m_location);
- identifiersClean = false;
- } else if (!checkMemberAccess(memberAccessChain, property.type(), &property)) {
- identifiersClean = false;
+ m_logger->log(QString::fromLatin1(
+ "Type of property \"%2\" not found")
+ .arg(memberAccessBase.m_name), Log_Type, memberAccessBase.m_location);
+ } else {
+ checkMemberAccess(memberAccessChain, property.type(), &property);
}
continue;
@@ -436,82 +350,79 @@ bool CheckIdentifiers::operator()(
}
if (typeIt != m_types.end() && !typeIt->isNull()) {
- if (!checkMemberAccess(memberAccessChain, *typeIt))
- identifiersClean = false;
+ checkMemberAccess(memberAccessChain, *typeIt);
continue;
}
- identifiersClean = false;
const auto location = memberAccessBase.m_location;
if (baseIsPrefixed) {
- m_colorOut->writePrefixedMessage(
- QString::fromLatin1("type not found in namespace at %1:%2:%3\n")
- .arg(m_fileName)
- .arg(location.startLine).arg(location.startColumn),
- Warning);
+ m_logger->log(
+ QLatin1String("Type not found in namespace"),
+ Log_Type, location);
} else {
- m_colorOut->writePrefixedMessage(
- QString::fromLatin1("unqualified access at %1:%2:%3\n")
- .arg(m_fileName)
- .arg(location.startLine).arg(location.startColumn),
- Warning);
+ m_logger->log(
+ QLatin1String("Unqualified access"),
+ Log_UnqualifiedAccess, location);
}
- printContext(m_code, m_colorOut, location);
-
// root(JS) --> (first element)
const auto firstElement = root->childScopes()[0];
- if (firstElement->hasProperty(memberAccessBase.m_name)
+
+ QColorOutput &colorOut = m_logger->colorOutput();
+
+ if (!m_logger->isCategorySilent(Log_UnqualifiedAccess) &&
+ (firstElement->hasProperty(memberAccessBase.m_name)
|| firstElement->hasMethod(memberAccessBase.m_name)
- || firstElement->hasEnumeration(memberAccessBase.m_name)) {
- m_colorOut->writePrefixedMessage(
+ || firstElement->hasEnumeration(memberAccessBase.m_name))) {
+
+ colorOut.writePrefixedMessage(
memberAccessBase.m_name
+ QLatin1String(" is a member of the root element\n")
+ QLatin1String(" You can qualify the access with its id "
"to avoid this warning:\n"),
- Info, QStringLiteral("Note"));
+ QtInfoMsg, QStringLiteral("Note"));
+ IssueLocationWithContext issueLocationWithContext {m_code, location};
+ colorOut.write(issueLocationWithContext.beforeText().toString());
+ colorOut.write(rootId + QLatin1Char('.'), QtDebugMsg);
+ colorOut.write(issueLocationWithContext.issueText().toString());
+ colorOut.write(issueLocationWithContext.afterText() + QLatin1String("\n\n"));
+
if (rootId == QLatin1String("<id>")) {
- m_colorOut->writePrefixedMessage(
+ colorOut.writePrefixedMessage(
QLatin1String("You first have to give the root element an id\n"),
- Warning, QStringLiteral("Note"));
+ QtInfoMsg, QStringLiteral("Note"));
}
- IssueLocationWithContext issueLocationWithContext {m_code, location};
- m_colorOut->write(issueLocationWithContext.beforeText(), Normal);
- m_colorOut->write(rootId + QLatin1Char('.'), Hint);
- m_colorOut->write(issueLocationWithContext.issueText(), Normal);
- m_colorOut->write(issueLocationWithContext.afterText() + QLatin1Char('\n'), Normal);
} else if (jsId.has_value()
&& jsId->kind == QQmlJSScope::JavaScriptIdentifier::Injected) {
const QQmlJSScope::JavaScriptIdentifier id = jsId.value();
- m_colorOut->writePrefixedMessage(
+ colorOut.writePrefixedMessage(
memberAccessBase.m_name + QString::fromLatin1(
" is accessible in this scope because "
"you are handling a signal at %1:%2:%3\n")
.arg(m_fileName)
.arg(id.location.startLine).arg(id.location.startColumn),
- Info, QStringLiteral("Note"));
- m_colorOut->write(QLatin1String("Consider using a function instead\n"), Normal);
+ QtInfoMsg, QStringLiteral("Note"));
+ colorOut.write(QLatin1String("Consider using a function instead\n"));
IssueLocationWithContext context {m_code, id.location};
- m_colorOut->write(context.beforeText() + QLatin1Char(' '));
+ colorOut.write(context.beforeText() + QLatin1Char(' '));
const auto handler = signalHandlers[id.location];
- m_colorOut->write(QLatin1String(handler.isMultiline ? "function(" : "("), Hint);
+ colorOut.write(QLatin1String(handler.isMultiline ? "function(" : "("), QtInfoMsg);
const auto parameters = handler.signal.parameterNames();
for (int numParams = parameters.size(); numParams > 0; --numParams) {
- m_colorOut->write(parameters.at(parameters.size() - numParams), Hint);
+ colorOut.write(parameters.at(parameters.size() - numParams), QtInfoMsg);
if (numParams > 1)
- m_colorOut->write(QLatin1String(", "), Hint);
+ colorOut.write(QLatin1String(", "), QtInfoMsg);
}
- m_colorOut->write(QLatin1String(handler.isMultiline ? ")" : ") => "), Hint);
- m_colorOut->write(QLatin1String(" {..."), Normal);
+ colorOut.write(QLatin1String(handler.isMultiline ? ")" : ") => "), QtInfoMsg);
+ colorOut.write(QLatin1String(" {..."));
}
- m_colorOut->write(QLatin1String("\n\n\n"), Normal);
+ colorOut.write(QLatin1String("\n\n\n"));
}
const auto childScopes = currentScope->childScopes();
for (auto const &childScope : childScopes)
workQueue.enqueue(childScope);
}
- return identifiersClean;
}
diff --git a/tools/qmllint/checkidentifiers.h b/tools/qmllint/checkidentifiers.h
index f4fd8c9f14..c23a64f9bd 100644
--- a/tools/qmllint/checkidentifiers.h
+++ b/tools/qmllint/checkidentifiers.h
@@ -29,10 +29,11 @@
#ifndef CHECKIDENTIFIERS_H
#define CHECKIDENTIFIERS_H
+#include <QtQmlCompiler/private/qqmljslogger_p.h>
#include <QtQmlCompiler/private/qqmljsscope_p.h>
#include <QtQmlCompiler/private/qqmljsimporter_p.h>
-class ColorOutput;
+class QColorOutput;
struct SignalHandler {
QQmlJSMetaMethod signal;
@@ -51,25 +52,22 @@ using MemberAccessChains = QHash<QQmlJSScope::ConstPtr, QVector<QVector<FieldMem
class CheckIdentifiers
{
public:
- CheckIdentifiers(ColorOutput *colorOut, const QString &code,
+ CheckIdentifiers(QQmlJSLogger *logger, const QString &code,
const QQmlJSImporter::ImportedTypes &types, const QString &fileName) :
- m_colorOut(colorOut), m_code(code), m_types(types), m_fileName(fileName)
+ m_logger(logger), m_code(code), m_types(types), m_fileName(fileName)
{}
- bool operator ()(const QHash<QString, QQmlJSScope::ConstPtr> &qmlIDs,
+ void operator ()(const QHash<QString, QQmlJSScope::ConstPtr> &qmlIDs,
const QHash<QQmlJS::SourceLocation, SignalHandler> &signalHandlers,
const MemberAccessChains &memberAccessChains,
const QQmlJSScope::ConstPtr &root, const QString &rootId) const;
- static void printContext(const QString &code, ColorOutput *output,
- const QQmlJS::SourceLocation &location);
-
private:
- bool checkMemberAccess(const QVector<FieldMember> &members,
+ void checkMemberAccess(const QVector<FieldMember> &members,
const QQmlJSScope::ConstPtr &outerScope,
const QQmlJSMetaProperty *prop = nullptr) const;
- ColorOutput *m_colorOut = nullptr;
+ QQmlJSLogger *m_logger = nullptr;
QString m_code;
QQmlJSImporter::ImportedTypes m_types;
QString m_fileName;
diff --git a/tools/qmllint/findwarnings.cpp b/tools/qmllint/findwarnings.cpp
index dd87293eb6..67d40e8a1d 100644
--- a/tools/qmllint/findwarnings.cpp
+++ b/tools/qmllint/findwarnings.cpp
@@ -59,11 +59,8 @@ void FindWarningVisitor::checkInheritanceCycle(QQmlJSScope::ConstPtr scope)
if (!deprecation.reason.isEmpty())
message.append(QStringLiteral(" (Reason: %1)").arg(deprecation.reason));
- m_errors.append({
- message,
- QtWarningMsg,
- originalScope->sourceLocation()
- });
+ m_logger.log(message, Log_Deprecation, originalScope->sourceLocation()
+ );
}
}
@@ -75,15 +72,9 @@ void FindWarningVisitor::checkInheritanceCycle(QQmlJSScope::ConstPtr scope)
inheritenceCycle.append(seen->baseTypeName());
}
- if (m_warnInheritanceCycle) {
- m_errors.append({
- QStringLiteral("%1 is part of an inheritance cycle: %2\n")
- .arg(scope->internalName())
- .arg(inheritenceCycle),
- QtWarningMsg,
- QQmlJS::SourceLocation()
- });
- }
+ m_logger.log(QStringLiteral("%1 is part of an inheritance cycle: %2\n")
+ .arg(scope->internalName())
+ .arg(inheritenceCycle), Log_InheritanceCycle);
m_unknownImports.insert(scope->internalName());
break;
@@ -96,12 +87,9 @@ void FindWarningVisitor::checkInheritanceCycle(QQmlJSScope::ConstPtr scope)
} else if (auto newScope = scope->baseType()) {
scope = newScope;
} else {
- m_errors.append({
- scope->baseTypeName() + QStringLiteral(
+ m_logger.log(scope->baseTypeName() + QStringLiteral(
" was not found. Did you add all import paths?\n"),
- QtWarningMsg,
- QQmlJS::SourceLocation()
- });
+ Log_Import);
m_unknownImports.insert(scope->baseTypeName());
break;
}
@@ -118,15 +106,15 @@ void FindWarningVisitor::checkGroupedAndAttachedScopes(QQmlJSScope::ConstPtr sco
case QQmlJSScope::GroupedPropertyScope:
case QQmlJSScope::AttachedPropertyScope:
if (!childScope->baseType()) {
- m_errors.append({
- QStringLiteral("unknown %1 property scope %2.")
- .arg(type == QQmlJSScope::GroupedPropertyScope
- ? QStringLiteral("grouped")
- : QStringLiteral("attached"),
- childScope->internalName()),
- QtWarningMsg,
- childScope->sourceLocation()
- });
+ m_logger.log(
+ QStringLiteral("unknown %1 property scope %2.")
+ .arg(type == QQmlJSScope::GroupedPropertyScope
+ ? QStringLiteral("grouped")
+ : QStringLiteral("attached"),
+ childScope->internalName()),
+ Log_UnqualifiedAccess,
+ childScope->sourceLocation()
+ );
}
children.append(childScope->childScopes());
default:
@@ -165,8 +153,8 @@ void FindWarningVisitor::checkDefaultProperty(const QQmlJSScope::ConstPtr &scope
}
}
if (defaultPropertyName.isEmpty()) {
- m_errors.append({ QStringLiteral("Cannot assign to non-existent default property"),
- QtWarningMsg, scope->sourceLocation() });
+ m_logger.log(QStringLiteral("Cannot assign to non-existent default property"),
+ Log_Property, scope->sourceLocation() );
return;
}
@@ -179,9 +167,8 @@ void FindWarningVisitor::checkDefaultProperty(const QQmlJSScope::ConstPtr &scope
if (m_scopeHasDefaultPropertyAssignment[scopeOfDefaultProperty] && !defaultProp.isList()) {
// already has some object assigned to a default property and
// this default property is not a list property
- m_errors.append(
- { QStringLiteral("Cannot assign multiple objects to a default non-list property"),
- QtWarningMsg, scope->sourceLocation() });
+ m_logger.log(QStringLiteral("Cannot assign multiple objects to a default non-list property"),
+ Log_Property, scope->sourceLocation());
}
m_scopeHasDefaultPropertyAssignment[scopeOfDefaultProperty] = true;
@@ -195,8 +182,8 @@ void FindWarningVisitor::checkDefaultProperty(const QQmlJSScope::ConstPtr &scope
return;
}
- m_errors.append({ QStringLiteral("Cannot assign to default property of incompatible type"),
- QtWarningMsg, scope->sourceLocation() });
+ m_logger.log(QStringLiteral("Cannot assign to default property of incompatible type"),
+ Log_Property, scope->sourceLocation());
}
void FindWarningVisitor::throwRecursionDepthError()
@@ -232,16 +219,12 @@ bool FindWarningVisitor::visit(QQmlJS::AST::Block *block)
bool FindWarningVisitor::visit(QQmlJS::AST::WithStatement *withStatement)
{
- if (m_warnWithStatement) {
- m_errors.append({
- QStringLiteral(
- "with statements are strongly discouraged in QML "
+ m_logger.log(QStringLiteral(
+ "with statements are strongly discouraged in QML "
"and might cause false positives when analysing unqualified "
"identifiers\n"),
- QtWarningMsg,
- withStatement->firstSourceLocation()
- });
- }
+ Log_WithStatement,
+ withStatement->firstSourceLocation());
return QQmlJSImportVisitor::visit(withStatement);
}
@@ -295,37 +278,38 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
}
if (!qmlScope->hasProperty(name.toString())) {
- m_errors.append({
- QStringLiteral("Binding assigned to \"%1\", but no property \"%1\" "
+ // TODO: Can this be in a better suited category?
+ m_logger.log(
+ QStringLiteral("Binding assigned to \"%1\", but no property \"%1\" "
"exists in the current element.\n").arg(name),
- QtWarningMsg,
- uisb->firstSourceLocation()
- });
+ Log_Type,
+ uisb->firstSourceLocation()
+ );
return true;
}
const auto property = qmlScope->property(name.toString());
if (!property.type()) {
- m_errors.append({
- QStringLiteral("No type found for property \"%1\". This may be due "
+ m_logger.log(
+ QStringLiteral("No type found for property \"%1\". This may be due "
"to a missing import statement or incomplete "
"qmltypes files.\n").arg(name),
- QtWarningMsg,
- uisb->firstSourceLocation()
- });
+ Log_Type,
+ uisb->firstSourceLocation()
+ );
}
return true;
}
- if (!qmlScope->hasMethod(signal) && m_warnUnqualified) {
- m_errors.append({
- QStringLiteral("no matching signal found for handler \"%1\"\n")
- .arg(name.toString()),
- QtWarningMsg,
- uisb->firstSourceLocation()
- });
+ if (!qmlScope->hasMethod(signal)) {
+ m_logger.log(
+ QStringLiteral("no matching signal found for handler \"%1\"\n")
+ .arg(name.toString()),
+ Log_UnqualifiedAccess,
+ uisb->firstSourceLocation()
+ );
return true;
}
@@ -352,13 +336,13 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
for (FormalParameterList *formal = func->formals;
formal; ++i, formal = formal->next) {
if (i == end) {
- m_errors.append({
- QStringLiteral("Signal handler for \"%2\" has more formal"
+ m_logger.log(
+ QStringLiteral("Signal handler for \"%2\" has more formal"
" parameters than the signal it handles.")
- .arg(name),
- QtWarningMsg,
- uisb->firstSourceLocation()
- });
+ .arg(name),
+ Log_Signal,
+ uisb->firstSourceLocation()
+ );
}
const QStringView handlerParameter = formal->element->bindingIdentifier;
@@ -366,14 +350,14 @@ bool FindWarningVisitor::visit(QQmlJS::AST::UiScriptBinding *uisb)
if (j == i || j < 0)
continue;
- m_errors.append({
- QStringLiteral("Parameter %1 to signal handler for \"%2\""
+ m_logger.log(
+ QStringLiteral("Parameter %1 to signal handler for \"%2\""
" is called \"%3\". The signal has a parameter"
" of the same name in position %4.\n")
- .arg(i + 1).arg(name, handlerParameter).arg(j + 1),
- QtWarningMsg,
- uisb->firstSourceLocation()
- });
+ .arg(i + 1).arg(name, handlerParameter).arg(j + 1),
+ Log_Signal,
+ uisb->firstSourceLocation()
+ );
}
return true;
@@ -403,26 +387,16 @@ bool FindWarningVisitor::visit(QQmlJS::AST::IdentifierExpression *idexp)
FindWarningVisitor::FindWarningVisitor(
QQmlJSImporter *importer, QStringList qmltypesFiles, QString code, QString fileName,
- bool silent, bool warnUnqualified, bool warnWithStatement, bool warnInheritanceCycle)
+ bool silent)
: QQmlJSImportVisitor(importer,
implicitImportDirectory(fileName, importer->resourceFileMapper()),
- qmltypesFiles),
+ qmltypesFiles, m_filePath, m_code, silent),
m_code(std::move(code)),
m_rootId(QLatin1String("<id>")),
- m_filePath(std::move(fileName)),
- m_colorOut(silent),
- m_warnUnqualified(warnUnqualified),
- m_warnWithStatement(warnWithStatement),
- m_warnInheritanceCycle(warnInheritanceCycle)
+ m_filePath(std::move(fileName))
{
m_currentScope->setInternalName("global");
- // setup color output
- m_colorOut.insertMapping(Error, ColorOutput::RedForeground);
- m_colorOut.insertMapping(Warning, ColorOutput::PurpleForeground);
- m_colorOut.insertMapping(Info, ColorOutput::BlueForeground);
- m_colorOut.insertMapping(Normal, ColorOutput::DefaultColor);
- m_colorOut.insertMapping(Hint, ColorOutput::GreenForeground);
QLatin1String jsGlobVars[] = {
/* Not listed on the MDN page; browser and QML extensions: */
// console/debug api
@@ -449,36 +423,8 @@ FindWarningVisitor::FindWarningVisitor(
m_currentScope->insertJSIdentifier(jsGlobVar, globalJavaScript);
}
-static MessageColors messageColor(QtMsgType type)
-{
- switch (type) {
- case QtDebugMsg:
- return Normal;
- case QtWarningMsg:
- return Warning;
- case QtCriticalMsg:
- case QtFatalMsg:
- return Error;
- case QtInfoMsg:
- return Info;
- }
-
- return Normal;
-}
-
bool FindWarningVisitor::check()
{
- for (const auto &error : qAsConst(m_errors)) {
- if (error.loc.isValid()) {
- m_colorOut.writePrefixedMessage(
- QStringLiteral("%1:%2: %3")
- .arg(error.loc.startLine).arg(error.loc.startColumn).arg(error.message),
- messageColor(error.type));
- } else {
- m_colorOut.writePrefixedMessage(error.message, messageColor(error.type));
- }
- }
-
// now that all ids are known, revisit any Connections whose target were perviously unknown
for (auto const &outstandingConnection: m_outstandingConnections) {
auto targetScope = m_scopesById[outstandingConnection.targetName];
@@ -505,20 +451,17 @@ bool FindWarningVisitor::check()
}
for (const auto &import : unusedImports) {
- m_colorOut.writePrefixedMessage(
+ m_logger.log(
QString::fromLatin1("Unused import at %1:%2:%3\n")
- .arg(m_filePath)
- .arg(import.startLine).arg(import.startColumn),
- Info);
- CheckIdentifiers::printContext(m_code, &m_colorOut, import);
+ .arg(m_filePath)
+ .arg(import.startLine).arg(import.startColumn),
+ Log_UnusedImport, import);
}
- if (!m_warnUnqualified)
- return m_errors.isEmpty();
+ CheckIdentifiers check(&m_logger, m_code, m_rootScopeImports, m_filePath);
+ check(m_scopesById, m_signalHandlers, m_memberAccessChains, m_globalScope, m_rootId);
- CheckIdentifiers check(&m_colorOut, m_code, m_rootScopeImports, m_filePath);
- return check(m_scopesById, m_signalHandlers, m_memberAccessChains, m_globalScope, m_rootId)
- && m_errors.isEmpty();
+ return !m_logger.hasWarnings() && !m_logger.hasErrors();
}
bool FindWarningVisitor::visit(QQmlJS::AST::UiObjectBinding *uiob)
@@ -617,8 +560,7 @@ void FindWarningVisitor::endVisit(QQmlJS::AST::UiObjectDefinition *uiod)
auto childScope = m_currentScope;
QQmlJSImportVisitor::endVisit(uiod);
- if (m_warnUnqualified)
- checkGroupedAndAttachedScopes(childScope);
+ checkGroupedAndAttachedScopes(childScope);
if (m_currentScope == m_globalScope
|| m_currentScope->baseTypeName() == QStringLiteral("Component")) {
diff --git a/tools/qmllint/findwarnings.h b/tools/qmllint/findwarnings.h
index 9d7e90f342..d5363a177b 100644
--- a/tools/qmllint/findwarnings.h
+++ b/tools/qmllint/findwarnings.h
@@ -39,9 +39,9 @@
//
// We mean it.
-#include "qcoloroutput.h"
#include "checkidentifiers.h"
+#include <QtQmlCompiler/private/qcoloroutput_p.h>
#include <QtQmlCompiler/private/qqmljstypedescriptionreader_p.h>
#include <QtQmlCompiler/private/qqmljsscope_p.h>
#include <QtQmlCompiler/private/qqmljsimporter_p.h>
@@ -59,7 +59,7 @@ class FindWarningVisitor : public QQmlJSImportVisitor
public:
explicit FindWarningVisitor(
QQmlJSImporter *importer, QStringList qmltypesFiles, QString code, QString fileName,
- bool silent, bool warnUnqualified, bool warnWithStatement, bool warnInheritanceCycle);
+ bool silent);
~FindWarningVisitor() override = default;
bool check();
@@ -74,11 +74,6 @@ private:
QString m_rootId;
QString m_filePath;
QSet<QString> m_unknownImports;
- ColorOutput m_colorOut;
-
- bool m_warnUnqualified;
- bool m_warnWithStatement;
- bool m_warnInheritanceCycle;
struct OutstandingConnection
{
diff --git a/tools/qmllint/main.cpp b/tools/qmllint/main.cpp
index 64388c78ae..c1befeb3e7 100644
--- a/tools/qmllint/main.cpp
+++ b/tools/qmllint/main.cpp
@@ -90,8 +90,12 @@ static bool lint_file(const QString &filename, const bool silent, const bool war
if (success && !isJavaScript) {
const auto check = [&](QQmlJSResourceFileMapper *mapper) {
QQmlJSImporter importer(qmlImportPaths, mapper);
- FindWarningVisitor v { &importer, qmltypesFiles, code, filename, silent,
- warnUnqualified, warnWithStatement, warnInheritanceCycle };
+ FindWarningVisitor v { &importer, qmltypesFiles, code, filename, silent };
+
+ v.logger().setCategorySilent(Log_WithStatement, !warnWithStatement);
+ v.logger().setCategorySilent(Log_InheritanceCycle, !warnInheritanceCycle);
+ v.logger().setCategorySilent(Log_UnqualifiedAccess, !warnUnqualified);
+
parser.rootNode()->accept(&v);
success = v.check();
};
diff --git a/tools/qmllint/qcoloroutput.cpp b/tools/qmllint/qcoloroutput.cpp
deleted file mode 100644
index 6e0a483050..0000000000
--- a/tools/qmllint/qcoloroutput.cpp
+++ /dev/null
@@ -1,336 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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 "qcoloroutput.h"
-
-#include <QtCore/qfile.h>
-#include <QtCore/qhash.h>
-
-#ifndef Q_OS_WIN
-#include <unistd.h>
-#endif
-
-class ColorOutputPrivate
-{
-public:
- ColorOutputPrivate(bool silent) : m_currentColorID(-1), m_silent(silent)
- {
- /* - QIODevice::Unbuffered because we want it to appear when the user actually calls,
- * performance is considered of lower priority.
- */
- m_out.open(stderr, QIODevice::WriteOnly | QIODevice::Unbuffered);
- m_coloringEnabled = isColoringPossible();
- }
-
- static const char *const foregrounds[];
- static const char *const backgrounds[];
-
- inline void write(const QString &msg) { m_out.write(msg.toLocal8Bit()); }
-
- static QString escapeCode(const QString &in)
- {
- const ushort escapeChar = 0x1B;
- QString result;
- result.append(QChar(escapeChar));
- result.append(QLatin1Char('['));
- result.append(in);
- result.append(QLatin1Char('m'));
- return result;
- }
-
- void insertColor(int id, ColorOutput::ColorCode code) { m_colorMapping.insert(id, code); }
- ColorOutput::ColorCode color(int id) const { return m_colorMapping.value(id); }
- bool containsColor(int id) const { return m_colorMapping.contains(id); }
-
- bool isSilent() const { return m_silent; }
- void setCurrentColorID(int colorId) { m_currentColorID = colorId; }
-
- bool coloringEnabled() const { return m_coloringEnabled; }
-
-private:
- QFile m_out;
- ColorOutput::ColorMapping m_colorMapping;
- int m_currentColorID;
- bool m_coloringEnabled;
- bool m_silent;
-
- /*!
- Returns true if it's suitable to send colored output to \c stderr.
- */
- inline bool isColoringPossible() const
- {
-#if defined(Q_OS_WIN)
- /* Windows doesn't at all support ANSI escape codes, unless
- * the user install a "device driver". See the Wikipedia links in the
- * class documentation for details. */
- return false;
-#else
- /* We use QFile::handle() to get the file descriptor. It's a bit unsure
- * whether it's 2 on all platforms and in all cases, so hopefully this layer
- * of abstraction helps handle such cases. */
- return isatty(m_out.handle());
-#endif
- }
-};
-
-const char *const ColorOutputPrivate::foregrounds[] =
-{
- "0;30",
- "0;34",
- "0;32",
- "0;36",
- "0;31",
- "0;35",
- "0;33",
- "0;37",
- "1;30",
- "1;34",
- "1;32",
- "1;36",
- "1;31",
- "1;35",
- "1;33",
- "1;37"
-};
-
-const char *const ColorOutputPrivate::backgrounds[] =
-{
- "0;40",
- "0;44",
- "0;42",
- "0;46",
- "0;41",
- "0;45",
- "0;43"
-};
-
-/*!
- \class ColorOutput
- \nonreentrant
- \brief Outputs colored messages to \c stderr.
- \internal
-
- ColorOutput is a convenience class for outputting messages to \c
- stderr using color escape codes, as mandated in ECMA-48. ColorOutput
- will only color output when it is detected to be suitable. For
- instance, if \c stderr is detected to be attached to a file instead
- of a TTY, no coloring will be done.
-
- ColorOutput does its best attempt. but it is generally undefined
- what coloring or effect the various coloring flags has. It depends
- strongly on what terminal software that is being used.
-
- When using `echo -e 'my escape sequence'`, \c{\033} works as an
- initiator but not when printing from a C++ program, despite having
- escaped the backslash. That's why we below use characters with
- value 0x1B.
-
- It can be convenient to subclass ColorOutput with a private scope,
- such that the functions are directly available in the class using
- it.
-
- \section1 Usage
-
- To output messages, call write() or writeUncolored(). write() takes
- as second argument an integer, which ColorOutput uses as a lookup
- key to find the color it should color the text in. The mapping from
- keys to colors is done using insertMapping(). Typically this is used
- by having enums for the various kinds of messages, which
- subsequently are registered.
-
- \code
- enum MyMessage
- {
- Error,
- Important
- };
-
- ColorOutput output;
- output.insertMapping(Error, ColorOutput::RedForeground);
- output.insertMapping(Import, ColorOutput::BlueForeground);
-
- output.write("This is important", Important);
- output.write("Jack, I'm only the selected official!", Error);
- \endcode
-
- \sa {http://tldp.org/HOWTO/Bash-Prompt-HOWTO/x329.html}{Bash Prompt HOWTO, 6.1. Colors},
- {http://linuxgazette.net/issue51/livingston-blade.html}{Linux Gazette, Tweaking Eterm, Edward Livingston-Blade},
- {http://www.ecma-international.org/publications/standards/Ecma-048.htm}{Standard ECMA-48, Control Functions for Coded Character Sets, ECMA International},
- {http://en.wikipedia.org/wiki/ANSI_escape_code}{Wikipedia, ANSI escape code},
- {http://linuxgazette.net/issue65/padala.html}{Linux Gazette, So You Like Color!, Pradeep Padala}
- */
-
-/*!
- \enum ColorOutput::ColorCodeComponent
- \value BlackForeground
- \value BlueForeground
- \value GreenForeground
- \value CyanForeground
- \value RedForeground
- \value PurpleForeground
- \value BrownForeground
- \value LightGrayForeground
- \value DarkGrayForeground
- \value LightBlueForeground
- \value LightGreenForeground
- \value LightCyanForeground
- \value LightRedForeground
- \value LightPurpleForeground
- \value YellowForeground
- \value WhiteForeground
- \value BlackBackground
- \value BlueBackground
- \value GreenBackground
- \value CyanBackground
- \value RedBackground
- \value PurpleBackground
- \value BrownBackground
-
- \value DefaultColor ColorOutput performs no coloring. This typically
- means black on white or white on black, depending
- on the settings of the user's terminal.
- */
-
-/*!
- Constructs a ColorOutput instance, ready for use.
- */
-ColorOutput::ColorOutput(bool silent) : d(new ColorOutputPrivate(silent)) {}
-
-// must be here so that QScopedPointer has access to the complete type
-ColorOutput::~ColorOutput() = default;
-
-/*!
- Sends \a message to \c stderr, using the color looked up in the color mapping using \a colorID.
-
- If \a color isn't available in the color mapping, result and behavior is undefined.
-
- If \a colorID is 0, which is the default value, the previously used coloring is used. ColorOutput
- is initialized to not color at all.
-
- If \a message is empty, effects are undefined.
-
- \a message will be printed as is. For instance, no line endings will be inserted.
- */
-void ColorOutput::write(QStringView message, int colorID)
-{
- if (!d->isSilent())
- d->write(colorify(message, colorID));
-}
-
-void ColorOutput::writePrefixedMessage(const QString &message, MessageColors type,
- const QString &prefix)
-{
- static const QStringList prefixes = {
- QStringLiteral("Error"),
- QStringLiteral("Warning"),
- QStringLiteral("Info"),
- QStringLiteral("Normal"),
- QStringLiteral("Hint"),
- };
-
- Q_ASSERT(prefixes.length() > qsizetype(type));
- Q_ASSERT(prefix.isEmpty() || prefix.front().isUpper());
- write((prefix.isEmpty() ? prefixes[type] : prefix) + QStringLiteral(": "), type);
- writeUncolored(message);
-}
-
-/*!
- Writes \a message to \c stderr as if for instance
- QTextStream would have been used, and adds a line ending at the end.
-
- This function can be practical to use such that one can use ColorOutput for all forms of writing.
- */
-void ColorOutput::writeUncolored(const QString &message)
-{
- if (!d->isSilent())
- d->write(message + QLatin1Char('\n'));
-}
-
-/*!
- Treats \a message and \a colorID identically to write(), but instead of writing
- \a message to \c stderr, it is prepared for being written to \c stderr, but is then
- returned.
-
- This is useful when the colored string is inserted into a translated string(dividing
- the string into several small strings prevents proper translation).
- */
-QString ColorOutput::colorify(QStringView message, int colorID) const
-{
- Q_ASSERT_X(colorID == -1 || d->containsColor(colorID), Q_FUNC_INFO,
- qPrintable(QString::fromLatin1("There is no color registered by id %1")
- .arg(colorID)));
- Q_ASSERT_X(!message.isEmpty(), Q_FUNC_INFO,
- "It makes no sense to attempt to print an empty string.");
-
- if (colorID != -1)
- d->setCurrentColorID(colorID);
-
- if (d->coloringEnabled() && colorID != -1) {
- const int color = d->color(colorID);
-
- /* If DefaultColor is set, we don't want to color it. */
- if (color & DefaultColor)
- return message.toString();
-
- const int foregroundCode = (color & ForegroundMask) >> ForegroundShift;
- const int backgroundCode = (color & BackgroundMask) >> BackgroundShift;
- QString finalMessage;
- bool closureNeeded = false;
-
- if (foregroundCode > 0) {
- finalMessage.append(
- ColorOutputPrivate::escapeCode(
- QLatin1String(ColorOutputPrivate::foregrounds[foregroundCode - 1])));
- closureNeeded = true;
- }
-
- if (backgroundCode > 0) {
- finalMessage.append(
- ColorOutputPrivate::escapeCode(
- QLatin1String(ColorOutputPrivate::backgrounds[backgroundCode - 1])));
- closureNeeded = true;
- }
-
- finalMessage.append(message);
-
- if (closureNeeded)
- finalMessage.append(ColorOutputPrivate::escapeCode(QLatin1String("0")));
-
- return finalMessage;
- }
-
- return message.toString();
-}
-
-/*!
- Adds a color mapping from \a colorID to \a colorCode, for this ColorOutput instance.
- */
-void ColorOutput::insertMapping(int colorID, const ColorCode colorCode)
-{
- d->insertColor(colorID, colorCode);
-}
diff --git a/tools/qmllint/qcoloroutput.h b/tools/qmllint/qcoloroutput.h
deleted file mode 100644
index 3b171da631..0000000000
--- a/tools/qmllint/qcoloroutput.h
+++ /dev/null
@@ -1,121 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 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$
-**
-****************************************************************************/
-
-#ifndef QCOLOROUTPUT_H
-#define QCOLOROUTPUT_H
-
-//
-// W A R N I N G
-// -------------
-//
-// This file is not part of the Qt API. It exists purely as an
-// implementation detail. This header file may change from version to
-// version without notice, or even be removed.
-//
-// We mean it.
-
-#include <QtCore/qglobal.h>
-#include <QtCore/qscopedpointer.h>
-#include <QtCore/qstring.h>
-
-class ColorOutputPrivate;
-
-enum MessageColors
-{
- Error,
- Warning,
- Info,
- Normal,
- Hint
-};
-
-class ColorOutput
-{
- enum
- {
- ForegroundShift = 10,
- BackgroundShift = 20,
- SpecialShift = 20,
- ForegroundMask = 0x1f << ForegroundShift,
- BackgroundMask = 0x7 << BackgroundShift
- };
-
-public:
- enum ColorCodeComponent
- {
- BlackForeground = 1 << ForegroundShift,
- BlueForeground = 2 << ForegroundShift,
- GreenForeground = 3 << ForegroundShift,
- CyanForeground = 4 << ForegroundShift,
- RedForeground = 5 << ForegroundShift,
- PurpleForeground = 6 << ForegroundShift,
- BrownForeground = 7 << ForegroundShift,
- LightGrayForeground = 8 << ForegroundShift,
- DarkGrayForeground = 9 << ForegroundShift,
- LightBlueForeground = 10 << ForegroundShift,
- LightGreenForeground = 11 << ForegroundShift,
- LightCyanForeground = 12 << ForegroundShift,
- LightRedForeground = 13 << ForegroundShift,
- LightPurpleForeground = 14 << ForegroundShift,
- YellowForeground = 15 << ForegroundShift,
- WhiteForeground = 16 << ForegroundShift,
-
- BlackBackground = 1 << BackgroundShift,
- BlueBackground = 2 << BackgroundShift,
- GreenBackground = 3 << BackgroundShift,
- CyanBackground = 4 << BackgroundShift,
- RedBackground = 5 << BackgroundShift,
- PurpleBackground = 6 << BackgroundShift,
- BrownBackground = 7 << BackgroundShift,
- DefaultColor = 1 << SpecialShift
- };
-
- using ColorCode = QFlags<ColorCodeComponent>;
- using ColorMapping = QHash<int, ColorCode>;
-
- ColorOutput(bool silent);
- ~ColorOutput();
-
- void insertMapping(int colorID, ColorCode colorCode);
-
- void writeUncolored(const QString &message);
- void write(QStringView message, int color = -1);
- // handle QStringBuilder case
- Q_WEAK_OVERLOAD void write(const QString &message, int color = -1) { write(QStringView(message), color); }
- void writePrefixedMessage(const QString &message, MessageColors type,
- const QString &prefix = QString());
- QString colorify(QStringView message, int color = -1) const;
-
-private:
- QScopedPointer<ColorOutputPrivate> d;
- Q_DISABLE_COPY_MOVE(ColorOutput)
-};
-
-Q_DECLARE_OPERATORS_FOR_FLAGS(ColorOutput::ColorCode)
-
-#endif // QCOLOROUTPUT_H