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);
96 "Cannot find attached type for %1/%2"_L1.arg(attachType.module, attachType.name),
97 quickAttachedPropertyType);
101 for (
const TypeDescription &desc : allowedTypes) {
102 const QQmlSA::Element type = resolveType(desc.module, desc.name);
105 elements.push_back(type);
108 m_attachedTypes.insert(
109 { std::make_pair<>(attachedType.internalId(),
110 Warning{ elements, allowInDelegate, warning.toString() }) });
112 return attachedType.internalId();
116 const QQmlSA::Element &scopeUsedIn,
117 const QQmlSA::SourceLocation &location)
119 auto warning = m_attachedTypes.constFind(element.internalId());
120 if (warning == m_attachedTypes.cend())
122 for (
const QQmlSA::Element &type : warning->allowedTypes) {
123 if (scopeUsedIn.inherits(type))
128 if ( QQmlJSScope::scope(scopeUsedIn)->isInCustomParserParent() )
131 if (warning->allowInDelegate) {
132 if (scopeUsedIn.isPropertyRequired(u"index"_s)
133 || scopeUsedIn.isPropertyRequired(u"model"_s))
138 if (scopeUsedIn.isFileRootComponent())
141 for (
const QQmlSA::Binding &binding :
142 scopeUsedIn.parentScope().propertyBindings(u"delegate"_s)) {
143 if (!binding.hasObject())
145 if (binding.objectType() == scopeUsedIn)
150 emitWarning(warning->message, quickAttachedPropertyType, location);
154 const QString &propertyName,
155 const QQmlSA::Binding &binding,
156 const QQmlSA::Element &bindingScope,
157 const QQmlSA::Element &value)
166 if (propertyName.count(QLatin1Char(
'.')) > 1)
169 checkWarnings(bindingScope.baseType(), element, binding.sourceLocation());
173 const QString &propertyName,
174 const QQmlSA::Element &readScope,
175 QQmlSA::SourceLocation location)
179 if (element.hasProperty(propertyName) || element.hasMethod(propertyName))
180 checkWarnings(element, readScope, location);
184 const QString &propertyName,
185 const QQmlSA::Element &value,
186 const QQmlSA::Element &writeScope,
187 QQmlSA::SourceLocation location)
189 Q_UNUSED(propertyName)
192 checkWarnings(element, writeScope, location);
199 ControlElement {
"Control",
200 QStringList {
"background",
"contentItem",
"leftPadding",
"rightPadding",
201 "topPadding",
"bottomPadding",
"horizontalPadding",
202 "verticalPadding",
"padding" },
204 ControlElement {
"Button", QStringList {
"indicator" } },
207 QStringList {
"background",
"contentItem",
"header",
"footer",
"menuBar" } },
208 ControlElement {
"ComboBox", QStringList {
"indicator" } },
209 ControlElement {
"Dial", QStringList {
"handle" } },
210 ControlElement {
"GroupBox", QStringList {
"label" } },
211 ControlElement {
"$internal$.QQuickIndicatorButton", QStringList {
"indicator" },
false },
212 ControlElement {
"Label", QStringList {
"background" } },
213 ControlElement {
"MenuItem", QStringList {
"arrow" } },
214 ControlElement {
"Page", QStringList {
"header",
"footer" } },
215 ControlElement {
"Popup", QStringList {
"background",
"contentItem" } },
216 ControlElement {
"RangeSlider", QStringList {
"handle" } },
217 ControlElement {
"Slider", QStringList {
"handle" } },
218 ControlElement {
"$internal$.QQuickSwipe",
219 QStringList {
"leftItem",
"behindItem",
"rightItem" },
false },
220 ControlElement {
"TextArea", QStringList {
"background" } },
221 ControlElement {
"TextField", QStringList {
"background" } },
224 for (
const QString &module : { u"QtQuick.Controls.macOS"_s, u"QtQuick.Controls.Windows"_s }) {
225 if (!manager->hasImportedModule(module))
228 QQmlSA::Element control = resolveType(module,
"Control");
230 for (ControlElement &element : m_elements) {
231 auto type = resolveType(element.isInModuleControls ? module :
"QtQuick.Templates",
237 element.inheritsControl = !element.isControl && type.inherits(control);
238 element.element = type;
241 m_elements.removeIf([](
const ControlElement &element) {
return element.element.isNull(); });
249 for (
const ControlElement &controlElement : m_elements) {
251 if (controlElement.inheritsControl)
253 if (element.inherits(controlElement.element))
261 for (
const ControlElement &controlElement : m_elements) {
262 if (element.inherits(controlElement.element)) {
263 for (
const QString &propertyName : controlElement.restrictedProperties) {
264 if (element.hasOwnPropertyBindings(propertyName)) {
265 emitWarning(QStringLiteral(
"Not allowed to override \"%1\" because native "
266 "styles cannot be customized: See "
267 "https://doc-snapshots.qt.io/qt6-dev/"
268 "qtquickcontrols-customize.html#customization-"
269 "reference for more information.")
271 quickControlsNativeCustomize, element.sourceLocation());
277 if (!controlElement.isControl)
291 return !m_item.isNull() && element.inherits(m_item)
292 && element.hasOwnPropertyBindings(u"anchors"_s);
297 enum BindingLocation { Exists = 1, Own = (1 << 1) };
298 QHash<QString, qint8> bindings;
300 const QStringList properties = { u"left"_s, u"right"_s, u"horizontalCenter"_s,
301 u"top"_s, u"bottom"_s, u"verticalCenter"_s,
304 QList<QQmlSA::Binding> anchorBindings = element.propertyBindings(u"anchors"_s);
306 for (qsizetype i = anchorBindings.size() - 1; i >= 0; i--) {
307 auto groupType = anchorBindings[i].groupType();
308 if (groupType.isNull())
311 for (
const QString &name : properties) {
313 const auto &propertyBindings = groupType.ownPropertyBindings(name);
314 if (propertyBindings.begin() == propertyBindings.end())
317 bool isUndefined =
false;
318 for (
const auto &propertyBinding : propertyBindings) {
319 if (propertyBinding.hasUndefinedScriptValue()) {
328 bindings[name] |= Exists | ((i == 0) ? Own : 0);
332 auto ownSourceLocation = [&](QStringList properties) -> QQmlSA::SourceLocation {
333 QQmlSA::SourceLocation warnLoc;
335 for (
const QString &name : properties) {
336 if (bindings[name] & Own) {
337 QQmlSA::Element groupType = QQmlSA::Element{ anchorBindings[0].groupType() };
338 auto bindings = groupType.ownPropertyBindings(name);
339 Q_ASSERT(bindings.begin() != bindings.end());
340 warnLoc = bindings.begin().value().sourceLocation();
347 if ((bindings[u"left"_s] & bindings[u"right"_s] & bindings[u"horizontalCenter"_s]) & Exists) {
348 QQmlSA::SourceLocation warnLoc =
349 ownSourceLocation({ u"left"_s, u"right"_s, u"horizontalCenter"_s });
351 if (warnLoc.isValid()) {
353 "Cannot specify left, right, and horizontalCenter anchors at the same time.",
354 quickAnchorCombinations, warnLoc);
358 if ((bindings[u"top"_s] & bindings[u"bottom"_s] & bindings[u"verticalCenter"_s]) & Exists) {
359 QQmlSA::SourceLocation warnLoc =
360 ownSourceLocation({ u"top"_s, u"bottom"_s, u"verticalCenter"_s });
361 if (warnLoc.isValid()) {
362 emitWarning(
"Cannot specify top, bottom, and verticalCenter anchors at the same time.",
363 quickAnchorCombinations, warnLoc);
367 if ((bindings[u"baseline"_s] & (bindings[u"bottom"_s] | bindings[u"verticalCenter"_s]))
369 QQmlSA::SourceLocation warnLoc =
370 ownSourceLocation({ u"baseline"_s, u"bottom"_s, u"verticalCenter"_s });
371 if (warnLoc.isValid()) {
372 emitWarning(
"Baseline anchor cannot be used in conjunction with top, bottom, or "
373 "verticalCenter anchors.",
374 quickAnchorCombinations, warnLoc);
387 return !m_swipeDelegate.isNull() && element.inherits(m_swipeDelegate);
392 for (
const auto &property : { u"background"_s, u"contentItem"_s }) {
393 for (
const auto &binding : element.ownPropertyBindings(property)) {
394 if (!binding.hasObject())
396 const QQmlSA::Element element = QQmlSA::Element{ binding.objectType() };
397 const auto &bindings = element.propertyBindings(u"anchors"_s);
398 if (bindings.isEmpty())
401 if (bindings.first().bindingType() != QQmlSA::BindingType::GroupProperty)
404 auto anchors = bindings.first().groupType();
405 for (
const auto &disallowed : { u"fill"_s, u"centerIn"_s, u"left"_s, u"right"_s }) {
406 if (anchors.hasPropertyBindings(disallowed)) {
407 QQmlSA::SourceLocation location;
408 const auto &ownBindings = anchors.ownPropertyBindings(disallowed);
409 if (ownBindings.begin() != ownBindings.end()) {
410 location = ownBindings.begin().value().sourceLocation();
414 u"SwipeDelegate: Cannot use horizontal anchors with %1; unable to layout the item."_s
416 quickAnchorCombinations, location);
424 const auto &swipe = element.ownPropertyBindings(u"swipe"_s);
425 if (swipe.begin() == swipe.end())
428 const auto firstSwipe = swipe.begin().value();
432 auto group = firstSwipe.groupType();
434 const std::array ownDirBindings = { group.ownPropertyBindings(u"right"_s),
435 group.ownPropertyBindings(u"left"_s),
436 group.ownPropertyBindings(u"behind"_s) };
438 auto ownBindingIterator =
439 std::find_if(ownDirBindings.begin(), ownDirBindings.end(),
440 [](
const auto &bindings) {
return bindings.begin() != bindings.end(); });
442 if (ownBindingIterator == ownDirBindings.end())
445 if (group.hasPropertyBindings(u"behind"_s)
446 && (group.hasPropertyBindings(u"right"_s) || group.hasPropertyBindings(u"left"_s))) {
447 emitWarning(
"SwipeDelegate: Cannot set both behind and left/right properties",
448 quickAnchorCombinations, ownBindingIterator->begin().value().sourceLocation());
453 QQmlSA::PassManager *manager,
454 const QMultiHash<QString, TypeDescription> &expectedPropertyTypes)
457 QMultiHash<QString, QQmlSA::Element> propertyTypes;
459 for (
const auto &pair : expectedPropertyTypes.asKeyValueRange()) {
460 const QQmlSA::Element propType = pair.second.module.isEmpty()
461 ? resolveBuiltinType(pair.second.name)
462 : resolveType(pair.second.module, pair.second.name);
463 if (!propType.isNull())
464 propertyTypes.insert(pair.first, propType);
467 m_expectedPropertyTypes = propertyTypes;
471 const QString &propertyName,
472 const QQmlSA::Binding &binding,
473 const QQmlSA::Element &bindingScope,
474 const QQmlSA::Element &value)
477 Q_UNUSED(bindingScope);
479 const auto range = m_expectedPropertyTypes.equal_range(propertyName);
481 if (range.first == range.second)
484 QQmlSA::Element bindingType;
486 if (!value.isNull()) {
489 if (QQmlSA::Binding::isLiteralBinding(binding.bindingType())) {
490 bindingType = resolveLiteralType(binding);
492 switch (binding.bindingType()) {
493 case QQmlSA::BindingType::Object:
494 bindingType = QQmlSA::Element{ binding.objectType() };
504 if (std::find_if(range.first, range.second,
505 [&](
const QQmlSA::Element &scope) {
return bindingType.inherits(scope); })
508 const bool bindingTypeIsComposite = bindingType.isComposite();
509 if (bindingTypeIsComposite && !bindingType.baseType()) {
511
512
513
514
515
518 const QString bindingTypeName =
519 bindingTypeIsComposite ? bindingType.baseType().name()
520 : bindingType.name();
521 QStringList expectedTypeNames;
523 for (
auto it = range.first; it != range.second; it++)
524 expectedTypeNames << it.value().name();
526 emitWarning(u"Unexpected type for property \"%1\" expected %2 got %3"_s.arg(
527 propertyName, expectedTypeNames.join(u", "_s), bindingTypeName),
528 quickUnexpectedVarType, binding.sourceLocation());
537 void onBinding(
const QQmlSA::Element &element,
const QString &propertyName,
538 const QQmlSA::Binding &binding,
const QQmlSA::Element &bindingScope,
539 const QQmlSA::Element &value)
override;
541 QQmlSA::Element m_colorType;
544 static inline const QRegularExpression s_hexPattern{
"^#((([0-9A-Fa-f]{3}){1,2})|(([0-9A-Fa-f]{4}){1,2}))$"_L1 };
546 QStringList m_colorNames = {
617 u"lightgoldenrodyellow"_s,
634 u"mediumaquamarine"_s,
639 u"mediumslateblue"_s,
640 u"mediumspringgreen"_s,
641 u"mediumturquoise"_s,
642 u"mediumvioletred"_s,
701 Q_ASSERT_X(std::is_sorted(m_colorNames.cbegin(), m_colorNames.cend()),
"ColorValidatorPass",
702 "m_colorNames should be sorted!");
706 const QQmlSA::Binding &binding,
const QQmlSA::Element &,
707 const QQmlSA::Element &)
711 const auto propertyType = element.property(propertyName).type();
712 if (!propertyType || propertyType != m_colorType)
715 QString colorName = binding.stringValue();
718 if (!colorName.startsWith(u'#'))
719 colorName = std::move(colorName).toLower();
720 if (s_hexPattern.match(colorName).hasMatch())
723 if (std::binary_search(m_colorNames.cbegin(), m_colorNames.cend(), colorName))
726 if (colorName == u"transparent")
729 auto suggestion = QQmlJSUtils::didYouMean(
730 colorName, m_colorNames,
731 QQmlSA::SourceLocationPrivate::sourceLocation(binding.sourceLocation()));
733 emitWarningWithOptionalFix(*
this,
"Invalid color \"%1\"."_L1.arg(colorName), quickColor,
734 binding.sourceLocation(), suggestion);
738 const QQmlSA::Element &readScope,
739 QQmlSA::SourceLocation location)
741 const auto range = usedAttachedTypes.equal_range(readScope);
742 const auto attachedTypeAndLocation = std::find_if(
743 range.first, range.second, [&](
const ElementAndLocation &elementAndLocation) {
744 return elementAndLocation.element == element;
746 if (attachedTypeAndLocation != range.second) {
747 const QQmlSA::SourceLocation attachedLocation = attachedTypeAndLocation->location;
751 if (!element.hasProperty(propertyName) && !element.hasMethod(propertyName))
754 for (QQmlSA::Element scope = readScope.parentScope(); !scope.isNull();
755 scope = scope.parentScope()) {
756 const auto range = usedAttachedTypes.equal_range(scope);
758 for (
auto it = range.first; it != range.second; ++it) {
759 if (it->element == element) {
767 const QString id = resolveElementToId(scope, readScope);
768 const QQmlSA::SourceLocation idInsertLocation{ attachedLocation.offset(), 0,
769 attachedLocation.startLine(),
770 attachedLocation.startColumn() };
771 QString m =
"Reference it by id instead%1:"_L1;
772 m = m.arg(id.isEmpty() ?
" (You first have to give the element and id)"_L1 :
""_L1);
773 QQmlSA::FixSuggestion suggestion{ m, idInsertLocation,
774 id.isEmpty() ? u"<id>."_s : (id +
'.'_L1) };
777 suggestion.setAutoApplicable();
779 emitWarning(
"Using attached type %1 already initialized in a parent scope."_L1.arg(
781 category, attachedLocation, suggestion);
788 if (element.hasProperty(propertyName))
791 QQmlSA::Element type = resolveTypeInFileScope(propertyName);
792 QQmlSA::Element attached = resolveAttachedInFileScope(propertyName);
793 if (!type || !attached)
796 if (category == quickControlsAttachedPropertyReuse) {
797 for (QQmlSA::Element parent = attached; parent; parent = parent.baseType()) {
800 if (parent.internalId() ==
"QQuickAttachedPropertyPropagator"_L1) {
801 usedAttachedTypes.insert(readScope, {attached, location});
807 usedAttachedTypes.insert(readScope, {attached, location});
812 const QQmlSA::Element &value,
const QQmlSA::Element &writeScope,
813 QQmlSA::SourceLocation location)
816 onRead(element, propertyName, writeScope, location);
820 const QQmlSA::Element &rootElement)
822 const QQmlSA::LoggerWarningId attachedReuseCategory = [manager]() {
823 if (manager->isCategoryEnabled(quickAttachedPropertyReuse))
824 return quickAttachedPropertyReuse;
825 if (manager->isCategoryEnabled(qmlAttachedPropertyReuse))
826 return qmlAttachedPropertyReuse;
827 return quickControlsAttachedPropertyReuse;
830 const bool hasQuick = manager->hasImportedModule(
"QtQuick");
831 const bool hasQuickLayouts = manager->hasImportedModule(
"QtQuick.Layouts");
832 const bool hasQuickControls = manager->hasImportedModule(
"QtQuick.Templates")
833 || manager->hasImportedModule(
"QtQuick.Controls")
834 || manager->hasImportedModule(
"QtQuick.Controls.Basic");
836 Q_UNUSED(rootElement);
839 manager->registerElementPass(std::make_unique<AnchorsValidatorPass>(manager));
840 manager->registerElementPass(std::make_unique<PropertyChangesValidatorPass>(manager));
841 manager->registerElementPass(std::make_unique<StateNoItemChildrenValidator>(manager));
842 manager->registerPropertyPass(std::make_unique<QQuickLiteralBindingCheck>(manager),
843 QAnyStringView(), QAnyStringView());
844 manager->registerPropertyPass(std::make_unique<ColorValidatorPass>(manager),
845 QAnyStringView(), QAnyStringView());
847 auto forbiddenChildProperty =
848 std::make_unique<ForbiddenChildrenPropertyValidatorPass>(manager);
850 for (
const QString &element : { u"Grid"_s, u"Flow"_s }) {
851 for (
const QString &property : { u"anchors"_s, u"x"_s, u"y"_s }) {
852 forbiddenChildProperty->addWarning(
853 "QtQuick", element, property,
854 u"Cannot specify %1 for items inside %2. %2 will not function."_s.arg(
859 if (hasQuickLayouts) {
860 forbiddenChildProperty->addWarning(
861 "QtQuick.Layouts",
"Layout",
"anchors",
862 "Detected anchors on an item that is managed by a layout. This is undefined "
863 u"behavior; use Layout.alignment instead.");
864 forbiddenChildProperty->addWarning(
865 "QtQuick.Layouts",
"Layout",
"x",
866 "Detected x on an item that is managed by a layout. This is undefined "
867 u"behavior; use Layout.leftMargin or Layout.rightMargin instead.");
868 forbiddenChildProperty->addWarning(
869 "QtQuick.Layouts",
"Layout",
"y",
870 "Detected y on an item that is managed by a layout. This is undefined "
871 u"behavior; use Layout.topMargin or Layout.bottomMargin instead.");
872 forbiddenChildProperty->addWarning(
873 "QtQuick.Layouts",
"Layout",
"width",
874 "Detected width on an item that is managed by a layout. This is undefined "
875 u"behavior; use implicitWidth or Layout.preferredWidth instead.");
876 forbiddenChildProperty->addWarning(
877 "QtQuick.Layouts",
"Layout",
"height",
878 "Detected height on an item that is managed by a layout. This is undefined "
879 u"behavior; use implictHeight or Layout.preferredHeight instead.");
882 manager->registerElementPass(std::move(forbiddenChildProperty));
885 auto attachedPropertyType = std::make_shared<AttachedPropertyTypeValidatorPass>(manager);
887 auto addAttachedWarning = [&](
TypeDescription attachedType, QList<TypeDescription> allowedTypes,
888 QAnyStringView warning,
bool allowInDelegate =
false) {
889 QString attachedTypeName = attachedPropertyType->addWarning(attachedType, allowedTypes,
890 allowInDelegate, warning);
891 if (attachedTypeName.isEmpty())
894 manager->registerPropertyPass(attachedPropertyType, attachedType.module,
895 u"$internal$."_s + attachedTypeName, {},
false);
898 auto addVarBindingWarning =
899 [&](QAnyStringView moduleName, QAnyStringView typeName,
900 const QMultiHash<QString, TypeDescription> &expectedPropertyTypes) {
901 auto varBindingType = std::make_shared<VarBindingTypeValidatorPass>(
902 manager, expectedPropertyTypes);
903 for (
const auto &propertyName : expectedPropertyTypes.uniqueKeys()) {
904 manager->registerPropertyPass(varBindingType, moduleName, typeName,
910 addVarBindingWarning(
"QtQuick",
"TableView",
911 { {
"columnWidthProvider", {
"",
"function" } },
912 {
"rowHeightProvider", {
"",
"function" } } });
913 addAttachedWarning({
"QtQuick",
"Accessible" },
914 { {
"QtQuick",
"Item" }, {
"QtQuick.Templates",
"Action" } },
915 "Accessible attached property must be attached to an object deriving "
916 "from Item or Action");
917 addAttachedWarning({
"QtQuick",
"LayoutMirroring" },
918 { {
"QtQuick",
"Item" }, {
"QtQuick",
"Window" } },
919 "LayoutMirroring attached property must be attached to an object deriving from Item or Window");
920 addAttachedWarning({
"QtQuick",
"EnterKey" }, { {
"QtQuick",
"Item" } },
921 "EnterKey attached property must be attached to an object deriving from Item");
923 if (hasQuickLayouts) {
924 addAttachedWarning({
"QtQuick.Layouts",
"Layout" }, { {
"QtQuick",
"Item" } },
925 "Layout attached property must be attached to an object deriving from Item");
926 addAttachedWarning({
"QtQuick.Layouts",
"StackLayout" }, { {
"QtQuick",
"Item" } },
927 "StackLayout attached property must be attached to an object deriving from Item");
931 if (hasQuickControls) {
932 manager->registerElementPass(std::make_unique<ControlsSwipeDelegateValidatorPass>(manager));
933 manager->registerPropertyPass(std::make_unique<AttachedPropertyReuse>(
934 manager, attachedReuseCategory),
"",
"");
936 addAttachedWarning({
"QtQuick.Templates",
"ScrollBar" },
937 { {
"QtQuick",
"Flickable" }, {
"QtQuick.Templates",
"ScrollView" } },
938 "ScrollBar attached property must be attached to an object deriving from Flickable or ScrollView");
939 addAttachedWarning({
"QtQuick.Templates",
"ScrollIndicator" },
940 { {
"QtQuick",
"Flickable" } },
941 "ScrollIndicator attached property must be attached to an object deriving from Flickable");
942 addAttachedWarning({
"QtQuick.Templates",
"TextArea" }, { {
"QtQuick",
"Flickable" } },
943 "TextArea attached property must be attached to an object deriving from Flickable");
944 addAttachedWarning({
"QtQuick.Templates",
"SplitView" }, { {
"QtQuick",
"Item" } },
945 "SplitView attached property must be attached to an object deriving from Item");
946 addAttachedWarning({
"QtQuick.Templates",
"StackView" }, { {
"QtQuick",
"Item" } },
947 "StackView attached property must be attached to an object deriving from Item");
948 addAttachedWarning({
"QtQuick.Templates",
"ToolTip" }, { {
"QtQuick",
"Item" } },
949 "ToolTip attached property must be attached to an object deriving from Item");
950 addAttachedWarning({
"QtQuick.Templates",
"SwipeDelegate" }, { {
"QtQuick",
"Item" } },
951 "SwipeDelegate attached property must be attached to an object deriving from Item");
952 addAttachedWarning({
"QtQuick.Templates",
"SwipeView" }, { {
"QtQuick",
"Item" } },
953 "SwipeView attached property must be attached to an object deriving from Item");
954 addVarBindingWarning(
"QtQuick.Templates",
"Tumbler",
955 { {
"contentItem", {
"QtQuick",
"PathView" } },
956 {
"contentItem", {
"QtQuick",
"ListView" } } });
957 addVarBindingWarning(
"QtQuick.Templates",
"SpinBox",
958 { {
"textFromValue", {
"",
"function" } },
959 {
"valueFromText", {
"",
"function" } } });
960 }
else if (attachedReuseCategory != quickControlsAttachedPropertyReuse) {
961 manager->registerPropertyPass(std::make_unique<AttachedPropertyReuse>(
962 manager, attachedReuseCategory),
"",
"");
965 if (manager->hasImportedModule(u"QtQuick.Controls.macOS"_s)
966 || manager->hasImportedModule(u"QtQuick.Controls.Windows"_s))
967 manager->registerElementPass(std::make_unique<ControlsNativeValidatorPass>(manager));
978 return !m_propertyChanges.isNull() && element.inherits(m_propertyChanges);
983 const QQmlSA::Binding::Bindings bindings = element.ownPropertyBindings();
986 std::find_if(bindings.constBegin(), bindings.constEnd(),
987 [](
const auto binding) {
return binding.propertyName() == u"target"_s; });
988 if (target == bindings.constEnd())
991 QString targetId = u"<id>"_s;
992 const auto targetLocation = target.value().sourceLocation();
993 const QString targetBinding = sourceCode(targetLocation);
994 const QQmlSA::Element targetElement = resolveIdToElement(targetBinding, element);
995 if (!targetElement.isNull())
996 targetId = targetBinding;
998 bool hadCustomParsedBindings =
false;
999 for (
auto it = bindings.constBegin(); it != bindings.constEnd(); ++it) {
1000 const auto &propertyName = it.key();
1001 const auto &propertyBinding = it.value();
1002 if (element.hasProperty(propertyName))
1005 const QQmlSA::SourceLocation bindingLocation = propertyBinding.sourceLocation();
1006 if (!targetElement.isNull() && !targetElement.hasProperty(propertyName)) {
1008 "Unknown property \"%1\" in PropertyChanges."_L1.arg(propertyName),
1009 quickPropertyChangesParsed, bindingLocation);
1013 QString binding = sourceCode(bindingLocation);
1014 if (binding.length() > 16)
1015 binding = binding.left(13) +
"..."_L1;
1017 hadCustomParsedBindings =
true;
1018 emitWarning(
"Property \"%1\" is custom-parsed in PropertyChanges. "
1019 "You should phrase this binding as \"%2.%1: %3\""_L1.arg(propertyName, targetId,
1021 quickPropertyChangesParsed, bindingLocation);
1024 if (hadCustomParsedBindings && !targetElement.isNull()) {
1025 emitWarning(
"You should remove any bindings on the \"target\" property and avoid "
1026 "custom-parsed bindings in PropertyChanges.",
1027 quickPropertyChangesParsed, targetLocation);
1042 return element.inherits(m_state);
1047 const auto &childScopes = QQmlJSScope::scope(element)->childScopes();
1048 for (
const auto &child : childScopes) {
1049 if (child->scopeType() != QQmlSA::ScopeType::QMLScope)
1052 if (child->inherits(QQmlJSScope::scope(m_anchorChanges))
1053 || child->inherits(QQmlJSScope::scope(m_parentChanges))
1054 || child->inherits(QQmlJSScope::scope(m_propertyChanges))
1055 || child->inherits(QQmlJSScope::scope(m_stateChangeScript))) {
1058 QString msg =
"A State cannot have a child item of type %1"_L1.arg(child->baseTypeName());
1059 auto loc = QQmlSA::SourceLocationPrivate::createQQmlSASourceLocation(
1060 child->sourceLocation());
1061 emitWarning(msg, quickStateNoChildItem, loc);
1067#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