7#include <QtQmlCompiler/private/qqmlsasourcelocation_p.h>
8#include <QtQmlCompiler/private/qqmljsutils_p.h>
12using namespace Qt::StringLiterals;
26 QQmlSA::PassManager *manager)
32 QAnyStringView typeName,
33 QAnyStringView propertyName,
34 QAnyStringView warning)
36 auto element = resolveType(moduleName, typeName);
37 if (!element.isNull())
38 m_types[element].append({ propertyName.toString(), warning.toString() });
43 if (!element.parentScope())
46 for (
const auto &pair : std::as_const(m_types).asKeyValueRange()) {
47 if (element.parentScope().inherits(pair.first))
56 for (
const auto &elementPair : std::as_const(m_types).asKeyValueRange()) {
57 const QQmlSA::Element &type = elementPair.first;
58 const QQmlSA::Element parentScope = element.parentScope();
62 const QQmlSA::Property defaultProperty
63 = parentScope.property(parentScope.defaultPropertyName());
64 if (defaultProperty != type.property(type.defaultPropertyName()))
67 if (!element.parentScope().inherits(type))
70 for (
const auto &warning : elementPair.second) {
71 if (!element.hasOwnPropertyBindings(warning.propertyName))
74 const auto bindings = element.ownPropertyBindings(warning.propertyName);
75 const auto firstBinding = bindings.constBegin().value();
76 emitWarning(warning.message, quickLayoutPositioning, firstBinding.sourceLocation());
88 QList<TypeDescription> allowedTypes,
89 bool allowInDelegate, QAnyStringView warning)
91 QVarLengthArray<QQmlSA::Element, 4> elements;
93 const QQmlSA::Element attachedType = resolveAttached(attachType.module, attachType.name);
98 for (
const TypeDescription &desc : allowedTypes) {
99 const QQmlSA::Element type = resolveType(desc.module, desc.name);
102 elements.push_back(type);
105 m_attachedTypes.insert(
106 { std::make_pair<>(attachedType.internalId(),
107 Warning{ elements, allowInDelegate, warning.toString() }) });
109 return attachedType.internalId();
113 const QQmlSA::Element &scopeUsedIn,
114 const QQmlSA::SourceLocation &location)
116 auto warning = m_attachedTypes.constFind(element.internalId());
117 if (warning == m_attachedTypes.cend())
119 for (
const QQmlSA::Element &type : warning->allowedTypes) {
120 if (scopeUsedIn.inherits(type))
125 if ( QQmlJSScope::scope(scopeUsedIn)->isInCustomParserParent() )
128 if (warning->allowInDelegate) {
129 if (scopeUsedIn.isPropertyRequired(u"index"_s)
130 || scopeUsedIn.isPropertyRequired(u"model"_s))
135 if (scopeUsedIn.isFileRootComponent())
138 for (
const QQmlSA::Binding &binding :
139 scopeUsedIn.parentScope().propertyBindings(u"delegate"_s)) {
140 if (!binding.hasObject())
142 if (binding.objectType() == scopeUsedIn)
147 emitWarning(warning->message, quickAttachedPropertyType, location);
151 const QString &propertyName,
152 const QQmlSA::Binding &binding,
153 const QQmlSA::Element &bindingScope,
154 const QQmlSA::Element &value)
163 if (propertyName.count(QLatin1Char(
'.')) > 1)
166 checkWarnings(bindingScope.baseType(), element, binding.sourceLocation());
170 const QString &propertyName,
171 const QQmlSA::Element &readScope,
172 QQmlSA::SourceLocation location)
176 if (element.hasProperty(propertyName) || element.hasMethod(propertyName))
177 checkWarnings(element, readScope, location);
181 const QString &propertyName,
182 const QQmlSA::Element &value,
183 const QQmlSA::Element &writeScope,
184 QQmlSA::SourceLocation location)
186 Q_UNUSED(propertyName)
189 checkWarnings(element, writeScope, location);
196 ControlElement {
"Control",
197 QStringList {
"background",
"contentItem",
"leftPadding",
"rightPadding",
198 "topPadding",
"bottomPadding",
"horizontalPadding",
199 "verticalPadding",
"padding" },
201 ControlElement {
"Button", QStringList {
"indicator" } },
204 QStringList {
"background",
"contentItem",
"header",
"footer",
"menuBar" } },
205 ControlElement {
"ComboBox", QStringList {
"indicator" } },
206 ControlElement {
"Dial", QStringList {
"handle" } },
207 ControlElement {
"GroupBox", QStringList {
"label" } },
208 ControlElement {
"$internal$.QQuickIndicatorButton", QStringList {
"indicator" },
false },
209 ControlElement {
"Label", QStringList {
"background" } },
210 ControlElement {
"MenuItem", QStringList {
"arrow" } },
211 ControlElement {
"Page", QStringList {
"header",
"footer" } },
212 ControlElement {
"Popup", QStringList {
"background",
"contentItem" } },
213 ControlElement {
"RangeSlider", QStringList {
"handle" } },
214 ControlElement {
"Slider", QStringList {
"handle" } },
215 ControlElement {
"$internal$.QQuickSwipe",
216 QStringList {
"leftItem",
"behindItem",
"rightItem" },
false },
217 ControlElement {
"TextArea", QStringList {
"background" } },
218 ControlElement {
"TextField", QStringList {
"background" } },
221 for (
const QString &module : { u"QtQuick.Controls.macOS"_s, u"QtQuick.Controls.Windows"_s }) {
222 if (!manager->hasImportedModule(module))
225 QQmlSA::Element control = resolveType(module,
"Control");
227 for (ControlElement &element : m_elements) {
228 auto type = resolveType(element.isInModuleControls ? module :
"QtQuick.Templates",
234 element.inheritsControl = !element.isControl && type.inherits(control);
235 element.element = type;
238 m_elements.removeIf([](
const ControlElement &element) {
return element.element.isNull(); });
246 for (
const ControlElement &controlElement : m_elements) {
248 if (controlElement.inheritsControl)
250 if (element.inherits(controlElement.element))
258 for (
const ControlElement &controlElement : m_elements) {
259 if (element.inherits(controlElement.element)) {
260 for (
const QString &propertyName : controlElement.restrictedProperties) {
261 if (element.hasOwnPropertyBindings(propertyName)) {
262 emitWarning(QStringLiteral(
"Not allowed to override \"%1\" because native "
263 "styles cannot be customized: See "
264 "https://doc-snapshots.qt.io/qt6-dev/"
265 "qtquickcontrols-customize.html#customization-"
266 "reference for more information.")
268 quickControlsNativeCustomize, element.sourceLocation());
274 if (!controlElement.isControl)
288 return !m_item.isNull() && element.inherits(m_item)
289 && element.hasOwnPropertyBindings(u"anchors"_s);
294 enum BindingLocation { Exists = 1, Own = (1 << 1) };
295 QHash<QString, qint8> bindings;
297 const QStringList properties = { u"left"_s, u"right"_s, u"horizontalCenter"_s,
298 u"top"_s, u"bottom"_s, u"verticalCenter"_s,
301 QList<QQmlSA::Binding> anchorBindings = element.propertyBindings(u"anchors"_s);
303 for (qsizetype i = anchorBindings.size() - 1; i >= 0; i--) {
304 auto groupType = anchorBindings[i].groupType();
305 if (groupType.isNull())
308 for (
const QString &name : properties) {
310 const auto &propertyBindings = groupType.ownPropertyBindings(name);
311 if (propertyBindings.begin() == propertyBindings.end())
314 bool isUndefined =
false;
315 for (
const auto &propertyBinding : propertyBindings) {
316 if (propertyBinding.hasUndefinedScriptValue()) {
325 bindings[name] |= Exists | ((i == 0) ? Own : 0);
329 auto ownSourceLocation = [&](QStringList properties) -> QQmlSA::SourceLocation {
330 QQmlSA::SourceLocation warnLoc;
332 for (
const QString &name : properties) {
333 if (bindings[name] & Own) {
334 QQmlSA::Element groupType = QQmlSA::Element{ anchorBindings[0].groupType() };
335 auto bindings = groupType.ownPropertyBindings(name);
336 Q_ASSERT(bindings.begin() != bindings.end());
337 warnLoc = bindings.begin().value().sourceLocation();
344 if ((bindings[u"left"_s] & bindings[u"right"_s] & bindings[u"horizontalCenter"_s]) & Exists) {
345 QQmlSA::SourceLocation warnLoc =
346 ownSourceLocation({ u"left"_s, u"right"_s, u"horizontalCenter"_s });
348 if (warnLoc.isValid()) {
350 "Cannot specify left, right, and horizontalCenter anchors at the same time.",
351 quickAnchorCombinations, warnLoc);
355 if ((bindings[u"top"_s] & bindings[u"bottom"_s] & bindings[u"verticalCenter"_s]) & Exists) {
356 QQmlSA::SourceLocation warnLoc =
357 ownSourceLocation({ u"top"_s, u"bottom"_s, u"verticalCenter"_s });
358 if (warnLoc.isValid()) {
359 emitWarning(
"Cannot specify top, bottom, and verticalCenter anchors at the same time.",
360 quickAnchorCombinations, warnLoc);
364 if ((bindings[u"baseline"_s] & (bindings[u"bottom"_s] | bindings[u"verticalCenter"_s]))
366 QQmlSA::SourceLocation warnLoc =
367 ownSourceLocation({ u"baseline"_s, u"bottom"_s, u"verticalCenter"_s });
368 if (warnLoc.isValid()) {
369 emitWarning(
"Baseline anchor cannot be used in conjunction with top, bottom, or "
370 "verticalCenter anchors.",
371 quickAnchorCombinations, warnLoc);
384 return !m_swipeDelegate.isNull() && element.inherits(m_swipeDelegate);
389 for (
const auto &property : { u"background"_s, u"contentItem"_s }) {
390 for (
const auto &binding : element.ownPropertyBindings(property)) {
391 if (!binding.hasObject())
393 const QQmlSA::Element element = QQmlSA::Element{ binding.objectType() };
394 const auto &bindings = element.propertyBindings(u"anchors"_s);
395 if (bindings.isEmpty())
398 if (bindings.first().bindingType() != QQmlSA::BindingType::GroupProperty)
401 auto anchors = bindings.first().groupType();
402 for (
const auto &disallowed : { u"fill"_s, u"centerIn"_s, u"left"_s, u"right"_s }) {
403 if (anchors.hasPropertyBindings(disallowed)) {
404 QQmlSA::SourceLocation location;
405 const auto &ownBindings = anchors.ownPropertyBindings(disallowed);
406 if (ownBindings.begin() != ownBindings.end()) {
407 location = ownBindings.begin().value().sourceLocation();
411 u"SwipeDelegate: Cannot use horizontal anchors with %1; unable to layout the item."_s
413 quickAnchorCombinations, location);
421 const auto &swipe = element.ownPropertyBindings(u"swipe"_s);
422 if (swipe.begin() == swipe.end())
425 const auto firstSwipe = swipe.begin().value();
426 if (firstSwipe.bindingType() != QQmlSA::BindingType::GroupProperty)
429 auto group = firstSwipe.groupType();
431 const std::array ownDirBindings = { group.ownPropertyBindings(u"right"_s),
432 group.ownPropertyBindings(u"left"_s),
433 group.ownPropertyBindings(u"behind"_s) };
435 auto ownBindingIterator =
436 std::find_if(ownDirBindings.begin(), ownDirBindings.end(),
437 [](
const auto &bindings) {
return bindings.begin() != bindings.end(); });
439 if (ownBindingIterator == ownDirBindings.end())
442 if (group.hasPropertyBindings(u"behind"_s)
443 && (group.hasPropertyBindings(u"right"_s) || group.hasPropertyBindings(u"left"_s))) {
444 emitWarning(
"SwipeDelegate: Cannot set both behind and left/right properties",
445 quickAnchorCombinations, ownBindingIterator->begin().value().sourceLocation());
450 QQmlSA::PassManager *manager,
451 const QMultiHash<QString, TypeDescription> &expectedPropertyTypes)
454 QMultiHash<QString, QQmlSA::Element> propertyTypes;
456 for (
const auto &pair : expectedPropertyTypes.asKeyValueRange()) {
457 const QQmlSA::Element propType = pair.second.module.isEmpty()
458 ? resolveBuiltinType(pair.second.name)
459 : resolveType(pair.second.module, pair.second.name);
460 if (!propType.isNull())
461 propertyTypes.insert(pair.first, propType);
464 m_expectedPropertyTypes = propertyTypes;
468 const QString &propertyName,
469 const QQmlSA::Binding &binding,
470 const QQmlSA::Element &bindingScope,
471 const QQmlSA::Element &value)
474 Q_UNUSED(bindingScope);
476 const auto range = m_expectedPropertyTypes.equal_range(propertyName);
478 if (range.first == range.second)
481 QQmlSA::Element bindingType;
483 if (!value.isNull()) {
486 if (QQmlSA::Binding::isLiteralBinding(binding.bindingType())) {
487 bindingType = resolveLiteralType(binding);
489 switch (binding.bindingType()) {
490 case QQmlSA::BindingType::Object:
491 bindingType = QQmlSA::Element{ binding.objectType() };
493 case QQmlSA::BindingType::Script:
501 if (std::find_if(range.first, range.second,
502 [&](
const QQmlSA::Element &scope) {
return bindingType.inherits(scope); })
505 const bool bindingTypeIsComposite = bindingType.isComposite();
506 if (bindingTypeIsComposite && !bindingType.baseType()) {
508
509
510
511
512
515 const QString bindingTypeName =
516 bindingTypeIsComposite ? bindingType.baseType().name()
517 : bindingType.name();
518 QStringList expectedTypeNames;
520 for (
auto it = range.first; it != range.second; it++)
521 expectedTypeNames << it.value().name();
523 emitWarning(u"Unexpected type for property \"%1\" expected %2 got %3"_s.arg(
524 propertyName, expectedTypeNames.join(u", "_s), bindingTypeName),
525 quickUnexpectedVarType, binding.sourceLocation());
534 void onBinding(
const QQmlSA::Element &element,
const QString &propertyName,
535 const QQmlSA::Binding &binding,
const QQmlSA::Element &bindingScope,
536 const QQmlSA::Element &value)
override;
538 QQmlSA::Element m_colorType;
541 static inline const QRegularExpression s_hexPattern{
"^#((([0-9A-Fa-f]{3}){1,2})|(([0-9A-Fa-f]{4}){1,2}))$"_L1 };
543 QStringList m_colorNames = {
614 u"lightgoldenrodyellow"_s,
631 u"mediumaquamarine"_s,
636 u"mediumslateblue"_s,
637 u"mediumspringgreen"_s,
638 u"mediumturquoise"_s,
639 u"mediumvioletred"_s,
698 Q_ASSERT_X(std::is_sorted(m_colorNames.cbegin(), m_colorNames.cend()),
"ColorValidatorPass",
699 "m_colorNames should be sorted!");
703 const QQmlSA::Binding &binding,
const QQmlSA::Element &,
704 const QQmlSA::Element &)
706 if (binding.bindingType() != QQmlSA::BindingType::StringLiteral)
708 const auto propertyType = element.property(propertyName).type();
709 if (!propertyType || propertyType != m_colorType)
712 QString colorName = binding.stringValue();
715 if (!colorName.startsWith(u'#'))
716 colorName = std::move(colorName).toLower();
717 if (s_hexPattern.match(colorName).hasMatch())
720 if (std::binary_search(m_colorNames.cbegin(), m_colorNames.cend(), colorName))
723 if (colorName == u"transparent")
726 auto suggestion = QQmlJSUtils::didYouMean(
727 colorName, m_colorNames,
728 QQmlSA::SourceLocationPrivate::sourceLocation(binding.sourceLocation()));
730 emitWarningWithOptionalFix(*
this,
"Invalid color \"%1\"."_L1.arg(colorName), quickColor,
731 binding.sourceLocation(), suggestion);
735 const QQmlSA::Element &readScope,
736 QQmlSA::SourceLocation location)
738 const auto range = usedAttachedTypes.equal_range(readScope);
739 const auto attachedTypeAndLocation = std::find_if(
740 range.first, range.second, [&](
const ElementAndLocation &elementAndLocation) {
741 return elementAndLocation.element == element;
743 if (attachedTypeAndLocation != range.second) {
744 const QQmlSA::SourceLocation attachedLocation = attachedTypeAndLocation->location;
748 if (!element.hasProperty(propertyName) && !element.hasMethod(propertyName))
751 for (QQmlSA::Element scope = readScope.parentScope(); !scope.isNull();
752 scope = scope.parentScope()) {
753 const auto range = usedAttachedTypes.equal_range(scope);
755 for (
auto it = range.first; it != range.second; ++it) {
756 if (it->element == element) {
764 const QString id = resolveElementToId(scope, readScope);
765 const QQmlSA::SourceLocation idInsertLocation{ attachedLocation.offset(), 0,
766 attachedLocation.startLine(),
767 attachedLocation.startColumn() };
768 QString m =
"Reference it by id instead%1:"_L1;
769 m = m.arg(id.isEmpty() ?
" (You first have to give the element and id)"_L1 :
""_L1);
770 QQmlSA::FixSuggestion suggestion{ m, idInsertLocation,
771 id.isEmpty() ? u"<id>."_s : (id +
'.'_L1) };
774 suggestion.setAutoApplicable();
776 emitWarning(
"Using attached type %1 already initialized in a parent scope."_L1.arg(
778 category, attachedLocation, suggestion);
785 if (element.hasProperty(propertyName))
788 QQmlSA::Element type = resolveTypeInFileScope(propertyName);
789 QQmlSA::Element attached = resolveAttachedInFileScope(propertyName);
790 if (!type || !attached)
793 if (category == quickControlsAttachedPropertyReuse) {
794 for (QQmlSA::Element parent = attached; parent; parent = parent.baseType()) {
797 if (parent.internalId() ==
"QQuickAttachedPropertyPropagator"_L1) {
798 usedAttachedTypes.insert(readScope, {attached, location});
804 usedAttachedTypes.insert(readScope, {attached, location});
809 const QQmlSA::Element &value,
const QQmlSA::Element &writeScope,
810 QQmlSA::SourceLocation location)
813 onRead(element, propertyName, writeScope, location);
817 const QQmlSA::Element &rootElement)
819 const QQmlSA::LoggerWarningId attachedReuseCategory = [manager]() {
820 if (manager->isCategoryEnabled(quickAttachedPropertyReuse))
821 return quickAttachedPropertyReuse;
822 if (manager->isCategoryEnabled(qmlAttachedPropertyReuse))
823 return qmlAttachedPropertyReuse;
824 return quickControlsAttachedPropertyReuse;
827 const bool hasQuick = manager->hasImportedModule(
"QtQuick");
828 const bool hasQuickLayouts = manager->hasImportedModule(
"QtQuick.Layouts");
829 const bool hasQuickControls = manager->hasImportedModule(
"QtQuick.Templates")
830 || manager->hasImportedModule(
"QtQuick.Controls")
831 || manager->hasImportedModule(
"QtQuick.Controls.Basic");
833 Q_UNUSED(rootElement);
836 manager->registerElementPass(std::make_unique<AnchorsValidatorPass>(manager));
837 manager->registerElementPass(std::make_unique<PropertyChangesValidatorPass>(manager));
838 manager->registerElementPass(std::make_unique<StateNoItemChildrenValidator>(manager));
839 manager->registerPropertyPass(std::make_unique<QQuickLiteralBindingCheck>(manager),
840 QAnyStringView(), QAnyStringView());
841 manager->registerPropertyPass(std::make_unique<ColorValidatorPass>(manager),
842 QAnyStringView(), QAnyStringView());
844 auto forbiddenChildProperty =
845 std::make_unique<ForbiddenChildrenPropertyValidatorPass>(manager);
847 for (
const QString &element : { u"Grid"_s, u"Flow"_s }) {
848 for (
const QString &property : { u"anchors"_s, u"x"_s, u"y"_s }) {
849 forbiddenChildProperty->addWarning(
850 "QtQuick", element, property,
851 u"Cannot specify %1 for items inside %2. %2 will not function."_s.arg(
856 if (hasQuickLayouts) {
857 forbiddenChildProperty->addWarning(
858 "QtQuick.Layouts",
"Layout",
"anchors",
859 "Detected anchors on an item that is managed by a layout. This is undefined "
860 u"behavior; use Layout.alignment instead.");
861 forbiddenChildProperty->addWarning(
862 "QtQuick.Layouts",
"Layout",
"x",
863 "Detected x on an item that is managed by a layout. This is undefined "
864 u"behavior; use Layout.leftMargin or Layout.rightMargin instead.");
865 forbiddenChildProperty->addWarning(
866 "QtQuick.Layouts",
"Layout",
"y",
867 "Detected y on an item that is managed by a layout. This is undefined "
868 u"behavior; use Layout.topMargin or Layout.bottomMargin instead.");
869 forbiddenChildProperty->addWarning(
870 "QtQuick.Layouts",
"Layout",
"width",
871 "Detected width on an item that is managed by a layout. This is undefined "
872 u"behavior; use implicitWidth or Layout.preferredWidth instead.");
873 forbiddenChildProperty->addWarning(
874 "QtQuick.Layouts",
"Layout",
"height",
875 "Detected height on an item that is managed by a layout. This is undefined "
876 u"behavior; use implictHeight or Layout.preferredHeight instead.");
879 manager->registerElementPass(std::move(forbiddenChildProperty));
882 auto attachedPropertyType = std::make_shared<AttachedPropertyTypeValidatorPass>(manager);
884 auto addAttachedWarning = [&](TypeDescription attachedType, QList<TypeDescription> allowedTypes,
885 QAnyStringView warning,
bool allowInDelegate =
false) {
886 QString attachedTypeName = attachedPropertyType->addWarning(attachedType, allowedTypes,
887 allowInDelegate, warning);
888 if (attachedTypeName.isEmpty())
891 manager->registerPropertyPass(attachedPropertyType, attachedType.module,
892 u"$internal$."_s + attachedTypeName, {},
false);
895 auto addVarBindingWarning =
896 [&](QAnyStringView moduleName, QAnyStringView typeName,
897 const QMultiHash<QString, TypeDescription> &expectedPropertyTypes) {
898 auto varBindingType = std::make_shared<VarBindingTypeValidatorPass>(
899 manager, expectedPropertyTypes);
900 for (
const auto &propertyName : expectedPropertyTypes.uniqueKeys()) {
901 manager->registerPropertyPass(varBindingType, moduleName, typeName,
907 addVarBindingWarning(
"QtQuick",
"TableView",
908 { {
"columnWidthProvider", {
"",
"function" } },
909 {
"rowHeightProvider", {
"",
"function" } } });
910 addAttachedWarning({
"QtQuick",
"Accessible" },
911 { {
"QtQuick",
"Item" }, {
"QtQuick.Templates",
"Action" } },
912 "Accessible attached property must be attached to an object deriving "
913 "from Item or Action");
914 addAttachedWarning({
"QtQuick",
"LayoutMirroring" },
915 { {
"QtQuick",
"Item" }, {
"QtQuick",
"Window" } },
916 "LayoutMirroring attached property must be attached to an object deriving from Item or Window");
917 addAttachedWarning({
"QtQuick",
"EnterKey" }, { {
"QtQuick",
"Item" } },
918 "EnterKey attached property must be attached to an object deriving from Item");
920 if (hasQuickLayouts) {
921 addAttachedWarning({
"QtQuick.Layouts",
"Layout" }, { {
"QtQuick",
"Item" } },
922 "Layout attached property must be attached to an object deriving from Item");
923 addAttachedWarning({
"QtQuick.Layouts",
"StackLayout" }, { {
"QtQuick",
"Item" } },
924 "StackLayout attached property must be attached to an object deriving from Item");
928 if (hasQuickControls) {
929 manager->registerElementPass(std::make_unique<ControlsSwipeDelegateValidatorPass>(manager));
930 manager->registerPropertyPass(std::make_unique<AttachedPropertyReuse>(
931 manager, attachedReuseCategory),
"",
"");
933 addAttachedWarning({
"QtQuick.Templates",
"ScrollBar" },
934 { {
"QtQuick",
"Flickable" }, {
"QtQuick.Templates",
"ScrollView" } },
935 "ScrollBar attached property must be attached to an object deriving from Flickable or ScrollView");
936 addAttachedWarning({
"QtQuick.Templates",
"ScrollIndicator" },
937 { {
"QtQuick",
"Flickable" } },
938 "ScrollIndicator attached property must be attached to an object deriving from Flickable");
939 addAttachedWarning({
"QtQuick.Templates",
"TextArea" }, { {
"QtQuick",
"Flickable" } },
940 "TextArea attached property must be attached to an object deriving from Flickable");
941 addAttachedWarning({
"QtQuick.Templates",
"SplitView" }, { {
"QtQuick",
"Item" } },
942 "SplitView attached property must be attached to an object deriving from Item");
943 addAttachedWarning({
"QtQuick.Templates",
"StackView" }, { {
"QtQuick",
"Item" } },
944 "StackView attached property must be attached to an object deriving from Item");
945 addAttachedWarning({
"QtQuick.Templates",
"ToolTip" }, { {
"QtQuick",
"Item" } },
946 "ToolTip attached property must be attached to an object deriving from Item");
947 addAttachedWarning({
"QtQuick.Templates",
"SwipeDelegate" }, { {
"QtQuick",
"Item" } },
948 "SwipeDelegate attached property must be attached to an object deriving from Item");
949 addAttachedWarning({
"QtQuick.Templates",
"SwipeView" }, { {
"QtQuick",
"Item" } },
950 "SwipeView attached property must be attached to an object deriving from Item");
951 addVarBindingWarning(
"QtQuick.Templates",
"Tumbler",
952 { {
"contentItem", {
"QtQuick",
"PathView" } },
953 {
"contentItem", {
"QtQuick",
"ListView" } } });
954 addVarBindingWarning(
"QtQuick.Templates",
"SpinBox",
955 { {
"textFromValue", {
"",
"function" } },
956 {
"valueFromText", {
"",
"function" } } });
957 }
else if (attachedReuseCategory != quickControlsAttachedPropertyReuse) {
958 manager->registerPropertyPass(std::make_unique<AttachedPropertyReuse>(
959 manager, attachedReuseCategory),
"",
"");
962 if (manager->hasImportedModule(u"QtQuick.Controls.macOS"_s)
963 || manager->hasImportedModule(u"QtQuick.Controls.Windows"_s))
964 manager->registerElementPass(std::make_unique<ControlsNativeValidatorPass>(manager));
975 return !m_propertyChanges.isNull() && element.inherits(m_propertyChanges);
980 const QQmlSA::Binding::Bindings bindings = element.ownPropertyBindings();
983 std::find_if(bindings.constBegin(), bindings.constEnd(),
984 [](
const auto binding) {
return binding.propertyName() == u"target"_s; });
985 if (target == bindings.constEnd())
988 QString targetId = u"<id>"_s;
989 const auto targetLocation = target.value().sourceLocation();
990 const QString targetBinding = sourceCode(targetLocation);
991 const QQmlSA::Element targetElement = resolveIdToElement(targetBinding, element);
992 if (!targetElement.isNull())
993 targetId = targetBinding;
995 bool hadCustomParsedBindings =
false;
996 for (
auto it = bindings.constBegin(); it != bindings.constEnd(); ++it) {
997 const auto &propertyName = it.key();
998 const auto &propertyBinding = it.value();
999 if (element.hasProperty(propertyName))
1002 const QQmlSA::SourceLocation bindingLocation = propertyBinding.sourceLocation();
1003 if (!targetElement.isNull() && !targetElement.hasProperty(propertyName)) {
1005 "Unknown property \"%1\" in PropertyChanges."_L1.arg(propertyName),
1006 quickPropertyChangesParsed, bindingLocation);
1010 QString binding = sourceCode(bindingLocation);
1011 if (binding.length() > 16)
1012 binding = binding.left(13) +
"..."_L1;
1014 hadCustomParsedBindings =
true;
1015 emitWarning(
"Property \"%1\" is custom-parsed in PropertyChanges. "
1016 "You should phrase this binding as \"%2.%1: %3\""_L1.arg(propertyName, targetId,
1018 quickPropertyChangesParsed, bindingLocation);
1021 if (hadCustomParsedBindings && !targetElement.isNull()) {
1022 emitWarning(
"You should remove any bindings on the \"target\" property and avoid "
1023 "custom-parsed bindings in PropertyChanges.",
1024 quickPropertyChangesParsed, targetLocation);
1039 return element.inherits(m_state);
1044 const auto &childScopes = QQmlJSScope::scope(element)->childScopes();
1045 for (
const auto &child : childScopes) {
1046 if (child->scopeType() != QQmlSA::ScopeType::QMLScope)
1049 if (child->inherits(QQmlJSScope::scope(m_anchorChanges))
1050 || child->inherits(QQmlJSScope::scope(m_parentChanges))
1051 || child->inherits(QQmlJSScope::scope(m_propertyChanges))
1052 || child->inherits(QQmlJSScope::scope(m_stateChangeScript))) {
1055 QString msg =
"A State cannot have a child item of type %1"_L1.arg(child->baseTypeName());
1056 auto loc = QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(
1057 child->sourceLocation());
1058 emitWarning(msg, quickStateNoChildItem, loc);
1064#include "moc_quicklintplugin.cpp"
bool shouldRun(const QQmlSA::Element &element) override
Controls whether 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)
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
Executes whenever a property gets bound to a value.
ControlsNativeValidatorPass(QQmlSA::PassManager *manager)
void run(const QQmlSA::Element &element) override
Executes if shouldRun() returns true.
bool shouldRun(const QQmlSA::Element &element) override
Controls whether the run() function should be executed on the given element.
bool shouldRun(const QQmlSA::Element &element) override
Controls whether 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
Controls whether 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
Controls whether the run() function should be executed on the given element.
void run(const QQmlSA::Element &element) override
Executes if shouldRun() returns true.
StateNoItemChildrenValidator(QQmlSA::PassManager *manager)
bool shouldRun(const QQmlSA::Element &element) override
Controls whether the run() function should be executed on the given element.
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.
Combined button and popup list for selecting options.
static constexpr QQmlSA::LoggerWarningId quickControlsAttachedPropertyReuse
static constexpr QQmlSA::LoggerWarningId quickControlsNativeCustomize
static constexpr QQmlSA::LoggerWarningId quickStateNoChildItem
static constexpr QQmlSA::LoggerWarningId quickAttachedPropertyType
static constexpr QQmlSA::LoggerWarningId quickUnexpectedVarType
static constexpr QQmlSA::LoggerWarningId quickAttachedPropertyReuse
static constexpr QQmlSA::LoggerWarningId quickPropertyChangesParsed
static constexpr QQmlSA::LoggerWarningId quickAnchorCombinations
static constexpr QQmlSA::LoggerWarningId quickLayoutPositioning
static constexpr QQmlSA::LoggerWarningId quickColor