quicklintplugin: check color names
Implement the ErrInvalidColor warning in qmllint via the quick plugin, where literal strings assigned to colors are checked for correct color names. Add an assert in the constructor to make sure that the colors are sorted. We use a QStringList instead of a constexpr std::array to store the const list of color names because we need a QStringList for the "Did you mean" suggestions anyway. Task-number: QTBUG-129307 Change-Id: Ifbe0ce7f5158be7dae524889944f351184cc8559 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
0b0690b9cd
commit
53ccd32136
|
@ -44,8 +44,14 @@
|
|||
{
|
||||
"name": "attached-property-reuse",
|
||||
"settingsName": "AttachedPropertyReuse",
|
||||
"description": "Warn about failure to re-use any attached objects. Implies ControlsAttachedPropertyReuse.",
|
||||
"description":
|
||||
"Warn about failure to re-use any attached objects. Implies ControlsAttachedPropertyReuse.",
|
||||
"enabled": false
|
||||
},
|
||||
{
|
||||
"name": "color",
|
||||
"settingsName": "Color",
|
||||
"description": "Warn about invalid color values."
|
||||
}
|
||||
]
|
||||
}
|
||||
|
|
|
@ -3,6 +3,8 @@
|
|||
|
||||
#include "quicklintplugin.h"
|
||||
#include "qquickliteralbindingcheck_p.h"
|
||||
#include <QtQmlCompiler/private/qqmlsasourcelocation_p.h>
|
||||
#include <QtQmlCompiler/private/qqmljsutils_p.h>
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
|
||||
|
@ -16,6 +18,7 @@ static constexpr QQmlSA::LoggerWarningId quickUnexpectedVarType { "Quick.unexpec
|
|||
static constexpr QQmlSA::LoggerWarningId quickPropertyChangesParsed { "Quick.property-changes-parsed" };
|
||||
static constexpr QQmlSA::LoggerWarningId quickControlsAttachedPropertyReuse { "Quick.controls-attached-property-reuse" };
|
||||
static constexpr QQmlSA::LoggerWarningId quickAttachedPropertyReuse { "Quick.attached-property-reuse" };
|
||||
static constexpr QQmlSA::LoggerWarningId quickColor { "Quick.color" };
|
||||
|
||||
ForbiddenChildrenPropertyValidatorPass::ForbiddenChildrenPropertyValidatorPass(
|
||||
QQmlSA::PassManager *manager)
|
||||
|
@ -520,6 +523,203 @@ void VarBindingTypeValidatorPass::onBinding(const QQmlSA::Element &element,
|
|||
}
|
||||
}
|
||||
|
||||
class ColorValidatorPass : public QQmlSA::PropertyPass
|
||||
{
|
||||
public:
|
||||
ColorValidatorPass(QQmlSA::PassManager *manager);
|
||||
|
||||
void onBinding(const QQmlSA::Element &element, const QString &propertyName,
|
||||
const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope,
|
||||
const QQmlSA::Element &value) override;
|
||||
private:
|
||||
QQmlSA::Element m_colorType;
|
||||
|
||||
static inline const QRegularExpression s_hexPattern{ "^#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$"_L1 };
|
||||
// list taken from https://doc.qt.io/qt-6/qcolor.html#fromString
|
||||
QStringList m_colorNames = {
|
||||
u"aliceblue"_s,
|
||||
u"antiquewhite"_s,
|
||||
u"aqua"_s,
|
||||
u"aquamarine"_s,
|
||||
u"azure"_s,
|
||||
u"beige"_s,
|
||||
u"bisque"_s,
|
||||
u"black"_s,
|
||||
u"blanchedalmond"_s,
|
||||
u"blue"_s,
|
||||
u"blueviolet"_s,
|
||||
u"brown"_s,
|
||||
u"burlywood"_s,
|
||||
u"cadetblue"_s,
|
||||
u"chartreuse"_s,
|
||||
u"chocolate"_s,
|
||||
u"coral"_s,
|
||||
u"cornflowerblue"_s,
|
||||
u"cornsilk"_s,
|
||||
u"crimson"_s,
|
||||
u"cyan"_s,
|
||||
u"darkblue"_s,
|
||||
u"darkcyan"_s,
|
||||
u"darkgoldenrod"_s,
|
||||
u"darkgray"_s,
|
||||
u"darkgreen"_s,
|
||||
u"darkgrey"_s,
|
||||
u"darkkhaki"_s,
|
||||
u"darkmagenta"_s,
|
||||
u"darkolivegreen"_s,
|
||||
u"darkorange"_s,
|
||||
u"darkorchid"_s,
|
||||
u"darkred"_s,
|
||||
u"darksalmon"_s,
|
||||
u"darkseagreen"_s,
|
||||
u"darkslateblue"_s,
|
||||
u"darkslategray"_s,
|
||||
u"darkslategrey"_s,
|
||||
u"darkturquoise"_s,
|
||||
u"darkviolet"_s,
|
||||
u"deeppink"_s,
|
||||
u"deepskyblue"_s,
|
||||
u"dimgray"_s,
|
||||
u"dimgrey"_s,
|
||||
u"dodgerblue"_s,
|
||||
u"firebrick"_s,
|
||||
u"floralwhite"_s,
|
||||
u"forestgreen"_s,
|
||||
u"fuchsia"_s,
|
||||
u"gainsboro"_s,
|
||||
u"ghostwhite"_s,
|
||||
u"gold"_s,
|
||||
u"goldenrod"_s,
|
||||
u"gray"_s,
|
||||
u"green"_s,
|
||||
u"greenyellow"_s,
|
||||
u"grey"_s,
|
||||
u"honeydew"_s,
|
||||
u"hotpink"_s,
|
||||
u"indianred"_s,
|
||||
u"indigo"_s,
|
||||
u"ivory"_s,
|
||||
u"khaki"_s,
|
||||
u"lavender"_s,
|
||||
u"lavenderblush"_s,
|
||||
u"lawngreen"_s,
|
||||
u"lemonchiffon"_s,
|
||||
u"lightblue"_s,
|
||||
u"lightcoral"_s,
|
||||
u"lightcyan"_s,
|
||||
u"lightgoldenrodyellow"_s,
|
||||
u"lightgray"_s,
|
||||
u"lightgreen"_s,
|
||||
u"lightgrey"_s,
|
||||
u"lightpink"_s,
|
||||
u"lightsalmon"_s,
|
||||
u"lightseagreen"_s,
|
||||
u"lightskyblue"_s,
|
||||
u"lightslategray"_s,
|
||||
u"lightslategrey"_s,
|
||||
u"lightsteelblue"_s,
|
||||
u"lightyellow"_s,
|
||||
u"lime"_s,
|
||||
u"limegreen"_s,
|
||||
u"linen"_s,
|
||||
u"magenta"_s,
|
||||
u"maroon"_s,
|
||||
u"mediumaquamarine"_s,
|
||||
u"mediumblue"_s,
|
||||
u"mediumorchid"_s,
|
||||
u"mediumpurple"_s,
|
||||
u"mediumseagreen"_s,
|
||||
u"mediumslateblue"_s,
|
||||
u"mediumspringgreen"_s,
|
||||
u"mediumturquoise"_s,
|
||||
u"mediumvioletred"_s,
|
||||
u"midnightblue"_s,
|
||||
u"mintcream"_s,
|
||||
u"mistyrose"_s,
|
||||
u"moccasin"_s,
|
||||
u"navajowhite"_s,
|
||||
u"navy"_s,
|
||||
u"oldlace"_s,
|
||||
u"olive"_s,
|
||||
u"olivedrab"_s,
|
||||
u"orange"_s,
|
||||
u"orangered"_s,
|
||||
u"orchid"_s,
|
||||
u"palegoldenrod"_s,
|
||||
u"palegreen"_s,
|
||||
u"paleturquoise"_s,
|
||||
u"palevioletred"_s,
|
||||
u"papayawhip"_s,
|
||||
u"peachpuff"_s,
|
||||
u"peru"_s,
|
||||
u"pink"_s,
|
||||
u"plum"_s,
|
||||
u"powderblue"_s,
|
||||
u"purple"_s,
|
||||
u"red"_s,
|
||||
u"rosybrown"_s,
|
||||
u"royalblue"_s,
|
||||
u"saddlebrown"_s,
|
||||
u"salmon"_s,
|
||||
u"sandybrown"_s,
|
||||
u"seagreen"_s,
|
||||
u"seashell"_s,
|
||||
u"sienna"_s,
|
||||
u"silver"_s,
|
||||
u"skyblue"_s,
|
||||
u"slateblue"_s,
|
||||
u"slategray"_s,
|
||||
u"slategrey"_s,
|
||||
u"snow"_s,
|
||||
u"springgreen"_s,
|
||||
u"steelblue"_s,
|
||||
u"tan"_s,
|
||||
u"teal"_s,
|
||||
u"thistle"_s,
|
||||
u"tomato"_s,
|
||||
u"turquoise"_s,
|
||||
u"violet"_s,
|
||||
u"wheat"_s,
|
||||
u"white"_s,
|
||||
u"whitesmoke"_s,
|
||||
u"yellow"_s,
|
||||
u"yellowgreen"_s,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
ColorValidatorPass::ColorValidatorPass(QQmlSA::PassManager *manager)
|
||||
: PropertyPass(manager), m_colorType(resolveType("QtQuick"_L1, "color"_L1))
|
||||
{
|
||||
Q_ASSERT_X(std::is_sorted(m_colorNames.cbegin(), m_colorNames.cend()), "ColorValidatorPass",
|
||||
"m_colorNames should be sorted!");
|
||||
}
|
||||
|
||||
void ColorValidatorPass::onBinding(const QQmlSA::Element &element, const QString &propertyName,
|
||||
const QQmlSA::Binding &binding, const QQmlSA::Element &,
|
||||
const QQmlSA::Element &)
|
||||
{
|
||||
if (binding.bindingType() != QQmlSA::BindingType::StringLiteral)
|
||||
return;
|
||||
const auto propertyType = element.property(propertyName).type();
|
||||
if (!propertyType || propertyType != m_colorType)
|
||||
return;
|
||||
|
||||
const QString colorName = binding.stringValue();
|
||||
if (s_hexPattern.match(colorName).hasMatch())
|
||||
return;
|
||||
|
||||
if (std::binary_search(m_colorNames.cbegin(), m_colorNames.cend(), colorName))
|
||||
return;
|
||||
|
||||
auto suggestion = QQmlJSUtils::didYouMean(
|
||||
colorName, m_colorNames,
|
||||
QQmlSA::SourceLocationPrivate::sourceLocation(binding.sourceLocation()));
|
||||
|
||||
emitWarningWithOptionalFix(*this, "Invalid color \"%1\"."_L1.arg(colorName), quickColor,
|
||||
binding.sourceLocation(), suggestion);
|
||||
}
|
||||
|
||||
void AttachedPropertyReuse::onRead(const QQmlSA::Element &element, const QString &propertyName,
|
||||
const QQmlSA::Element &readScope,
|
||||
QQmlSA::SourceLocation location)
|
||||
|
@ -626,6 +826,8 @@ void QmlLintQuickPlugin::registerPasses(QQmlSA::PassManager *manager,
|
|||
manager->registerElementPass(std::make_unique<PropertyChangesValidatorPass>(manager));
|
||||
manager->registerPropertyPass(std::make_unique<QQuickLiteralBindingCheck>(manager),
|
||||
QAnyStringView(), QAnyStringView());
|
||||
manager->registerPropertyPass(std::make_unique<ColorValidatorPass>(manager),
|
||||
QAnyStringView(), QAnyStringView());
|
||||
|
||||
auto forbiddenChildProperty =
|
||||
std::make_unique<ForbiddenChildrenPropertyValidatorPass>(manager);
|
||||
|
|
|
@ -1359,6 +1359,23 @@ void TestQmllint::dirtyQmlSnippet_data()
|
|||
<< Result{ { { "Enum key 'World' has already been declared"_L1, 1, 28 },
|
||||
{ "Note: previous declaration of 'World' here"_L1, 1, 14 },
|
||||
{ "Enum keys should start with an uppercase"_L1, 1, 35 } } };
|
||||
|
||||
QTest::newRow("color-name") << u"property color myColor: \"lbue\""_s
|
||||
<< Result{ { { "Invalid color \"lbue\""_L1, 1, 25 } },
|
||||
{},
|
||||
{ { "Did you mean \"blue\"?", 1, 25 } } };
|
||||
QTest::newRow("color-hex") << u"property color myColor: \"#12345\""_s
|
||||
<< Result{ { { "Invalid color"_L1, 1, 25 } } };
|
||||
QTest::newRow("color-hex2") << u"property color myColor: \"#123456789\""_s
|
||||
<< Result{ { { "Invalid color"_L1, 1, 25 } } };
|
||||
QTest::newRow("color-hex3") << u"property color myColor: \"##123456\""_s
|
||||
<< Result{ { { "Invalid color"_L1, 1, 25 } } };
|
||||
QTest::newRow("color-hex4") << u"property color myColor: \"#123456#\""_s
|
||||
<< Result{ { { "Invalid color"_L1, 1, 25 } } };
|
||||
QTest::newRow("color-hex5") << u"property color myColor: \"#HELLOL\""_s
|
||||
<< Result{ { { "Invalid color"_L1, 1, 25 } } };
|
||||
QTest::newRow("color-hex6") << u"property color myColor: \"#1234567\""_s
|
||||
<< Result{ { { "Invalid color"_L1, 1, 25 } } };
|
||||
}
|
||||
|
||||
void TestQmllint::dirtyQmlSnippet()
|
||||
|
@ -1384,6 +1401,12 @@ void TestQmllint::cleanQmlSnippet_data()
|
|||
|
||||
QTest::newRow("testSnippet") << u"property int qwer: 123"_s;
|
||||
QTest::newRow("enum") << u"enum Hello { World, Kitty, DlroW }"_s;
|
||||
|
||||
QTest::newRow("color-name") << u"property color myColor: \"blue\""_s;
|
||||
QTest::newRow("color-name2") << u"property color myColor\nmyColor: \"green\""_s;
|
||||
QTest::newRow("color-hex") << u"property color myColor: \"#123456\""_s;
|
||||
QTest::newRow("color-hex2") << u"property color myColor: \"#FFFFFFFF\""_s;
|
||||
QTest::newRow("color-hex3") << u"property color myColor: \"#A0AAff1f\""_s;
|
||||
}
|
||||
|
||||
void TestQmllint::cleanQmlSnippet()
|
||||
|
|
Loading…
Reference in New Issue