2022-03-21 13:13:08 +00:00
|
|
|
/****************************************************************************
|
|
|
|
**
|
|
|
|
** Copyright (C) 2022 The Qt Company Ltd.
|
|
|
|
** Contact: https://www.qt.io/licensing/
|
|
|
|
**
|
|
|
|
** This file is part of the tools applications of the Qt Toolkit.
|
|
|
|
**
|
|
|
|
** $QT_BEGIN_LICENSE:GPL-EXCEPT$
|
|
|
|
** Commercial License Usage
|
|
|
|
** Licensees holding valid commercial Qt licenses may use this file in
|
|
|
|
** accordance with the commercial license agreement provided with the
|
|
|
|
** Software or, alternatively, in accordance with the terms contained in
|
|
|
|
** a written agreement between you and The Qt Company. For licensing terms
|
|
|
|
** and conditions see https://www.qt.io/terms-conditions. For further
|
|
|
|
** information use the contact form at https://www.qt.io/contact-us.
|
|
|
|
**
|
|
|
|
** GNU General Public License Usage
|
|
|
|
** Alternatively, this file may be used under the terms of the GNU
|
|
|
|
** General Public License version 3 as published by the Free Software
|
|
|
|
** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
|
|
|
|
** included in the packaging of this file. Please review the following
|
|
|
|
** information to ensure the GNU General Public License requirements will
|
|
|
|
** be met: https://www.gnu.org/licenses/gpl-3.0.html.
|
|
|
|
**
|
|
|
|
** $QT_END_LICENSE$
|
|
|
|
**
|
|
|
|
****************************************************************************/
|
|
|
|
|
|
|
|
#include "quicklintplugin.h"
|
|
|
|
|
|
|
|
LayoutChildrenValidatorPass::LayoutChildrenValidatorPass(QQmlSA::PassManager *manager)
|
|
|
|
: QQmlSA::ElementPass(manager)
|
|
|
|
{
|
|
|
|
m_layout = resolveType("QtQuick.Layouts", "Layout");
|
|
|
|
}
|
|
|
|
|
|
|
|
bool LayoutChildrenValidatorPass::shouldRun(const QQmlSA::Element &element)
|
|
|
|
{
|
|
|
|
return !m_layout.isNull() && element->parentScope()
|
|
|
|
&& element->parentScope()->inherits(m_layout);
|
|
|
|
}
|
|
|
|
|
|
|
|
void LayoutChildrenValidatorPass::run(const QQmlSA::Element &element)
|
|
|
|
{
|
|
|
|
auto bindings = element->propertyBindings(u"anchors"_qs);
|
|
|
|
if (!bindings.empty())
|
|
|
|
emitWarning(u"Detected anchors on an item that is managed by a layout. This is undefined "
|
|
|
|
u"behavior; use Layout.alignment instead.",
|
|
|
|
element->sourceLocation());
|
|
|
|
}
|
|
|
|
|
2022-04-12 13:59:13 +00:00
|
|
|
ControlsNativeValidatorPass::ControlsNativeValidatorPass(QQmlSA::PassManager *manager)
|
|
|
|
: QQmlSA::ElementPass(manager)
|
|
|
|
{
|
|
|
|
m_elements = {
|
|
|
|
ControlElement { "Control",
|
|
|
|
QStringList { "background", "contentItem", "leftPadding", "rightPadding",
|
|
|
|
"topPadding", "bottomPadding", "horizontalPadding",
|
|
|
|
"verticalPadding", "padding" },
|
|
|
|
false, true },
|
|
|
|
ControlElement { "Button", QStringList { "indicator" } },
|
|
|
|
ControlElement {
|
|
|
|
"ApplicationWindow",
|
|
|
|
QStringList { "background", "contentItem", "header", "footer", "menuBar" } },
|
|
|
|
ControlElement { "ComboBox", QStringList { "indicator" } },
|
|
|
|
ControlElement { "Dial", QStringList { "handle" } },
|
|
|
|
ControlElement { "Dialog", QStringList { "header", "footer" } },
|
|
|
|
ControlElement { "GroupBox", QStringList { "label" } },
|
|
|
|
ControlElement { "$internal$.QQuickIndicatorButton", QStringList { "indicator" }, false },
|
|
|
|
ControlElement { "Label", QStringList { "background" } },
|
|
|
|
ControlElement { "MenuItem", QStringList { "arrow" } },
|
|
|
|
ControlElement { "Page", QStringList { "header", "footer" } },
|
|
|
|
ControlElement { "Popup", QStringList { "background", "contentItem" } },
|
|
|
|
ControlElement { "RangeSlider", QStringList { "handle" } },
|
|
|
|
ControlElement { "Slider", QStringList { "handle" } },
|
|
|
|
ControlElement { "$internal$.QQuickSwipe",
|
|
|
|
QStringList { "leftItem", "behindItem", "rightItem" }, false },
|
|
|
|
ControlElement { "TextArea", QStringList { "background" } },
|
|
|
|
ControlElement { "TextField", QStringList { "background" } },
|
|
|
|
};
|
|
|
|
|
|
|
|
for (const QString &module : { u"QtQuick.Controls.macOS"_qs, u"QtQuick.Controls.Windows"_qs }) {
|
|
|
|
if (!manager->hasImportedModule(module))
|
|
|
|
continue;
|
|
|
|
|
|
|
|
QQmlSA::Element control = resolveType(module, "Control");
|
|
|
|
|
|
|
|
for (ControlElement &element : m_elements) {
|
|
|
|
auto type = resolveType(element.isInModuleControls ? module : "QtQuick.Templates",
|
|
|
|
element.name);
|
|
|
|
|
|
|
|
if (type.isNull())
|
|
|
|
continue;
|
|
|
|
|
|
|
|
element.inheritsControl = !element.isControl && type->inherits(control);
|
|
|
|
element.element = type;
|
|
|
|
}
|
|
|
|
|
|
|
|
m_elements.removeIf([](const ControlElement &element) { return element.element.isNull(); });
|
|
|
|
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool ControlsNativeValidatorPass::shouldRun(const QQmlSA::Element &element)
|
|
|
|
{
|
|
|
|
for (const ControlElement &controlElement : m_elements) {
|
|
|
|
// If our element inherits control, we don't have to individually check for them here.
|
|
|
|
if (controlElement.inheritsControl)
|
|
|
|
continue;
|
|
|
|
if (element->inherits(controlElement.element))
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
void ControlsNativeValidatorPass::run(const QQmlSA::Element &element)
|
|
|
|
{
|
|
|
|
for (const ControlElement &controlElement : m_elements) {
|
|
|
|
if (element->inherits(controlElement.element)) {
|
|
|
|
for (const QString &propertyName : controlElement.restrictedProperties) {
|
|
|
|
if (element->hasOwnPropertyBindings(propertyName)) {
|
|
|
|
emitWarning(QStringLiteral("Not allowed to override \"%1\" because native "
|
|
|
|
"styles cannot be customized: See "
|
|
|
|
"https://doc-snapshots.qt.io/qt6-dev/"
|
|
|
|
"qtquickcontrols2-customize.html#customization-"
|
|
|
|
"reference for more information.")
|
|
|
|
.arg(propertyName),
|
|
|
|
element->sourceLocation());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// Since all the different types we have rules for don't inherit from each other (except
|
|
|
|
// for Control) we don't have to keep checking whether other types match once we've
|
|
|
|
// found one that has been inherited from.
|
|
|
|
if (!controlElement.isControl)
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-04-07 10:35:48 +00:00
|
|
|
void QmlLintQuickPlugin::registerPasses(QQmlSA::PassManager *manager,
|
2022-03-21 13:13:08 +00:00
|
|
|
const QQmlSA::Element &rootElement)
|
|
|
|
{
|
|
|
|
Q_UNUSED(rootElement);
|
2022-04-12 13:59:13 +00:00
|
|
|
if (manager->hasImportedModule(u"QtQuick.Layouts"_qs))
|
|
|
|
manager->registerElementPass(std::make_unique<LayoutChildrenValidatorPass>(manager));
|
|
|
|
|
|
|
|
if (manager->hasImportedModule(u"QtQuick.Controls.macOS"_qs)
|
|
|
|
|| manager->hasImportedModule(u"QtQuick.Controls.Windows"_qs))
|
|
|
|
manager->registerElementPass(std::make_unique<ControlsNativeValidatorPass>(manager));
|
2022-03-21 13:13:08 +00:00
|
|
|
}
|