31 if (!element.isNull())
55 for (
const auto &warning : elementPair.second) {
60 const auto firstBinding = bindings.
constBegin().value();
90 Warning{ elements, allowInDelegate, warning.toString() }) });
95void AttachedPropertyTypeValidatorPass::checkWarnings(
const QQmlSA::Element &element,
100 if (warning == m_attachedTypes.
cend())
107 if (warning->allowInDelegate) {
120 scopeUsedIn.parentScope().propertyBindings(u
"delegate"_s)) {
121 if (!binding.hasObject())
123 if (binding.objectType() == scopeUsedIn)
153 checkWarnings(element, readScope,
location);
165 checkWarnings(element, writeScope,
location);
172 ControlElement {
"Control",
173 QStringList {
"background",
"contentItem",
"leftPadding",
"rightPadding",
174 "topPadding",
"bottomPadding",
"horizontalPadding",
175 "verticalPadding",
"padding" },
177 ControlElement {
"Button",
QStringList {
"indicator" } },
180 QStringList {
"background",
"contentItem",
"header",
"footer",
"menuBar" } },
181 ControlElement {
"ComboBox",
QStringList {
"indicator" } },
182 ControlElement {
"Dial",
QStringList {
"handle" } },
183 ControlElement {
"Dialog",
QStringList {
"header",
"footer" } },
184 ControlElement {
"GroupBox",
QStringList {
"label" } },
185 ControlElement {
"$internal$.QQuickIndicatorButton",
QStringList {
"indicator" },
false },
186 ControlElement {
"Label",
QStringList {
"background" } },
187 ControlElement {
"MenuItem",
QStringList {
"arrow" } },
188 ControlElement {
"Page",
QStringList {
"header",
"footer" } },
189 ControlElement {
"Popup",
QStringList {
"background",
"contentItem" } },
190 ControlElement {
"RangeSlider",
QStringList {
"handle" } },
191 ControlElement {
"Slider",
QStringList {
"handle" } },
192 ControlElement {
"$internal$.QQuickSwipe",
193 QStringList {
"leftItem",
"behindItem",
"rightItem" },
false },
194 ControlElement {
"TextArea",
QStringList {
"background" } },
195 ControlElement {
"TextField",
QStringList {
"background" } },
198 for (
const QString &module : { u
"QtQuick.Controls.macOS"_s, u
"QtQuick.Controls.Windows"_s }) {
199 if (!
manager->hasImportedModule(module))
204 for (ControlElement &element : m_elements) {
205 auto type =
resolveType(element.isInModuleControls ? module :
"QtQuick.Templates",
211 element.inheritsControl = !element.isControl &&
type.
inherits(control);
212 element.element =
type;
215 m_elements.
removeIf([](
const ControlElement &element) {
return element.element.isNull(); });
223 for (
const ControlElement &controlElement : m_elements) {
225 if (controlElement.inheritsControl)
227 if (element.
inherits(controlElement.element))
235 for (
const ControlElement &controlElement : m_elements) {
236 if (element.
inherits(controlElement.element)) {
237 for (
const QString &propertyName : controlElement.restrictedProperties) {
240 "styles cannot be customized: See "
241 "https://doc-snapshots.qt.io/qt6-dev/"
242 "qtquickcontrols-customize.html#customization-"
243 "reference for more information.")
251 if (!controlElement.isControl)
259 , m_item(resolveType(
"QtQuick",
"Item"))
271 enum BindingLocation { Exists = 1, Own = (1 << 1) };
275 u
"top"_s, u
"bottom"_s, u
"verticalCenter"_s,
281 auto groupType = anchorBindings[
i].groupType();
282 if (groupType.isNull())
287 const auto &propertyBindings = groupType.ownPropertyBindings(
name);
288 if (propertyBindings.begin() == propertyBindings.end())
291 bool isUndefined =
false;
292 for (
const auto &propertyBinding : propertyBindings) {
293 if (propertyBinding.hasUndefinedScriptValue()) {
302 bindings[
name] |= Exists | ((
i == 0) ? Own : 0);
310 if (bindings[
name] & Own) {
314 warnLoc = bindings.
begin().
value().sourceLocation();
321 if ((bindings[u
"left"_s] & bindings[u
"right"_s] & bindings[u
"horizontalCenter"_s]) & Exists) {
323 ownSourceLocation({ u
"left"_s, u
"right"_s, u
"horizontalCenter"_s });
327 "Cannot specify left, right, and horizontalCenter anchors at the same time.",
332 if ((bindings[u
"top"_s] & bindings[u
"bottom"_s] & bindings[u
"verticalCenter"_s]) & Exists) {
334 ownSourceLocation({ u
"top"_s, u
"bottom"_s, u
"verticalCenter"_s });
336 emitWarning(
"Cannot specify top, bottom, and verticalCenter anchors at the same time.",
341 if ((bindings[u
"baseline"_s] & (bindings[u
"bottom"_s] | bindings[u
"verticalCenter"_s]))
344 ownSourceLocation({ u
"baseline"_s, u
"bottom"_s, u
"verticalCenter"_s });
346 emitWarning(
"Baseline anchor cannot be used in conjunction with top, bottom, or "
347 "verticalCenter anchors.",
355 , m_swipeDelegate(resolveType(
"QtQuick.Controls",
"SwipeDelegate"))
361 return !m_swipeDelegate.
isNull() && element.
inherits(m_swipeDelegate);
366 for (
const auto &
property : { u
"background"_s, u
"contentItem"_s }) {
368 if (!binding.hasObject())
372 if (bindings.isEmpty())
378 auto anchors = bindings.first().groupType();
379 for (
const auto &disallowed : { u
"fill"_s, u
"centerIn"_s, u
"left"_s, u
"right"_s }) {
380 if (
anchors.hasPropertyBindings(disallowed)) {
382 const auto &ownBindings =
anchors.ownPropertyBindings(disallowed);
383 if (ownBindings.begin() != ownBindings.end()) {
384 location = ownBindings.begin().value().sourceLocation();
388 u
"SwipeDelegate: Cannot use horizontal anchors with %1; unable to layout the item."_s
399 if (swipe.begin() == swipe.end())
402 const auto firstSwipe = swipe.
begin().value();
406 auto group = firstSwipe.groupType();
408 const std::array ownDirBindings = {
group.ownPropertyBindings(u
"right"_s),
409 group.ownPropertyBindings(u
"left"_s),
410 group.ownPropertyBindings(u
"behind"_s) };
412 auto ownBindingIterator =
413 std::find_if(ownDirBindings.begin(), ownDirBindings.end(),
414 [](
const auto &bindings) { return bindings.begin() != bindings.end(); });
416 if (ownBindingIterator == ownDirBindings.end())
419 if (
group.hasPropertyBindings(u
"behind"_s)
420 && (
group.hasPropertyBindings(u
"right"_s) ||
group.hasPropertyBindings(u
"left"_s))) {
421 emitWarning(
"SwipeDelegate: Cannot set both behind and left/right properties",
436 :
resolveType(pair.second.module, pair.second.name);
438 propertyTypes.
insert(pair.first, propType);
441 m_expectedPropertyTypes = propertyTypes;
460 if (!
value.isNull()) {
479 [&](
const QQmlSA::Element &scope) { return bindingType.inherits(scope); })
482 const bool bindingTypeIsComposite = bindingType.
isComposite();
483 if (bindingTypeIsComposite && !bindingType.
baseType()) {
492 const QString bindingTypeName =
494 : bindingType.
name();
498 expectedTypeNames <<
it.value().name();
500 emitWarning(u
"Unexpected type for property \"%1\" expected %2 got %3"_s.arg(
501 propertyName, expectedTypeNames.join(u
", "_s), bindingTypeName),
511 const auto attachedTypeAndLocation = std::find_if(
512 range.first,
range.second, [&](
const ElementAndLocation &elementAndLocation) {
513 return elementAndLocation.element == element;
515 if (attachedTypeAndLocation !=
range.second) {
524 scope = scope.parentScope()) {
528 if (
it->element == element) {
541 id.isEmpty() ? u
"<id>."_s : (
id +
'.'_L1) };
544 suggestion.
setHint(
"You first have to give the element an id"_L1);
546 suggestion.setAutoApplicable();
548 emitWarning(
"Using attached type %1 already initialized in a parent scope."_L1.arg(
550 category, attachedLocation, suggestion);
561 if (!
type || !attached)
568 if (
parent.internalId() ==
"QQuickAttachedPropertyPropagator"_L1) {
598 const bool hasQuick =
manager->hasImportedModule(
"QtQuick");
599 const bool hasQuickLayouts =
manager->hasImportedModule(
"QtQuick.Layouts");
600 const bool hasQuickControls =
manager->hasImportedModule(
"QtQuick.Templates")
601 ||
manager->hasImportedModule(
"QtQuick.Controls")
602 ||
manager->hasImportedModule(
"QtQuick.Controls.Basic");
607 manager->registerElementPass(std::make_unique<AnchorsValidatorPass>(
manager));
608 manager->registerElementPass(std::make_unique<PropertyChangesValidatorPass>(
manager));
610 auto forbiddenChildProperty =
611 std::make_unique<ForbiddenChildrenPropertyValidatorPass>(
manager);
613 for (
const QString &element : { u
"Grid"_s, u
"Flow"_s }) {
615 forbiddenChildProperty->addWarning(
617 u
"Cannot specify %1 for items inside %2. %2 will not function."_s.arg(
622 if (hasQuickLayouts) {
623 forbiddenChildProperty->addWarning(
624 "QtQuick.Layouts",
"Layout",
"anchors",
625 "Detected anchors on an item that is managed by a layout. This is undefined "
626 u
"behavior; use Layout.alignment instead.");
627 forbiddenChildProperty->addWarning(
628 "QtQuick.Layouts",
"Layout",
"x",
629 "Detected x on an item that is managed by a layout. This is undefined "
630 u
"behavior; use Layout.leftMargin or Layout.rightMargin instead.");
631 forbiddenChildProperty->addWarning(
632 "QtQuick.Layouts",
"Layout",
"y",
633 "Detected y on an item that is managed by a layout. This is undefined "
634 u
"behavior; use Layout.topMargin or Layout.bottomMargin instead.");
635 forbiddenChildProperty->addWarning(
636 "QtQuick.Layouts",
"Layout",
"width",
637 "Detected width on an item that is managed by a layout. This is undefined "
638 u
"behavior; use implicitWidth or Layout.preferredWidth instead.");
639 forbiddenChildProperty->addWarning(
640 "QtQuick.Layouts",
"Layout",
"height",
641 "Detected height on an item that is managed by a layout. This is undefined "
642 u
"behavior; use implictHeight or Layout.preferredHeight instead.");
645 manager->registerElementPass(std::move(forbiddenChildProperty));
648 auto attachedPropertyType = std::make_shared<AttachedPropertyTypeValidatorPass>(
manager);
652 QString attachedTypeName = attachedPropertyType->addWarning(attachedType, allowedTypes,
653 allowInDelegate, warning);
654 manager->registerPropertyPass(attachedPropertyType, attachedType.
module,
655 u
"$internal$."_s + attachedTypeName, {},
false);
658 auto addVarBindingWarning =
661 auto varBindingType = std::make_shared<VarBindingTypeValidatorPass>(
662 manager, expectedPropertyTypes);
663 for (
const auto &propertyName : expectedPropertyTypes.uniqueKeys()) {
670 addVarBindingWarning(
"QtQuick",
"TableView",
671 { {
"columnWidthProvider", {
"",
"function" } },
672 {
"rowHeightProvider", {
"",
"function" } } });
673 addAttachedWarning({
"QtQuick",
"Accessible" }, { {
"QtQuick",
"Item" } },
674 "Accessible must be attached to an Item");
675 addAttachedWarning({
"QtQuick",
"LayoutMirroring" },
676 { {
"QtQuick",
"Item" }, {
"QtQuick",
"Window" } },
677 "LayoutDirection attached property only works with Items and Windows");
678 addAttachedWarning({
"QtQuick",
"EnterKey" }, { {
"QtQuick",
"Item" } },
679 "EnterKey attached property only works with Items");
681 if (hasQuickLayouts) {
682 addAttachedWarning({
"QtQuick.Layouts",
"Layout" }, { {
"QtQuick",
"Item" } },
683 "Layout must be attached to Item elements");
684 addAttachedWarning({
"QtQuick.Layouts",
"StackLayout" }, { {
"QtQuick",
"Item" } },
685 "StackLayout must be attached to an Item");
689 if (hasQuickControls) {
690 manager->registerElementPass(std::make_unique<ControlsSwipeDelegateValidatorPass>(
manager));
691 manager->registerPropertyPass(std::make_unique<AttachedPropertyReuse>(
692 manager, attachedReuseCategory),
"",
"");
694 addAttachedWarning({
"QtQuick.Templates",
"ScrollBar" },
695 { {
"QtQuick",
"Flickable" }, {
"QtQuick.Templates",
"ScrollView" } },
696 "ScrollBar must be attached to a Flickable or ScrollView");
697 addAttachedWarning({
"QtQuick.Templates",
"ScrollIndicator" },
698 { {
"QtQuick",
"Flickable" } },
699 "ScrollIndicator must be attached to a Flickable");
700 addAttachedWarning({
"QtQuick.Templates",
"TextArea" }, { {
"QtQuick",
"Flickable" } },
701 "TextArea must be attached to a Flickable");
702 addAttachedWarning({
"QtQuick.Templates",
"SplitView" }, { {
"QtQuick",
"Item" } },
703 "SplitView attached property only works with Items");
704 addAttachedWarning({
"QtQuick.Templates",
"StackView" }, { {
"QtQuick",
"Item" } },
705 "StackView attached property only works with Items");
706 addAttachedWarning({
"QtQuick.Templates",
"ToolTip" }, { {
"QtQuick",
"Item" } },
707 "ToolTip must be attached to an Item");
708 addAttachedWarning({
"QtQuick.Templates",
"SwipeDelegate" }, { {
"QtQuick",
"Item" } },
709 "Attached properties of SwipeDelegate must be accessed through an Item");
710 addAttachedWarning({
"QtQuick.Templates",
"SwipeView" }, { {
"QtQuick",
"Item" } },
711 "SwipeView must be attached to an Item");
713 {
"QtQuick.Templates",
"Tumbler" }, { {
"QtQuick",
"Tumbler" } },
714 "Tumbler: attached properties of Tumbler must be accessed through a delegate item",
716 addVarBindingWarning(
"QtQuick.Templates",
"Tumbler",
717 { {
"contentItem", {
"QtQuick",
"PathView" } },
718 {
"contentItem", {
"QtQuick",
"ListView" } } });
719 addVarBindingWarning(
"QtQuick.Templates",
"SpinBox",
720 { {
"textFromValue", {
"",
"function" } },
721 {
"valueFromText", {
"",
"function" } } });
723 manager->registerPropertyPass(std::make_unique<AttachedPropertyReuse>(
724 manager, attachedReuseCategory),
"",
"");
727 if (
manager->hasImportedModule(u
"QtQuick.Controls.macOS"_s)
728 ||
manager->hasImportedModule(u
"QtQuick.Controls.Windows"_s))
729 manager->registerElementPass(std::make_unique<ControlsNativeValidatorPass>(
manager));
734 , m_propertyChanges(resolveType(
"QtQuick",
"PropertyChanges"))
740 return !m_propertyChanges.
isNull() && element.
inherits(m_propertyChanges);
749 [](
const auto binding) { return binding.propertyName() == u
"target"_s; });
756 if (!targetElement.
isNull())
757 targetId = targetBinding;
760 const auto &propertyName =
it.key();
761 const auto &propertyBinding =
it.value();
768 "Unknown property \"%1\" in PropertyChanges."_L1.arg(propertyName),
774 if (binding.
length() > 16)
775 binding = binding.
left(13) +
"..."_L1;
777 emitWarning(
"Property \"%1\" is custom-parsed in PropertyChanges. "
778 "You should phrase this binding as \"%2.%1: %3\""_L1.arg(propertyName, targetId,
786#include "moc_quicklintplugin.cpp"
bool shouldRun(const QQmlSA::Element &element) override
Returns true if the run() function should be executed on the given element.
AnchorsValidatorPass(QQmlSA::PassManager *manager)
void run(const QQmlSA::Element &element) override
Executes if shouldRun() returns true.
void onRead(const QQmlSA::Element &element, const QString &propertyName, const QQmlSA::Element &readScope, QQmlSA::SourceLocation location) override
Executes whenever a property is read.
void onWrite(const QQmlSA::Element &element, const QString &propertyName, const QQmlSA::Element &value, const QQmlSA::Element &writeScope, QQmlSA::SourceLocation location) override
Executes whenever a property is written to.
void onRead(const QQmlSA::Element &element, const QString &propertyName, const QQmlSA::Element &readScope, QQmlSA::SourceLocation location) override
Executes whenever a property is read.
AttachedPropertyTypeValidatorPass(QQmlSA::PassManager *manager)
void onWrite(const QQmlSA::Element &element, const QString &propertyName, const QQmlSA::Element &value, const QQmlSA::Element &writeScope, QQmlSA::SourceLocation location) override
Executes whenever a property is written to.
void onBinding(const QQmlSA::Element &element, const QString &propertyName, const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope, const QQmlSA::Element &value) override
Executes whenever a property gets bound to a value.
QString addWarning(TypeDescription attachType, QList< TypeDescription > allowedTypes, bool allowInDelegate, QAnyStringView warning)
ControlsNativeValidatorPass(QQmlSA::PassManager *manager)
void run(const QQmlSA::Element &element) override
Executes if shouldRun() returns true.
bool shouldRun(const QQmlSA::Element &element) override
Returns true if the run() function should be executed on the given element.
bool shouldRun(const QQmlSA::Element &element) override
Returns true if the run() function should be executed on the given element.
ControlsSwipeDelegateValidatorPass(QQmlSA::PassManager *manager)
void run(const QQmlSA::Element &element) override
Executes if shouldRun() returns true.
void addWarning(QAnyStringView moduleName, QAnyStringView typeName, QAnyStringView propertyName, QAnyStringView warning)
ForbiddenChildrenPropertyValidatorPass(QQmlSA::PassManager *manager)
void run(const QQmlSA::Element &element) override
Executes if shouldRun() returns true.
bool shouldRun(const QQmlSA::Element &element) override
Returns true if the run() function should be executed on the given element.
void run(const QQmlSA::Element &element) override
Executes if shouldRun() returns true.
PropertyChangesValidatorPass(QQmlSA::PassManager *manager)
bool shouldRun(const QQmlSA::Element &element) override
Returns true if the run() function should be executed on the given element.
QString toString() const
Returns a deep copy of this string view's data as a QString.
T & value() const noexcept
Returns a modifiable reference to the current item's value.
iterator begin()
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the first item in the hash.
const_iterator constFind(const Key &key) const noexcept
iterator end() noexcept
Returns an \l{STL-style iterators}{STL-style iterator} pointing to the imaginary item after the last ...
const_iterator cend() const noexcept
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
qsizetype size() const noexcept
qsizetype removeIf(Predicate pred)
QPair< iterator, iterator > equal_range(const Key &key)
iterator insert(const Key &key, const T &value)
Inserts a new item with the key and a value of value.
QMultiHash< QString, Binding >::const_iterator constBegin() const
Returns an iterator to the beginning of the bindings.
QMultiHash< QString, Binding >::const_iterator begin() const
QMultiHash< QString, Binding >::const_iterator constEnd() const
Returns an iterator to the end of the bindings.
BindingType bindingType() const
static bool isLiteralBinding(BindingType)
Returns true if bindingType is a literal type, and false otherwise.
Element objectType() const
Returns the type of the associated object if the content type of this binding is Object,...
QQmlSA::SourceLocation sourceLocation() const
Returns the location in the QML code where this binding is defined.
QString internalId() const
Element baseType() const
Returns the Element this Element derives from.
bool hasMethod(const QString &methodName) const
Returns whether this Element has a method with the name methodName.
bool isPropertyRequired(const QString &propertyName) const
Returns whether the property with the name propertyName resolved on this Element is required.
QString name() const
Returns the name of this Element.
QQmlSA::SourceLocation sourceLocation() const
Returns the location in the QML code where this method is defined.
Binding::Bindings ownPropertyBindings() const
Returns this Element's property bindings which are not defined on its base or extension objects.
QList< Binding > propertyBindings(const QString &propertyName) const
Returns this Element's property bindings that have the name propertyName.
bool isComposite() const
Returns true for objects defined from Qml, and false for objects declared from C++.
bool hasProperty(const QString &propertyName) const
Returns whether this Element has a property with the name propertyName.
Element parentScope() const
Returns the Element that encloses this Element.
bool inherits(const Element &) const
Returns whether this Element inherits from element.
bool hasOwnPropertyBindings(const QString &propertyName) const
Returns whether this Element has property bindings which are not defined in its base or extension obj...
void setHint(const QString &)
Sets hint as the hint for this fix suggestion.
Element resolveLiteralType(const Binding &binding)
Returns the element representing the type of literal in binding.
void emitWarning(QAnyStringView diagnostic, QQmlJS::LoggerWarningId id)
Emits a warning message diagnostic about an issue of type id.
Element resolveBuiltinType(QAnyStringView typeName) const
Returns the type of the built-in type identified by typeName.
Element resolveAttached(QAnyStringView moduleName, QAnyStringView typeName)
Returns the attached type of typeName defined in module moduleName.
QString resolveElementToId(const Element &element, const Element &context)
Returns the id of element in a given context.
Element resolveTypeInFileScope(QAnyStringView typeName)
Returns the type corresponding to typeName inside the currently analysed file.
QString sourceCode(QQmlSA::SourceLocation location)
Returns the source code located within location.
Element resolveAttachedInFileScope(QAnyStringView typeName)
Returns the attached type corresponding to typeName used inside the currently analysed file.
Element resolveIdToElement(QAnyStringView id, const Element &context)
Returns the element in context that has id id.
Element resolveType(QAnyStringView moduleName, QAnyStringView typeName)
Returns the type of typeName defined in module moduleName.
quint32 startColumn() const
Returns the column number containing the beginning of this source location.
quint32 startLine() const
Returns the line number containing the beginning of this source location.
quint32 offset() const
Returns the offset of the beginning of this source location.
\macro QT_RESTRICTED_CAST_FROM_ASCII
QString left(qsizetype n) const
Returns a substring that contains the n leftmost characters of the string.
qsizetype length() const
Returns the number of characters in this string.
void registerPasses(QQmlSA::PassManager *manager, const QQmlSA::Element &rootElement) override
Adds a pass manager that will be executed on rootElement.
VarBindingTypeValidatorPass(QQmlSA::PassManager *manager, const QMultiHash< QString, TypeDescription > &expectedPropertyTypes)
void onBinding(const QQmlSA::Element &element, const QString &propertyName, const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope, const QQmlSA::Element &value) override
Executes whenever a property gets bound to a value.
QSet< QString >::iterator it
Combined button and popup list for selecting options.
static const QCssKnownValue properties[NumProperties - 1]
EGLOutputLayerEXT EGLint EGLAttrib value
[5]
const QQmlJS::LoggerWarningId qmlAttachedPropertyReuse
QQuickAnchors * anchors(QQuickItem *item)
#define QStringLiteral(str)
static const QTextHtmlElement elements[Html_NumElements]
static constexpr QQmlJS::LoggerWarningId quickPropertyChangesParsed
static constexpr QQmlJS::LoggerWarningId quickControlsAttachedPropertyReuse
static constexpr QQmlJS::LoggerWarningId quickAttachedPropertyType
static constexpr QQmlJS::LoggerWarningId quickControlsNativeCustomize
static constexpr QQmlJS::LoggerWarningId quickUnexpectedVarType
static constexpr QQmlJS::LoggerWarningId quickAnchorCombinations
static constexpr QQmlJS::LoggerWarningId quickLayoutPositioning
static constexpr QQmlJS::LoggerWarningId quickAttachedPropertyReuse
QNetworkAccessManager manager
IUIAutomationTreeWalker __RPC__deref_out_opt IUIAutomationElement ** parent