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;
543 static inline const QRegularExpression s_hexPattern{
"^#[0-9A-Fa-f]{6}([0-9A-Fa-f]{2})?$"_L1 };
545 QStringList m_colorNames = {
616 u"lightgoldenrodyellow"_s,
633 u"mediumaquamarine"_s,
638 u"mediumslateblue"_s,
639 u"mediumspringgreen"_s,
640 u"mediumturquoise"_s,
641 u"mediumvioletred"_s,
700 Q_ASSERT_X(std::is_sorted(m_colorNames.cbegin(), m_colorNames.cend()),
"ColorValidatorPass",
701 "m_colorNames should be sorted!");
705 const QQmlSA::Binding &binding,
const QQmlSA::Element &,
706 const QQmlSA::Element &)
710 const auto propertyType = element.property(propertyName).type();
711 if (!propertyType || propertyType != m_colorType)
714 QString colorName = binding.stringValue();
717 if (!colorName.startsWith(u'#'))
718 colorName = std::move(colorName).toLower();
719 if (s_hexPattern.match(colorName).hasMatch())
722 if (std::binary_search(m_colorNames.cbegin(), m_colorNames.cend(), colorName))
725 if (colorName == u"transparent")
728 auto suggestion = QQmlJSUtils::didYouMean(
729 colorName, m_colorNames,
730 QQmlSA::SourceLocationPrivate::sourceLocation(binding.sourceLocation()));
732 emitWarningWithOptionalFix(*
this,
"Invalid color \"%1\"."_L1.arg(colorName), quickColor,
733 binding.sourceLocation(), suggestion);
737 const QQmlSA::Element &readScope,
738 QQmlSA::SourceLocation location)
740 const auto range = usedAttachedTypes.equal_range(readScope);
741 const auto attachedTypeAndLocation = std::find_if(
742 range.first, range.second, [&](
const ElementAndLocation &elementAndLocation) {
743 return elementAndLocation.element == element;
745 if (attachedTypeAndLocation != range.second) {
746 const QQmlSA::SourceLocation attachedLocation = attachedTypeAndLocation->location;
750 if (!element.hasProperty(propertyName) && !element.hasMethod(propertyName))
753 for (QQmlSA::Element scope = readScope.parentScope(); !scope.isNull();
754 scope = scope.parentScope()) {
755 const auto range = usedAttachedTypes.equal_range(scope);
757 for (
auto it = range.first; it != range.second; ++it) {
758 if (it->element == element) {
766 const QString id = resolveElementToId(scope, readScope);
767 const QQmlSA::SourceLocation idInsertLocation{ attachedLocation.offset(), 0,
768 attachedLocation.startLine(),
769 attachedLocation.startColumn() };
770 QQmlSA::FixSuggestion suggestion{
"Reference it by id instead:"_L1, idInsertLocation,
771 id.isEmpty() ? u"<id>."_s : (id +
'.'_L1) };
774 suggestion.setHint(
"You first have to give the element an id"_L1);
776 suggestion.setAutoApplicable();
778 emitWarning(
"Using attached type %1 already initialized in a parent scope."_L1.arg(
780 category, attachedLocation, suggestion);
787 if (element.hasProperty(propertyName))
790 QQmlSA::Element type = resolveTypeInFileScope(propertyName);
791 QQmlSA::Element attached = resolveAttachedInFileScope(propertyName);
792 if (!type || !attached)
795 if (category == quickControlsAttachedPropertyReuse) {
796 for (QQmlSA::Element parent = attached; parent; parent = parent.baseType()) {
799 if (parent.internalId() ==
"QQuickAttachedPropertyPropagator"_L1) {
800 usedAttachedTypes.insert(readScope, {attached, location});
806 usedAttachedTypes.insert(readScope, {attached, location});
811 const QQmlSA::Element &value,
const QQmlSA::Element &writeScope,
812 QQmlSA::SourceLocation location)
815 onRead(element, propertyName, writeScope, location);
819 const QQmlSA::Element &rootElement)
821 const QQmlSA::LoggerWarningId attachedReuseCategory = [manager]() {
822 if (manager->isCategoryEnabled(quickAttachedPropertyReuse))
823 return quickAttachedPropertyReuse;
824 if (manager->isCategoryEnabled(qmlAttachedPropertyReuse))
825 return qmlAttachedPropertyReuse;
826 return quickControlsAttachedPropertyReuse;
829 const bool hasQuick = manager->hasImportedModule(
"QtQuick");
830 const bool hasQuickLayouts = manager->hasImportedModule(
"QtQuick.Layouts");
831 const bool hasQuickControls = manager->hasImportedModule(
"QtQuick.Templates")
832 || manager->hasImportedModule(
"QtQuick.Controls")
833 || manager->hasImportedModule(
"QtQuick.Controls.Basic");
835 Q_UNUSED(rootElement);
838 manager->registerElementPass(std::make_unique<AnchorsValidatorPass>(manager));
839 manager->registerElementPass(std::make_unique<PropertyChangesValidatorPass>(manager));
840 manager->registerElementPass(std::make_unique<StateNoItemChildrenValidator>(manager));
841 manager->registerPropertyPass(std::make_unique<QQuickLiteralBindingCheck>(manager),
842 QAnyStringView(), QAnyStringView());
843 manager->registerPropertyPass(std::make_unique<ColorValidatorPass>(manager),
844 QAnyStringView(), QAnyStringView());
846 auto forbiddenChildProperty =
847 std::make_unique<ForbiddenChildrenPropertyValidatorPass>(manager);
849 for (
const QString &element : { u"Grid"_s, u"Flow"_s }) {
850 for (
const QString &property : { u"anchors"_s, u"x"_s, u"y"_s }) {
851 forbiddenChildProperty->addWarning(
852 "QtQuick", element, property,
853 u"Cannot specify %1 for items inside %2. %2 will not function."_s.arg(
858 if (hasQuickLayouts) {
859 forbiddenChildProperty->addWarning(
860 "QtQuick.Layouts",
"Layout",
"anchors",
861 "Detected anchors on an item that is managed by a layout. This is undefined "
862 u"behavior; use Layout.alignment instead.");
863 forbiddenChildProperty->addWarning(
864 "QtQuick.Layouts",
"Layout",
"x",
865 "Detected x on an item that is managed by a layout. This is undefined "
866 u"behavior; use Layout.leftMargin or Layout.rightMargin instead.");
867 forbiddenChildProperty->addWarning(
868 "QtQuick.Layouts",
"Layout",
"y",
869 "Detected y on an item that is managed by a layout. This is undefined "
870 u"behavior; use Layout.topMargin or Layout.bottomMargin instead.");
871 forbiddenChildProperty->addWarning(
872 "QtQuick.Layouts",
"Layout",
"width",
873 "Detected width on an item that is managed by a layout. This is undefined "
874 u"behavior; use implicitWidth or Layout.preferredWidth instead.");
875 forbiddenChildProperty->addWarning(
876 "QtQuick.Layouts",
"Layout",
"height",
877 "Detected height on an item that is managed by a layout. This is undefined "
878 u"behavior; use implictHeight or Layout.preferredHeight instead.");
881 manager->registerElementPass(std::move(forbiddenChildProperty));
884 auto attachedPropertyType = std::make_shared<AttachedPropertyTypeValidatorPass>(manager);
886 auto addAttachedWarning = [&](
TypeDescription attachedType, QList<TypeDescription> allowedTypes,
887 QAnyStringView warning,
bool allowInDelegate =
false) {
888 QString attachedTypeName = attachedPropertyType->addWarning(attachedType, allowedTypes,
889 allowInDelegate, warning);
890 if (attachedTypeName.isEmpty())
893 manager->registerPropertyPass(attachedPropertyType, attachedType.module,
894 u"$internal$."_s + attachedTypeName, {},
false);
897 auto addVarBindingWarning =
898 [&](QAnyStringView moduleName, QAnyStringView typeName,
899 const QMultiHash<QString, TypeDescription> &expectedPropertyTypes) {
900 auto varBindingType = std::make_shared<VarBindingTypeValidatorPass>(
901 manager, expectedPropertyTypes);
902 for (
const auto &propertyName : expectedPropertyTypes.uniqueKeys()) {
903 manager->registerPropertyPass(varBindingType, moduleName, typeName,
909 addVarBindingWarning(
"QtQuick",
"TableView",
910 { {
"columnWidthProvider", {
"",
"function" } },
911 {
"rowHeightProvider", {
"",
"function" } } });
912 addAttachedWarning({
"QtQuick",
"Accessible" }, { {
"QtQuick",
"Item" } },
913 "Accessible attached property must be attached to an object deriving 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