diff options
Diffstat (limited to 'tests/auto/qml/qmllint')
372 files changed, 6139 insertions, 228 deletions
diff --git a/tests/auto/qml/qmllint/CMakeLists.txt b/tests/auto/qml/qmllint/CMakeLists.txt index 2518740101..5a3e2d9c0d 100644 --- a/tests/auto/qml/qmllint/CMakeLists.txt +++ b/tests/auto/qml/qmllint/CMakeLists.txt @@ -1,23 +1,37 @@ +# Copyright (C) 2022 The Qt Company Ltd. +# SPDX-License-Identifier: BSD-3-Clause + # Generated from qmllint.pro. ##################################################################### ## tst_qmllint Test: ##################################################################### +if(NOT QT_BUILD_STANDALONE_TESTS AND NOT QT_BUILDING_QT) + cmake_minimum_required(VERSION 3.16) + project(tst_qmllint LANGUAGES CXX) + find_package(Qt6BuildInternals REQUIRED COMPONENTS STANDALONE_TEST) +endif() + # Collect test data file(GLOB_RECURSE test_data_glob RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} data/*) list(APPEND test_data ${test_data_glob}) +add_library(LintPlugin STATIC lintplugin.h lintplugin.cpp) +target_link_libraries(LintPlugin PRIVATE Qt::QmlCompilerPrivate) +qt_autogen_tools_initial_setup(LintPlugin) +target_compile_definitions(LintPlugin PRIVATE QT_STATICPLUGIN) + qt_internal_add_test(tst_qmllint SOURCES - ../../shared/util.cpp ../../shared/util.h tst_qmllint.cpp - INCLUDE_DIRECTORIES - ../../shared - PUBLIC_LIBRARIES + LIBRARIES Qt::Gui + Qt::QuickTestUtilsPrivate + Qt::QmlCompilerPrivate + LintPlugin TESTDATA ${test_data} ) @@ -26,10 +40,23 @@ qt_internal_add_test(tst_qmllint qt_internal_extend_target(tst_qmllint CONDITION ANDROID OR IOS DEFINES - QT_QMLTEST_DATADIR=\\\":/data\\\" + QT_QMLTEST_DATADIR=":/data" ) qt_internal_extend_target(tst_qmllint CONDITION NOT ANDROID AND NOT IOS DEFINES - QT_QMLTEST_DATADIR=\\\"${CMAKE_CURRENT_SOURCE_DIR}/data\\\" + QT_QMLTEST_DATADIR="${CMAKE_CURRENT_SOURCE_DIR}/data" ) + +if (TARGET qmllint) + add_dependencies(tst_qmllint Qt::qmllint) +endif() + +if (TARGET qmljsrootgen) + qt_internal_extend_target(tst_qmllint + DEFINES + QT_QMLJSROOTGEN_PRESENT + ) + + add_dependencies(tst_qmllint Qt::qmljsrootgen) +endif() diff --git a/tests/auto/qml/qmllint/data/2behavior.qml b/tests/auto/qml/qmllint/data/2behavior.qml new file mode 100644 index 0000000000..0520415155 --- /dev/null +++ b/tests/auto/qml/qmllint/data/2behavior.qml @@ -0,0 +1,10 @@ +import QtQuick 2.15 + +Item { + Behavior { + SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 } + } + Behavior { + SpringAnimation{ spring: 2; damping: 0.2; modulus: 360 } + } +} diff --git a/tests/auto/qml/qmllint/data/2interceptors.qml b/tests/auto/qml/qmllint/data/2interceptors.qml new file mode 100644 index 0000000000..9db9766a8e --- /dev/null +++ b/tests/auto/qml/qmllint/data/2interceptors.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +Item { + Behavior on x {} + Behavior on x {} +} diff --git a/tests/auto/qml/qmllint/data/2valueSources.qml b/tests/auto/qml/qmllint/data/2valueSources.qml new file mode 100644 index 0000000000..49e4c65caf --- /dev/null +++ b/tests/auto/qml/qmllint/data/2valueSources.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +Item { + NumberAnimation on x {} + NumberAnimation on x {} +} diff --git a/tests/auto/qml/qmllint/data/AliasListType.qml b/tests/auto/qml/qmllint/data/AliasListType.qml new file mode 100644 index 0000000000..bdefa1d35f --- /dev/null +++ b/tests/auto/qml/qmllint/data/AliasListType.qml @@ -0,0 +1,7 @@ +import QtQuick 2.15 + +Item { + Item { id: item } + + default property alias content: item.children +} diff --git a/tests/auto/qml/qmllint/data/AttachedProperties/attachedProperty.qmltypes b/tests/auto/qml/qmllint/data/AttachedProperties/attachedProperty.qmltypes new file mode 100644 index 0000000000..1192a53911 --- /dev/null +++ b/tests/auto/qml/qmllint/data/AttachedProperties/attachedProperty.qmltypes @@ -0,0 +1,21 @@ +import QtQuick.tooling 1.2 +Module { + Component { + file: "attachedtype.h" + name: "TestType" + accessSemantics: "reference" + prototype: "QObject" + exports: ["QmlLintTestLib/TestType 1.0"] + exportMetaObjectRevisions: [256] + attachedType: "TestTypeAttached" + } + Component { + file: "attachedtype.h" + name: "TestTypeAttached" + accessSemantics: "reference" + prototype: "QObject" + Property { name: "count"; type: "int"; read: "getCount"; write: "setCount" } + Property { name: "str"; type: "QString"; read: "getStr"; write: "setStr" } + Property { name: "object"; type: "QObject"; isPointer: true; read: "getObject"; write: "setObject" } + } +} diff --git a/tests/auto/qml/qmllint/data/AttachedProperties/qmldir b/tests/auto/qml/qmllint/data/AttachedProperties/qmldir new file mode 100644 index 0000000000..965b336902 --- /dev/null +++ b/tests/auto/qml/qmllint/data/AttachedProperties/qmldir @@ -0,0 +1,3 @@ +module AttachedProperties +typeinfo attachedProperty.qmltypes +import QtQml diff --git a/tests/auto/qml/qmllint/data/Cycle/MenuItem.qml b/tests/auto/qml/qmllint/data/Cycle/MenuItem.qml new file mode 100644 index 0000000000..b316a5432c --- /dev/null +++ b/tests/auto/qml/qmllint/data/Cycle/MenuItem.qml @@ -0,0 +1,3 @@ +import QtQml + +MenuItem {} diff --git a/tests/auto/qml/qmllint/data/Cycle/qmldir b/tests/auto/qml/qmllint/data/Cycle/qmldir new file mode 100644 index 0000000000..6b0ba5519a --- /dev/null +++ b/tests/auto/qml/qmllint/data/Cycle/qmldir @@ -0,0 +1,3 @@ +module Cycle + +MenuItem 1.0 MenuItem.qml diff --git a/tests/auto/qml/qmllint/data/Cycle1.qml b/tests/auto/qml/qmllint/data/Cycle1.qml index 8095e9f732..00b7c2a4ce 100644 --- a/tests/auto/qml/qmllint/data/Cycle1.qml +++ b/tests/auto/qml/qmllint/data/Cycle1.qml @@ -1,2 +1,4 @@ import QtQml 2.0 -Cycle2 {} +Cycle2 { + QtObject {} // Having children here has caused qmllint to hang in the past (QTBUG-96343) +} diff --git a/tests/auto/qml/qmllint/data/DeprProp.qml b/tests/auto/qml/qmllint/data/DeprProp.qml new file mode 100644 index 0000000000..39f271902e --- /dev/null +++ b/tests/auto/qml/qmllint/data/DeprProp.qml @@ -0,0 +1,8 @@ +import QtQml + +QtObject { + @Deprecated {} + property int deprecated: 500 + @Deprecated { reason: "Test" } + property int deprecatedReason: 200 +} diff --git a/tests/auto/qml/qmllint/data/DeprecatedFunctions.qml b/tests/auto/qml/qmllint/data/DeprecatedFunctions.qml new file mode 100644 index 0000000000..139e8a6230 --- /dev/null +++ b/tests/auto/qml/qmllint/data/DeprecatedFunctions.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +Item { + @Deprecated { reason: "This deprecation should be overridden!" } + function deprecatedOverride(a, b) {} + + @Deprecated { reason: "This deprecation should be visible!" } + function deprecatedInherited(c, d) {} +} diff --git a/tests/auto/qml/qmllint/data/DuplicateImport/plugins.qmltypes b/tests/auto/qml/qmllint/data/DuplicateImport/plugins.qmltypes new file mode 100644 index 0000000000..b9144a673a --- /dev/null +++ b/tests/auto/qml/qmllint/data/DuplicateImport/plugins.qmltypes @@ -0,0 +1,11 @@ +import QtQuick.tooling 1.2 +Module { + dependencies: [] + Component { + name: "ItemDerived" + prototype: "QQuickItem" + exports: [ + "DuplicateImport/ItemDerived 1.0" + ] + } +} diff --git a/tests/auto/qml/qmllint/data/DuplicateImport/qmldir b/tests/auto/qml/qmllint/data/DuplicateImport/qmldir new file mode 100644 index 0000000000..309ab5ac11 --- /dev/null +++ b/tests/auto/qml/qmllint/data/DuplicateImport/qmldir @@ -0,0 +1,4 @@ +module DuplicateImport +typeinfo plugins.qmltypes +depends QtQuick 2.0 +import QtQml diff --git a/tests/auto/qml/qmllint/data/Elsewhere/B.qml b/tests/auto/qml/qmllint/data/Elsewhere/B.qml new file mode 100644 index 0000000000..8fc36a40da --- /dev/null +++ b/tests/auto/qml/qmllint/data/Elsewhere/B.qml @@ -0,0 +1,3 @@ +import QtQml + +QtObject {} diff --git a/tests/auto/qml/qmllint/data/Elsewhere/qmldir b/tests/auto/qml/qmllint/data/Elsewhere/qmldir new file mode 100644 index 0000000000..e38f7da9ce --- /dev/null +++ b/tests/auto/qml/qmllint/data/Elsewhere/qmldir @@ -0,0 +1,2 @@ +module Things.Nested +A 1.0 B.qml diff --git a/tests/auto/qml/qmllint/data/EnumAccessCpp.qml b/tests/auto/qml/qmllint/data/EnumAccessCpp.qml new file mode 100644 index 0000000000..77cdc5eb6a --- /dev/null +++ b/tests/auto/qml/qmllint/data/EnumAccessCpp.qml @@ -0,0 +1,9 @@ +import Things +import QtQml + +QtObject { + property int foo1: SomethingEntirelyStrange.AnEnum.AAA + property int foo2: SomethingEntirelyStrange.AnEnum.BBB + property int foo3: SomethingEntirelyStrange.AnEnum.CCC + property int boo1: SomethingEntirelyStrange.V1 +} diff --git a/tests/auto/qml/qmllint/data/Fake5Compat/GraphicalEffects/private/qmldir b/tests/auto/qml/qmllint/data/Fake5Compat/GraphicalEffects/private/qmldir new file mode 100644 index 0000000000..b13cdc9c3e --- /dev/null +++ b/tests/auto/qml/qmllint/data/Fake5Compat/GraphicalEffects/private/qmldir @@ -0,0 +1,2 @@ +module Qt5Compat.GraphicalEffects.private +typeinfo plugins.qmltypes diff --git a/tests/auto/qml/qmllint/data/Foo.qml b/tests/auto/qml/qmllint/data/Foo.qml new file mode 100644 index 0000000000..6e47488e95 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Foo.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + function whatSUp() : string { return "I'm crashing"; } +} diff --git a/tests/auto/qml/qmllint/data/Foozle.qml b/tests/auto/qml/qmllint/data/Foozle.qml new file mode 100644 index 0000000000..f9ed238343 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Foozle.qml @@ -0,0 +1,3 @@ +import QtQml + +Barzle {} diff --git a/tests/auto/qml/qmllint/data/FormUser.qml b/tests/auto/qml/qmllint/data/FormUser.qml index ea3621586f..46a5c4fd6d 100644 --- a/tests/auto/qml/qmllint/data/FormUser.qml +++ b/tests/auto/qml/qmllint/data/FormUser.qml @@ -1,5 +1,3 @@ -import QtQuick 2.0 - Form { x: 12 y: 13 diff --git a/tests/auto/qml/qmllint/data/GrdView.qml b/tests/auto/qml/qmllint/data/GrdView.qml new file mode 100644 index 0000000000..a275839849 --- /dev/null +++ b/tests/auto/qml/qmllint/data/GrdView.qml @@ -0,0 +1,3 @@ +import QtQuick 2.15 as Quick + +Quick.GridView {} diff --git a/tests/auto/qml/qmllint/data/ImportPath/ModuleInImportPath/A.qml b/tests/auto/qml/qmllint/data/ImportPath/ModuleInImportPath/A.qml new file mode 100644 index 0000000000..4141884af9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/ImportPath/ModuleInImportPath/A.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + property string myProperty +} diff --git a/tests/auto/qml/qmllint/data/ImportPath/ModuleInImportPath/qmldir b/tests/auto/qml/qmllint/data/ImportPath/ModuleInImportPath/qmldir new file mode 100644 index 0000000000..b6e958d657 --- /dev/null +++ b/tests/auto/qml/qmllint/data/ImportPath/ModuleInImportPath/qmldir @@ -0,0 +1,2 @@ +module ModuleInImportPath +A 1.0 A.qml diff --git a/tests/auto/qml/qmllint/data/InfoItemTextEdit.qml b/tests/auto/qml/qmllint/data/InfoItemTextEdit.qml new file mode 100644 index 0000000000..be2d35d574 --- /dev/null +++ b/tests/auto/qml/qmllint/data/InfoItemTextEdit.qml @@ -0,0 +1,12 @@ +import QtQuick 2.11 +import QtQuick.Window 2.3 + +Rectangle { + property color textStrColor: "steelblue" + property alias valueStr: input.text + + TextInput { + id: input + } + +} diff --git a/tests/auto/qml/qmllint/data/IsNotAnEntryOfEnum.qml b/tests/auto/qml/qmllint/data/IsNotAnEntryOfEnum.qml new file mode 100644 index 0000000000..8b20fe9ae9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/IsNotAnEntryOfEnum.qml @@ -0,0 +1,14 @@ +import QtQuick + +Item { + id: item + visible: true + + enum Mode { + Hours, + Minutes + } + + property int mode: item.Mode.Hours + property string s: item.mode === IsNotAnEntryOfEnum.Mode.Hour ? "green" : "tomato" +} diff --git a/tests/auto/qml/qmllint/data/JsLibrary/HelperLibrary.js b/tests/auto/qml/qmllint/data/JsLibrary/HelperLibrary.js new file mode 100644 index 0000000000..cf75a11b72 --- /dev/null +++ b/tests/auto/qml/qmllint/data/JsLibrary/HelperLibrary.js @@ -0,0 +1,5 @@ +.pragma library + +function foo() { + return "Hello World"; +} diff --git a/tests/auto/qml/qmllint/data/JsLibrary/qmldir b/tests/auto/qml/qmllint/data/JsLibrary/qmldir new file mode 100644 index 0000000000..d1c7011d7a --- /dev/null +++ b/tests/auto/qml/qmllint/data/JsLibrary/qmldir @@ -0,0 +1,3 @@ +module JsLibrary +HelperLibrary 1.0 HelperLibrary.js + diff --git a/tests/auto/qml/qmllint/data/LazyAndDirect/Direct.qml b/tests/auto/qml/qmllint/data/LazyAndDirect/Direct.qml new file mode 100644 index 0000000000..fcb08c1e80 --- /dev/null +++ b/tests/auto/qml/qmllint/data/LazyAndDirect/Direct.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + Component.onCompleted: Lazy.setDirect(this) +} diff --git a/tests/auto/qml/qmllint/data/LazyAndDirect/Lazy.qml b/tests/auto/qml/qmllint/data/LazyAndDirect/Lazy.qml new file mode 100644 index 0000000000..1f69d0f16a --- /dev/null +++ b/tests/auto/qml/qmllint/data/LazyAndDirect/Lazy.qml @@ -0,0 +1,8 @@ +pragma Singleton +import QtQml + +QtObject { + property Direct direct + + function setDirect(newDirect : Direct) { direct = newDirect } +} diff --git a/tests/auto/qml/qmllint/data/LazyAndDirect/qmldir b/tests/auto/qml/qmllint/data/LazyAndDirect/qmldir new file mode 100644 index 0000000000..ebc7f2a157 --- /dev/null +++ b/tests/auto/qml/qmllint/data/LazyAndDirect/qmldir @@ -0,0 +1,4 @@ +module LazyAndDirect + +Direct 1.0 Direct.qml +singleton Lazy 1.0 Lazy.qml diff --git a/tests/auto/qml/qmllint/data/ListProperty.qml b/tests/auto/qml/qmllint/data/ListProperty.qml index d2bbc58cc5..0290f51ce9 100644 --- a/tests/auto/qml/qmllint/data/ListProperty.qml +++ b/tests/auto/qml/qmllint/data/ListProperty.qml @@ -1,4 +1,3 @@ -import QtQuick 2.12 import Things 1.0 Frame { diff --git a/tests/auto/qml/qmllint/data/LocaleTest/localeTest.qmltypes b/tests/auto/qml/qmllint/data/LocaleTest/localeTest.qmltypes new file mode 100644 index 0000000000..b5baa22357 --- /dev/null +++ b/tests/auto/qml/qmllint/data/LocaleTest/localeTest.qmltypes @@ -0,0 +1,31 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "AppManager.h" + name: "AppManager" + accessSemantics: "reference" + prototype: "QObject" + exports: ["LocaleTest/AppManager 1.0"] + isCreatable: false + isSingleton: true + exportMetaObjectRevisions: [256] + Property { + name: "primaryLocale" + type: "QLocale" + read: "getPrimaryLocale" + notify: "primaryLocaleChanged" + index: 0 + isReadonly: true + } + Signal { + name: "primaryLocaleChanged" + Parameter { type: "QLocale" } + } + } +} diff --git a/tests/auto/qml/qmllint/data/LocaleTest/qmldir b/tests/auto/qml/qmllint/data/LocaleTest/qmldir new file mode 100644 index 0000000000..2dc0799d5b --- /dev/null +++ b/tests/auto/qml/qmllint/data/LocaleTest/qmldir @@ -0,0 +1,3 @@ +module LocaleTest +typeinfo localeTest.qmltypes +depends QtQml diff --git a/tests/auto/qml/qmllint/data/MultiDefaultProperty.qml b/tests/auto/qml/qmllint/data/MultiDefaultProperty.qml new file mode 100644 index 0000000000..a708219c96 --- /dev/null +++ b/tests/auto/qml/qmllint/data/MultiDefaultProperty.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + default property list<Simple> xxx +} diff --git a/tests/auto/qml/qmllint/data/MultiDirectory/Outer.qml b/tests/auto/qml/qmllint/data/MultiDirectory/Outer.qml new file mode 100644 index 0000000000..5dda9a4d12 --- /dev/null +++ b/tests/auto/qml/qmllint/data/MultiDirectory/Outer.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property int o: 12 +} diff --git a/tests/auto/qml/qmllint/data/MultiDirectory/multi.qrc b/tests/auto/qml/qmllint/data/MultiDirectory/multi.qrc new file mode 100644 index 0000000000..b6df21ec4c --- /dev/null +++ b/tests/auto/qml/qmllint/data/MultiDirectory/multi.qrc @@ -0,0 +1,10 @@ +<RCC> + <qresource prefix="/qt/qml/MultiDirectory"> + <file>qmldir</file> + <file>Outer.qml</file> + <file>qml/qmldir</file> + <file>qml/Inner.qml</file> + <file>qml/pages/qmldir</file> + <file>qml/pages/Page.qml</file> + </qresource> +</RCC> diff --git a/tests/auto/qml/qmllint/data/MultiDirectory/qml/Inner.qml b/tests/auto/qml/qmllint/data/MultiDirectory/qml/Inner.qml new file mode 100644 index 0000000000..01b7c331d9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/MultiDirectory/qml/Inner.qml @@ -0,0 +1,5 @@ +import QtQml + +Outer { + o: 25 +} diff --git a/tests/auto/qml/qmllint/data/MultiDirectory/qml/pages/Page.qml b/tests/auto/qml/qmllint/data/MultiDirectory/qml/pages/Page.qml new file mode 100644 index 0000000000..7efc889fb1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/MultiDirectory/qml/pages/Page.qml @@ -0,0 +1,5 @@ +import QtQml + +Inner { + o: 32 +} diff --git a/tests/auto/qml/qmllint/data/MultiDirectory/qml/pages/qmldir b/tests/auto/qml/qmllint/data/MultiDirectory/qml/pages/qmldir new file mode 100644 index 0000000000..56ef19d41b --- /dev/null +++ b/tests/auto/qml/qmllint/data/MultiDirectory/qml/pages/qmldir @@ -0,0 +1 @@ +prefer :/qt/qml/MultiDirectory/ diff --git a/tests/auto/qml/qmllint/data/MultiDirectory/qml/qmldir b/tests/auto/qml/qmllint/data/MultiDirectory/qml/qmldir new file mode 100644 index 0000000000..56ef19d41b --- /dev/null +++ b/tests/auto/qml/qmllint/data/MultiDirectory/qml/qmldir @@ -0,0 +1 @@ +prefer :/qt/qml/MultiDirectory/ diff --git a/tests/auto/qml/qmllint/data/MultiDirectory/qmldir b/tests/auto/qml/qmllint/data/MultiDirectory/qmldir new file mode 100644 index 0000000000..699132dc4f --- /dev/null +++ b/tests/auto/qml/qmllint/data/MultiDirectory/qmldir @@ -0,0 +1,5 @@ +module MultiDirectory +prefer :/qt/qml/MultiDirectory +Outer 1.0 Outer.qml +Inner 1.0 qml/Inner.qml +Page 1.0 qml/pages/Page.qml diff --git a/tests/auto/qml/qmllint/data/MyStyle/MyStyle.qmltypes b/tests/auto/qml/qmllint/data/MyStyle/MyStyle.qmltypes new file mode 100644 index 0000000000..92c1b0953e --- /dev/null +++ b/tests/auto/qml/qmllint/data/MyStyle/MyStyle.qmltypes @@ -0,0 +1,112 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "mystyle.h" + name: "MyStyle" + accessSemantics: "reference" + prototype: "QQuickAttachedPropertyPropagator" + exports: ["MyStyle/MyStyle 1.0", "MyStyle/MyStyle 254.0"] + isCreatable: false + exportMetaObjectRevisions: [256, 65024] + attachedType: "MyStyle" + Enum { + name: "Theme" + values: ["Light", "Dark"] + } + Property { + name: "theme" + type: "Theme" + read: "theme" + write: "setTheme" + reset: "resetTheme" + notify: "themeChanged" + index: 0 + isFinal: true + } + Property { + name: "windowColor" + type: "QColor" + read: "windowColor" + notify: "themeChanged" + index: 1 + isReadonly: true + isFinal: true + } + Property { + name: "windowTextColor" + type: "QColor" + read: "windowTextColor" + notify: "themeChanged" + index: 2 + isReadonly: true + isFinal: true + } + Property { + name: "buttonColor" + type: "QColor" + read: "buttonColor" + notify: "themeChanged" + index: 3 + isReadonly: true + isFinal: true + } + Property { + name: "buttonTextColor" + type: "QColor" + read: "buttonTextColor" + notify: "themeChanged" + index: 4 + isReadonly: true + isFinal: true + } + Property { + name: "toolBarColor" + type: "QColor" + read: "toolBarColor" + notify: "themeChanged" + index: 5 + isReadonly: true + isFinal: true + } + Property { + name: "popupColor" + type: "QColor" + read: "popupColor" + notify: "themeChanged" + index: 6 + isReadonly: true + isFinal: true + } + Property { + name: "popupBorderColor" + type: "QColor" + read: "popupBorderColor" + notify: "themeChanged" + index: 7 + isReadonly: true + isFinal: true + } + Property { + name: "backgroundDimColor" + type: "QColor" + read: "backgroundDimColor" + notify: "themeChanged" + index: 8 + isReadonly: true + isFinal: true + } + Signal { name: "themeChanged" } + } + Component { + file: "qquickattachedpropertypropagator.h" + name: "QQuickAttachedPropertyPropagator" + accessSemantics: "reference" + prototype: "QObject" + } +} diff --git a/tests/auto/qml/qmllint/data/MyStyle/ToolBar.qml b/tests/auto/qml/qmllint/data/MyStyle/ToolBar.qml new file mode 100644 index 0000000000..5920797d9b --- /dev/null +++ b/tests/auto/qml/qmllint/data/MyStyle/ToolBar.qml @@ -0,0 +1,12 @@ +import QtQuick +import QtQuick.Templates as T +import MyStyle + +T.ToolBar { + id: control + + property color c: MyStyle.toolBarColor + background: Rectangle { + color: MyStyle.toolBarColor + } +} diff --git a/tests/auto/qml/qmllint/data/MyStyle/qmldir b/tests/auto/qml/qmllint/data/MyStyle/qmldir new file mode 100644 index 0000000000..8cc4246f7c --- /dev/null +++ b/tests/auto/qml/qmllint/data/MyStyle/qmldir @@ -0,0 +1,4 @@ +module MyStyle +typeinfo MyStyle.qmltypes +ToolBar 254.0 ToolBar.qml +import QtQuick.Controls.Material diff --git a/tests/auto/qml/qmllint/data/NeedImportPath.qml b/tests/auto/qml/qmllint/data/NeedImportPath.qml new file mode 100644 index 0000000000..0a63b58f7c --- /dev/null +++ b/tests/auto/qml/qmllint/data/NeedImportPath.qml @@ -0,0 +1,5 @@ +import ModuleInImportPath + +A { + myProperty: "Hello World" +} diff --git a/tests/auto/qml/qmllint/data/NotScopedEnumCpp.qml b/tests/auto/qml/qmllint/data/NotScopedEnumCpp.qml new file mode 100644 index 0000000000..4fbe3ec273 --- /dev/null +++ b/tests/auto/qml/qmllint/data/NotScopedEnumCpp.qml @@ -0,0 +1,6 @@ +import Things +import QtQml + +QtObject { + property int boo1: SomethingEntirelyStrange.TheEnum.V1 +} diff --git a/tests/auto/qml/qmllint/data/NotSoSimple.qml b/tests/auto/qml/qmllint/data/NotSoSimple.qml new file mode 100644 index 0000000000..82a0a36ef1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/NotSoSimple.qml @@ -0,0 +1,5 @@ +import QtQml + +Simple { + property int complicated: 433 +} diff --git a/tests/auto/qml/qmllint/data/PluginQuickAnchorsBase.qml b/tests/auto/qml/qmllint/data/PluginQuickAnchorsBase.qml new file mode 100644 index 0000000000..5543762bf8 --- /dev/null +++ b/tests/auto/qml/qmllint/data/PluginQuickAnchorsBase.qml @@ -0,0 +1,8 @@ +import QtQuick + +Item { + anchors.left: parent.left + anchors.right: parent.right + anchors.top: parent.top + anchors.bottom: parent.bottom +} diff --git a/tests/auto/qml/qmllint/data/PropertyBase.qml b/tests/auto/qml/qmllint/data/PropertyBase.qml new file mode 100644 index 0000000000..a7a3cb5bb4 --- /dev/null +++ b/tests/auto/qml/qmllint/data/PropertyBase.qml @@ -0,0 +1,5 @@ +import QtQml 2.15 + +QtObject { + property var foo +} diff --git a/tests/auto/qml/qmllint/data/PropertyBase2.qml b/tests/auto/qml/qmllint/data/PropertyBase2.qml new file mode 100644 index 0000000000..cfb07da0f5 --- /dev/null +++ b/tests/auto/qml/qmllint/data/PropertyBase2.qml @@ -0,0 +1,5 @@ +import QtQml 2.15 + +PropertyBase { + foo: QtObject { property int bar: 5 } +} diff --git a/tests/auto/qml/qmllint/data/PropertyChangeHandlers/propertychangehandlers.qmltypes b/tests/auto/qml/qmllint/data/PropertyChangeHandlers/propertychangehandlers.qmltypes new file mode 100644 index 0000000000..d16b97dc6c --- /dev/null +++ b/tests/auto/qml/qmllint/data/PropertyChangeHandlers/propertychangehandlers.qmltypes @@ -0,0 +1,65 @@ +import QtQuick.tooling 1.2 +Module { + Component { + file: "typewithproperties.h" + name: "TypeWithProperties" + accessSemantics: "reference" + prototype: "QObject" + exports: ["QmltcTests/TypeWithProperties 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "a" + type: "double" + bindable: "bindableA" + read: "a" + write: "setA" + index: 0 + } + Property { + name: "b" + type: "QString" + read: "b" + write: "setB" + notify: "bChanged" + index: 1 + } + Property { + name: "c" + type: "QVariant" + read: "c" + write: "setC" + notify: "cWeirdSignal" + index: 2 + } + Property { + name: "d" + type: "QVariant" + bindable: "bindableD" + read: "d" + write: "setD" + notify: "dSignal" + index: 3 + } + Property { + name: "e" + type: "QString" + bindable: "bindableE" + read: "e" + write: "setE" + notify: "eChanged" + index: 3 + } + Signal { name: "bChanged" } + Signal { + name: "cWeirdSignal" + Parameter { type: "QVariant" } + } + Signal { + name: "dSignal" + Parameter { type: "QVariant" } + Parameter { type: "QString" } + } + Signal { name: "eChanged" } + Method { name: "wannabeSignal" } + } +} diff --git a/tests/auto/qml/qmllint/data/PropertyChangeHandlers/qmldir b/tests/auto/qml/qmllint/data/PropertyChangeHandlers/qmldir new file mode 100644 index 0000000000..6adb690e9c --- /dev/null +++ b/tests/auto/qml/qmllint/data/PropertyChangeHandlers/qmldir @@ -0,0 +1,3 @@ +module PropertyChangeHandlers +typeinfo propertychangehandlers.qmltypes +import QtQml diff --git a/tests/auto/qml/qmllint/data/QmlBench/Globals.qml b/tests/auto/qml/qmllint/data/QmlBench/Globals.qml new file mode 100644 index 0000000000..6531a1e7ec --- /dev/null +++ b/tests/auto/qml/qmllint/data/QmlBench/Globals.qml @@ -0,0 +1,10 @@ +pragma Singleton +import QtQuick 2.0 + +QtObject { + readonly property string stringProp: "stringValue" + readonly property int intProp: 10 + readonly property real realProp: 4.5 + readonly property color colorProp: "green" + readonly property bool boolProp: true +} diff --git a/tests/auto/qml/qmllint/data/QmlBench/Locals.qml b/tests/auto/qml/qmllint/data/QmlBench/Locals.qml new file mode 100644 index 0000000000..3dc7d7116c --- /dev/null +++ b/tests/auto/qml/qmllint/data/QmlBench/Locals.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +QtObject { + readonly property string stringProp: "stringValue" + readonly property int intProp: 10 + readonly property real realProp: 4.5 + readonly property color colorProp: "green" + readonly property bool boolProp: true +} diff --git a/tests/auto/qml/qmllint/data/QmlBench/qmldir b/tests/auto/qml/qmllint/data/QmlBench/qmldir new file mode 100644 index 0000000000..a166e269e3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/QmlBench/qmldir @@ -0,0 +1,3 @@ +module QmlBench +singleton Globals 1.0 Globals.qml +Locals 1.0 Locals.qml diff --git a/tests/auto/qml/qmllint/data/RequiredWithRootLevelAlias.qml b/tests/auto/qml/qmllint/data/RequiredWithRootLevelAlias.qml new file mode 100644 index 0000000000..cfedd4cf01 --- /dev/null +++ b/tests/auto/qml/qmllint/data/RequiredWithRootLevelAlias.qml @@ -0,0 +1,9 @@ +import QtQuick + +Item { + property alias requiredAlias: nested.foo + Item { + id: nested + required property string foo + } +} diff --git a/tests/auto/qml/qmllint/data/SharedFunctions.js b/tests/auto/qml/qmllint/data/SharedFunctions.js new file mode 100644 index 0000000000..3398d2d6d7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/SharedFunctions.js @@ -0,0 +1,5 @@ +.pragma library + +function setColorAlpha(color, alpha) { + return Qt.hsla(color.hslHue, color.hslSaturation, color.hslLightness, alpha) +} diff --git a/tests/auto/qml/qmllint/data/Singletons/MissingPragma.qml b/tests/auto/qml/qmllint/data/Singletons/MissingPragma.qml new file mode 100644 index 0000000000..54531c4bdc --- /dev/null +++ b/tests/auto/qml/qmllint/data/Singletons/MissingPragma.qml @@ -0,0 +1,2 @@ +import QtQml +QtObject {} diff --git a/tests/auto/qml/qmllint/data/Singletons/MissingQmldirSingleton.qml b/tests/auto/qml/qmllint/data/Singletons/MissingQmldirSingleton.qml new file mode 100644 index 0000000000..923966c483 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Singletons/MissingQmldirSingleton.qml @@ -0,0 +1,3 @@ +pragma Singleton +import QtQml +QtObject {} diff --git a/tests/auto/qml/qmllint/data/Singletons/qmldir b/tests/auto/qml/qmllint/data/Singletons/qmldir new file mode 100644 index 0000000000..84e9876b80 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Singletons/qmldir @@ -0,0 +1,3 @@ +module Singletons +singleton MissingPragma 1.0 MissingPragma.qml +MissingQmldirSingleton 1.0 MissingQmldirSingleton.qml diff --git a/tests/auto/qml/qmllint/data/StringToDateTime/qmldir b/tests/auto/qml/qmllint/data/StringToDateTime/qmldir new file mode 100644 index 0000000000..761f613496 --- /dev/null +++ b/tests/auto/qml/qmllint/data/StringToDateTime/qmldir @@ -0,0 +1,3 @@ +module StringToDateTime +typeinfo stringToDateTime.qmltypes +import QtQml diff --git a/tests/auto/qml/qmllint/data/StringToDateTime/stringToDateTime.qmltypes b/tests/auto/qml/qmllint/data/StringToDateTime/stringToDateTime.qmltypes new file mode 100644 index 0000000000..e0f13fa2ec --- /dev/null +++ b/tests/auto/qml/qmllint/data/StringToDateTime/stringToDateTime.qmltypes @@ -0,0 +1,14 @@ +import QtQuick.tooling 1.2 +Module { + Component { + file: "stringToQDateTime.h" + name: "StringToDateTimeComponent" + exports: ["QmlLintTestLib/StringToDateTime 1.0"] + exportMetaObjectRevisions: [256] + accessSemantics: "reference" + prototype: "QObject" + Property { name: "aDate"; type: "QDate"; read: "getADate"; write: "setADate" } + Property { name: "aTime"; type: "QTime"; read: "getATime"; write: "setATime" } + Property { name: "aDateTime"; type: "QDateTime"; read: "getADateTime"; write: "setADateTime" } + } +} diff --git a/tests/auto/qml/qmllint/data/Switch.qml b/tests/auto/qml/qmllint/data/Switch.qml new file mode 100644 index 0000000000..e57fde4818 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Switch.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + id: control + property alias onLabel: control.objectName +} diff --git a/tests/auto/qml/qmllint/data/T/A.qml b/tests/auto/qml/qmllint/data/T/A.qml new file mode 100644 index 0000000000..2b8d2ad52f --- /dev/null +++ b/tests/auto/qml/qmllint/data/T/A.qml @@ -0,0 +1,6 @@ +pragma Singleton +import QtQml + +QtObject { + property int a: 10 +} diff --git a/tests/auto/qml/qmllint/data/T/a.qrc b/tests/auto/qml/qmllint/data/T/a.qrc new file mode 100644 index 0000000000..a419534a08 --- /dev/null +++ b/tests/auto/qml/qmllint/data/T/a.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/"> + <file>qmldir</file> + <file>A.qml</file> + <file>b.qml</file> + </qresource> +</RCC> diff --git a/tests/auto/qml/qmllint/data/T/b.qml b/tests/auto/qml/qmllint/data/T/b.qml new file mode 100644 index 0000000000..10d3c755cf --- /dev/null +++ b/tests/auto/qml/qmllint/data/T/b.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + property int b: A.a + property int e: X.a +} diff --git a/tests/auto/qml/qmllint/data/T/qmldir b/tests/auto/qml/qmllint/data/T/qmldir new file mode 100644 index 0000000000..656fafd9bb --- /dev/null +++ b/tests/auto/qml/qmllint/data/T/qmldir @@ -0,0 +1,2 @@ +module T +singleton X 1.0 A.qml diff --git a/tests/auto/qml/qmllint/data/TestTypes/qmldir b/tests/auto/qml/qmllint/data/TestTypes/qmldir new file mode 100644 index 0000000000..314dccb7a9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/TestTypes/qmldir @@ -0,0 +1,3 @@ +module TestTypes +typeinfo testtypes.qmltypes + diff --git a/tests/auto/qml/qmllint/data/TestTypes/testtypes.qmltypes b/tests/auto/qml/qmllint/data/TestTypes/testtypes.qmltypes new file mode 100644 index 0000000000..77ad6a3cef --- /dev/null +++ b/tests/auto/qml/qmllint/data/TestTypes/testtypes.qmltypes @@ -0,0 +1,201 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "birthdayparty.h" + name: "BirthDayPartyExtended" + accessSemantics: "reference" + prototype: "QObject" + Property { name: "eee"; type: "int"; read: "eee"; write: "setEee"; notify: "eeeChanged"; index: 0 } + Signal { name: "eeeChanged" } + } + Component { + file: "birthdayparty.h" + name: "BirthdayParty" + accessSemantics: "reference" + prototype: "QObject" + extension: "BirthDayPartyExtended" + exports: ["TestTypes/BirthdayParty 1.0"] + exportMetaObjectRevisions: [256] + attachedType: "BirthdayPartyAttached" + Property { + name: "host" + type: "Person" + isPointer: true + read: "host" + write: "setHost" + notify: "hostChanged" + index: 0 + isFinal: true + } + Property { name: "guests"; type: "Person"; isList: true; read: "guests"; index: 1; isReadonly: true } + Signal { name: "hostChanged" } + Method { + name: "invite" + Parameter { name: "name"; type: "QString" } + } + } + Component { + file: "birthdayparty.h" + name: "BirthdayPartyAttached" + accessSemantics: "reference" + prototype: "QObject" + Property { + name: "rsvp" + type: "QDateTime" + bindable: "rsvpBindable" + read: "rsvp" + write: "setRsvp" + index: 0 + } + } + Component { + file: "cppbaseclass.h" + name: "CppBaseClass" + accessSemantics: "reference" + prototype: "QObject" + exports: ["TestTypes/CppBaseClass 1.0"] + exportMetaObjectRevisions: [256] + Property { name: "cppProp"; type: "int"; bindable: "cppPropBindable"; index: 0; isFinal: true } + Property { name: "cppProp2"; type: "int"; bindable: "cppProp2Bindable"; index: 1; isFinal: true } + Method { + name: "doCall" + Parameter { name: "foo"; type: "QObject"; isPointer: true } + } + } + Component { + file: "cppbaseclass.h" + name: "CppSingleton" + accessSemantics: "reference" + prototype: "QObject" + exports: ["TestTypes/CppSingleton 1.0"] + isCreatable: false + isSingleton: true + exportMetaObjectRevisions: [256] + } + Component { + file: "birthdayparty.h" + name: "Nasty" + accessSemantics: "reference" + exports: ["TestTypes/Nasty 1.0"] + exportMetaObjectRevisions: [256] + attachedType: "Nasty" + } + Component { + file: "objectwithmethod.h" + name: "ObjectWithMethod" + accessSemantics: "reference" + prototype: "QObject" + exports: ["TestTypes/ObjectWithMethod 1.0"] + exportMetaObjectRevisions: [256] + Property { name: "fff"; type: "int"; bindable: "theThingBindable"; index: 0; isFinal: true } + Method { name: "doThing"; type: "int" } + } + Component { + file: "person.h" + name: "Person" + accessSemantics: "reference" + prototype: "QObject" + exports: ["TestTypes/Person 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "name" + type: "QString" + read: "name" + write: "setName" + notify: "nameChanged" + index: 0 + isFinal: true + } + Property { + name: "shoeSize" + type: "int" + read: "shoeSize" + write: "setShoeSize" + notify: "shoeSizeChanged" + index: 1 + } + Signal { name: "nameChanged" } + Signal { name: "shoeSizeChanged" } + } + Component { + file: "objectwithmethod.h" + name: "QObject" + accessSemantics: "reference" + Property { + name: "objectName" + type: "QString" + bindable: "bindableObjectName" + read: "objectName" + write: "setObjectName" + notify: "objectNameChanged" + index: 0 + } + Signal { + name: "destroyed" + Parameter { type: "QObject"; isPointer: true } + } + Signal { name: "destroyed" } + Signal { + name: "objectNameChanged" + Parameter { name: "objectName"; type: "QString" } + } + Method { name: "deleteLater" } + Method { + name: "_q_reregisterTimers" + Parameter { type: "void"; isPointer: true } + } + } + Component { + file: "hasbytearray.h" + name: "HasByteArray" + exports: ["TestTypes/HasByteArray 1.0"] + exportMetaObjectRevisions: [256] + accessSemantics: "reference" + prototype: "QObject" + Property { + name: "byteArray" + type: "QByteArray" + read: "byteArray" + write: "setByteArray" + notify: "byteArrayChanged" + index: 1 + } + Signal { name: "byteArrayChanged" } + } + + Component { + file: "somefile.h" + name: "someType" + accessSemantics: "reference" + prototype: "QObject" + exports: ["TestTypes/MyComponent 1.0"] + exportMetaObjectRevisions: [256] + Method { name: "createObject"; isJavaScriptFunction: true } + } + Component { + file: "variantMapLookup.h" + name: "VariantMapLookupFoo" + prototype: "QObject" + exports: ["TestTypes/VariantMapLookupFoo 1.0"] + exportMetaObjectRevisions: [256] + Property { + name: "data" + type: "QVariantMap" + read: "data" + index: 0 + } + } + Component { + file: "foo.h" + name: "Foo" + prototype: "QObject" + exports: ["TestTypes/Foo 1.0"] + Method { name: "print" } + } +} diff --git a/tests/auto/qml/qmllint/data/Things/LintDirectly.qml b/tests/auto/qml/qmllint/data/Things/LintDirectly.qml new file mode 100644 index 0000000000..4384fa99f4 --- /dev/null +++ b/tests/auto/qml/qmllint/data/Things/LintDirectly.qml @@ -0,0 +1,4 @@ +Pane { + property var thing: NotPartOfThings {} + property var something: Something {} +} diff --git a/tests/auto/qml/qmllint/data/Things/NotPartOfThings.qml b/tests/auto/qml/qmllint/data/Things/NotPartOfThings.qml new file mode 100644 index 0000000000..16fd397d1d --- /dev/null +++ b/tests/auto/qml/qmllint/data/Things/NotPartOfThings.qml @@ -0,0 +1,3 @@ +import QtQuick + +Component {} diff --git a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes index 9ad8c71468..47ae34cc00 100644 --- a/tests/auto/qml/qmllint/data/Things/plugins.qmltypes +++ b/tests/auto/qml/qmllint/data/Things/plugins.qmltypes @@ -2,18 +2,33 @@ import QtQuick.tooling 1.2 Module { dependencies: [] Component { + name: "CustomPalette" + prototype: "QPalette" + } + + Component { name: "SomethingEntirelyStrange" prototype: "QObject" exports: ["Things/SomethingEntirelyStrange 1.0"] Enum { name: "AnEnum" + isScoped: true values: { "AAA": 0, "BBB": 1, "CCC": 2 } } + Enum { + name: "TheEnum" + isScoped: false + values: { + "V1": 0, + "V2": 1 + } + } Property { name: "palette"; type: "QPalette" } + Property { name: "palette2"; type: "CustomPalette" } } Component { name: "Frame" @@ -26,12 +41,21 @@ Module { prototype: "QObject" exports: ["Things.Templates/Pane 1.0"] exportMetaObjectRevisions: [256] + deferredNames: ["contentData"] Property { name: "contentWidth"; type: "double" } Property { name: "contentHeight"; type: "double" } Property { name: "contentData"; type: "QObject"; isList: true; isReadonly: true } Property { name: "contentChildren"; type: "QQuickItem"; isList: true; isReadonly: true } } Component { + name: "WithImmediate" + prototype: "QObject" + exports: ["Things/WithImmediate 1.0"] + exportMetaObjectRevisions: [256] + immediateNames: ["contentData"] + Property { name: "contentData"; type: "double" } + } + Component { name: "MyScreen" prototype: "QObject" exports: [ @@ -64,4 +88,30 @@ Module { ] Property { name: "alignment"; type: "Qt::Alignment" } } + Component { + name: "CustomParserThing" + prototype: "QQuickItem" + exports: [ + "Things/CustomParserThing 1.0" + ] + Property { name: "foo"; type: "string" } + hasCustomParser: true + } + Component { + file: "mediaplayer-qml.h" + name: "MediaPlayerStateMachine" + accessSemantics: "value" + exports: ["Mediaplayer/MediaPlayerStateMachine 1.0"] + isCreatable: false + exportMetaObjectRevisions: [256] + } + Component { + file: "constinvokable.h" + name: "ConstInvokable" + accessSemantics: "reference" + prototype: "QObject" + exports: ["Things/ConstInvokable 1.0"] + exportMetaObjectRevisions: [256] + Method { name: "getObject"; type: "QObject"; isPointer: true; isConstant: true } + } } diff --git a/tests/auto/qml/qmllint/data/Things/qmldir b/tests/auto/qml/qmllint/data/Things/qmldir index 3c48ae0648..e1d493a480 100644 --- a/tests/auto/qml/qmllint/data/Things/qmldir +++ b/tests/auto/qml/qmllint/data/Things/qmldir @@ -2,5 +2,5 @@ module Things Something 1.0 SomethingElse.qml typeinfo plugins.qmltypes depends QtQuick 2.0 -import QtQml -optional import QtQuick.LocalStorage auto +import QtQml 2.0 +default import QtQuick.LocalStorage auto diff --git a/tests/auto/qml/qmllint/data/TypeDeprecated.qml b/tests/auto/qml/qmllint/data/TypeDeprecated.qml new file mode 100644 index 0000000000..53ae988052 --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeDeprecated.qml @@ -0,0 +1,4 @@ +import QtQml + +@Deprecated {} +QtObject {} diff --git a/tests/auto/qml/qmllint/data/TypeDeprecatedReason.qml b/tests/auto/qml/qmllint/data/TypeDeprecatedReason.qml new file mode 100644 index 0000000000..1d43c118f7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeDeprecatedReason.qml @@ -0,0 +1,4 @@ +import QtQml + +@Deprecated { reason: "Test" } +QtObject {} diff --git a/tests/auto/qml/qmllint/data/TypeWithDefaultListProperty.qml b/tests/auto/qml/qmllint/data/TypeWithDefaultListProperty.qml new file mode 100644 index 0000000000..e30314a825 --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeWithDefaultListProperty.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + default property list<QtObject> children +} diff --git a/tests/auto/qml/qmllint/data/TypeWithDefaultProperty.qml b/tests/auto/qml/qmllint/data/TypeWithDefaultProperty.qml new file mode 100644 index 0000000000..e64befb764 --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeWithDefaultProperty.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + default property QtObject child +} diff --git a/tests/auto/qml/qmllint/data/TypeWithDefaultStringProperty.qml b/tests/auto/qml/qmllint/data/TypeWithDefaultStringProperty.qml new file mode 100644 index 0000000000..98c446870c --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeWithDefaultStringProperty.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + default property string child +} diff --git a/tests/auto/qml/qmllint/data/TypeWithDefaultVarProperty.qml b/tests/auto/qml/qmllint/data/TypeWithDefaultVarProperty.qml new file mode 100644 index 0000000000..9fa89833d5 --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeWithDefaultVarProperty.qml @@ -0,0 +1,4 @@ +import QtQml 2.0 +QtObject { + default property var child +} diff --git a/tests/auto/qml/qmllint/data/TypeWithUnknownPropertyType.qml b/tests/auto/qml/qmllint/data/TypeWithUnknownPropertyType.qml new file mode 100644 index 0000000000..dd53e414cc --- /dev/null +++ b/tests/auto/qml/qmllint/data/TypeWithUnknownPropertyType.qml @@ -0,0 +1,5 @@ +import QtQuick 2.12 + +Item { + required property Something foo +} diff --git a/tests/auto/qml/qmllint/data/UnqualifiedInStoreSloppy.qml b/tests/auto/qml/qmllint/data/UnqualifiedInStoreSloppy.qml new file mode 100644 index 0000000000..197b74fa60 --- /dev/null +++ b/tests/auto/qml/qmllint/data/UnqualifiedInStoreSloppy.qml @@ -0,0 +1,12 @@ +import QtQuick 2.15 +import QtQuick.Window 2.15 + +Window { + Rectangle { + property real divisor: 0 + + Timer { + onTriggered: divisor = 1 + } + } +} diff --git a/tests/auto/qml/qmllint/data/UnqualifiedInStoreStrict.qml b/tests/auto/qml/qmllint/data/UnqualifiedInStoreStrict.qml new file mode 100644 index 0000000000..198e2146f5 --- /dev/null +++ b/tests/auto/qml/qmllint/data/UnqualifiedInStoreStrict.qml @@ -0,0 +1,12 @@ +import QtQuick 2.15 +import QtQuick.Window 2.15 + +Window { + Rectangle { + property real divisor: 0 + + Timer { + onTriggered: function() {"use strict"; divisor = 1 } + } + } +} diff --git a/tests/auto/qml/qmllint/data/accessible.qml b/tests/auto/qml/qmllint/data/accessible.qml new file mode 100644 index 0000000000..c68cf23648 --- /dev/null +++ b/tests/auto/qml/qmllint/data/accessible.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Item { + Accessible.role: Accessible.EditableText +} diff --git a/tests/auto/qml/qmllint/data/accessibleId.qml b/tests/auto/qml/qmllint/data/accessibleId.qml new file mode 100644 index 0000000000..904b856320 --- /dev/null +++ b/tests/auto/qml/qmllint/data/accessibleId.qml @@ -0,0 +1,14 @@ +import QtQml + +QtObject { + id: a + property Component c: Component { + QtObject { + id: a + property QtObject o: QtObject { + property int a: 5 + objectName: a.objectName + } + } + } +} diff --git a/tests/auto/qml/qmllint/data/additionalImplicitImport.qml b/tests/auto/qml/qmllint/data/additionalImplicitImport.qml new file mode 100644 index 0000000000..ef98259903 --- /dev/null +++ b/tests/auto/qml/qmllint/data/additionalImplicitImport.qml @@ -0,0 +1 @@ +Pane {} diff --git a/tests/auto/qml/qmllint/data/addressableValue.qml b/tests/auto/qml/qmllint/data/addressableValue.qml new file mode 100644 index 0000000000..9b93728ed8 --- /dev/null +++ b/tests/auto/qml/qmllint/data/addressableValue.qml @@ -0,0 +1,8 @@ +pragma ValueTypeBehavior: Addressable + +import QtQml +import scripts + +QtObject { + property var v: "red" as vvv +} diff --git a/tests/auto/qml/qmllint/data/aliasCycle.qml b/tests/auto/qml/qmllint/data/aliasCycle.qml new file mode 100644 index 0000000000..bdf938f1f8 --- /dev/null +++ b/tests/auto/qml/qmllint/data/aliasCycle.qml @@ -0,0 +1,7 @@ +import QtQml + +QtObject { + id: self + property alias a: self.b + property alias b: self.a +} diff --git a/tests/auto/qml/qmllint/data/aliasToList.qml b/tests/auto/qml/qmllint/data/aliasToList.qml new file mode 100644 index 0000000000..890bb9eeda --- /dev/null +++ b/tests/auto/qml/qmllint/data/aliasToList.qml @@ -0,0 +1,6 @@ +import QtQuick 2.15 + +AliasListType { + Item {} + Item {} +} diff --git a/tests/auto/qml/qmllint/data/animationEasing.qml b/tests/auto/qml/qmllint/data/animationEasing.qml new file mode 100644 index 0000000000..1b0c9ffea4 --- /dev/null +++ b/tests/auto/qml/qmllint/data/animationEasing.qml @@ -0,0 +1,5 @@ +import QtQml +import QtQuick +NumberAnimation { + easing.type: Easing.InOutQuad +} diff --git a/tests/auto/qml/qmllint/data/assignNonExistingTypeToVarProp.qml b/tests/auto/qml/qmllint/data/assignNonExistingTypeToVarProp.qml new file mode 100644 index 0000000000..dae699fae5 --- /dev/null +++ b/tests/auto/qml/qmllint/data/assignNonExistingTypeToVarProp.qml @@ -0,0 +1,6 @@ +import QtQuick + +ListView { + // model is a QVariant, so we can theoretically assign anything to it + model: NonExistingType {} +} diff --git a/tests/auto/qml/qmllint/data/assignToReadOnlyProperty.qml b/tests/auto/qml/qmllint/data/assignToReadOnlyProperty.qml new file mode 100644 index 0000000000..0f1e6f8cd7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/assignToReadOnlyProperty.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Item { + activeFocus: true +} diff --git a/tests/auto/qml/qmllint/data/assignToReadOnlyProperty2.qml b/tests/auto/qml/qmllint/data/assignToReadOnlyProperty2.qml new file mode 100644 index 0000000000..5e2b8408af --- /dev/null +++ b/tests/auto/qml/qmllint/data/assignToReadOnlyProperty2.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +Item { + id: item + Component.onCompleted: activeFocus = false +} diff --git a/tests/auto/qml/qmllint/data/attachedImportUse.qml b/tests/auto/qml/qmllint/data/attachedImportUse.qml new file mode 100644 index 0000000000..56b4e2bf7c --- /dev/null +++ b/tests/auto/qml/qmllint/data/attachedImportUse.qml @@ -0,0 +1,7 @@ +import QtQml +import TestTypes + +QtObject { + id: control + objectName: control.BirthdayParty.objectName +} diff --git a/tests/auto/qml/qmllint/data/attachedPropEnum.qml b/tests/auto/qml/qmllint/data/attachedPropEnum.qml new file mode 100644 index 0000000000..3149de04a0 --- /dev/null +++ b/tests/auto/qml/qmllint/data/attachedPropEnum.qml @@ -0,0 +1,9 @@ +import QtQuick + +Text { + id: root + text: KeyNavigation.priority == KeyNavigation.BeforeItem ? "before" : "after" + Text { + text: root.KeyNavigation.priority == KeyNavigation.BeforeItem ? "before" : "after" + } +} diff --git a/tests/auto/qml/qmllint/data/attachedPropNotReused.qml b/tests/auto/qml/qmllint/data/attachedPropNotReused.qml new file mode 100644 index 0000000000..456ccd3d7d --- /dev/null +++ b/tests/auto/qml/qmllint/data/attachedPropNotReused.qml @@ -0,0 +1,8 @@ +import QtQuick + +Text { + text: KeyNavigation.priority == KeyNavigation.BeforeItem ? "before" : "after" + Text { + text: KeyNavigation.priority == KeyNavigation.BeforeItem ? "before" : "after" + } +} diff --git a/tests/auto/qml/qmllint/data/attachedPropertyAssignments.qml b/tests/auto/qml/qmllint/data/attachedPropertyAssignments.qml new file mode 100644 index 0000000000..5ef62f8626 --- /dev/null +++ b/tests/auto/qml/qmllint/data/attachedPropertyAssignments.qml @@ -0,0 +1,5 @@ +import AttachedProperties 1.0 +QtObject { + TestType.count: 42 + TestType.str: "hello" +} diff --git a/tests/auto/qml/qmllint/data/attachedTypeIndirect.qml b/tests/auto/qml/qmllint/data/attachedTypeIndirect.qml new file mode 100644 index 0000000000..65598a26cd --- /dev/null +++ b/tests/auto/qml/qmllint/data/attachedTypeIndirect.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 + +QtObject { + GrdView.delayRemove: true +} diff --git a/tests/auto/qml/qmllint/data/badAliasExpression.qml b/tests/auto/qml/qmllint/data/badAliasExpression.qml new file mode 100644 index 0000000000..655509c783 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badAliasExpression.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + id: self + property alias name: self.objectName + 5 +} diff --git a/tests/auto/qml/qmllint/data/badAliasNotAnExpression.qml b/tests/auto/qml/qmllint/data/badAliasNotAnExpression.qml new file mode 100644 index 0000000000..cdc2b28c07 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badAliasNotAnExpression.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 +Item { + + property alias innerObj: { + id: inner + } + +} diff --git a/tests/auto/qml/qmllint/data/badAttachedProperty.qml b/tests/auto/qml/qmllint/data/badAttachedProperty.qml new file mode 100644 index 0000000000..c3f81c8058 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badAttachedProperty.qml @@ -0,0 +1,8 @@ +import AttachedProperties 1.0 +QtObject { + TestType.object: Component {} + + Component.onCompleted: { + console.log(TestType.progress) // wrong, as progress should be a property of TestType.object + } +} diff --git a/tests/auto/qml/qmllint/data/badAttachedPropertyNested.qml b/tests/auto/qml/qmllint/data/badAttachedPropertyNested.qml new file mode 100644 index 0000000000..4c88a263dd --- /dev/null +++ b/tests/auto/qml/qmllint/data/badAttachedPropertyNested.qml @@ -0,0 +1,15 @@ +import AttachedProperties 1.0 +QtObject { + TestType.object: Component {} + + Component.onCompleted: { + console.log(TestType.object.progress); + } + + property QtObject child: QtObject { + Component.onCompleted: { + // doesn't work: this type's TestType.object is not set + console.log(TestType.object.progress); + } + } +} diff --git a/tests/auto/qml/qmllint/data/badAttachedPropertyTypeQtObject.qml b/tests/auto/qml/qmllint/data/badAttachedPropertyTypeQtObject.qml new file mode 100644 index 0000000000..8aa241bb64 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badAttachedPropertyTypeQtObject.qml @@ -0,0 +1,5 @@ +import AttachedProperties 1.0 +QtObject { + // count has type int, so assigning QtObject to it is wrong + TestType.count: QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/badAttachedPropertyTypeString.qml b/tests/auto/qml/qmllint/data/badAttachedPropertyTypeString.qml new file mode 100644 index 0000000000..b06052d93f --- /dev/null +++ b/tests/auto/qml/qmllint/data/badAttachedPropertyTypeString.qml @@ -0,0 +1,5 @@ +import AttachedProperties 1.0 +QtObject { + // count has type int, so assigning string to it is wrong + TestType.count: "hello, world" +} diff --git a/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers1.qml b/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers1.qml new file mode 100644 index 0000000000..a2d1c14aaa --- /dev/null +++ b/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers1.qml @@ -0,0 +1,4 @@ +import PropertyChangeHandlers 1.0 +TypeWithProperties { + onAChanged: function(value) { console.log("error!", value); } +} diff --git a/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers2.qml b/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers2.qml new file mode 100644 index 0000000000..8e6ed938b0 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers2.qml @@ -0,0 +1,4 @@ +import PropertyChangeHandlers 1.0 +TypeWithProperties { + onBChanged: function(value) { console.log("error!", value); } +} diff --git a/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers3.qml b/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers3.qml new file mode 100644 index 0000000000..58b56128d2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers3.qml @@ -0,0 +1,4 @@ +import PropertyChangeHandlers 1.0 +TypeWithProperties { + onXChanged: { console.log("error!"); } +} diff --git a/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers4.qml b/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers4.qml new file mode 100644 index 0000000000..6526a46a8c --- /dev/null +++ b/tests/auto/qml/qmllint/data/badCppPropertyChangeHandlers4.qml @@ -0,0 +1,4 @@ +import PropertyChangeHandlers 1.0 +TypeWithProperties { + onWannabeSignal: { console.log("error!"); } +} diff --git a/tests/auto/qml/qmllint/data/badGeneralizedGroup1.qml b/tests/auto/qml/qmllint/data/badGeneralizedGroup1.qml new file mode 100644 index 0000000000..95d38d42de --- /dev/null +++ b/tests/auto/qml/qmllint/data/badGeneralizedGroup1.qml @@ -0,0 +1,9 @@ +import QtQuick +import Things + +Item { + id: self + WithImmediate { + self.aaaa: 15 - 1 + } +} diff --git a/tests/auto/qml/qmllint/data/badGeneralizedGroup2.qml b/tests/auto/qml/qmllint/data/badGeneralizedGroup2.qml new file mode 100644 index 0000000000..546aad50ab --- /dev/null +++ b/tests/auto/qml/qmllint/data/badGeneralizedGroup2.qml @@ -0,0 +1,9 @@ +import QtQuick +import Things + +Item { + id: self + WithImmediate { + aself.x: 15 - 1 + } +} diff --git a/tests/auto/qml/qmllint/data/badLiteralBinding.qml b/tests/auto/qml/qmllint/data/badLiteralBinding.qml new file mode 100644 index 0000000000..b3cfc8f4ee --- /dev/null +++ b/tests/auto/qml/qmllint/data/badLiteralBinding.qml @@ -0,0 +1,4 @@ +import QtQuick +Item { + property int int1: "foo" +} diff --git a/tests/auto/qml/qmllint/data/badLiteralBindingDate.qml b/tests/auto/qml/qmllint/data/badLiteralBindingDate.qml new file mode 100644 index 0000000000..5a62a97083 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badLiteralBindingDate.qml @@ -0,0 +1,4 @@ +import QtQuick +Item { + property date date1: "not a valid date" +} diff --git a/tests/auto/qml/qmllint/data/badModulePrefix.qml b/tests/auto/qml/qmllint/data/badModulePrefix.qml new file mode 100644 index 0000000000..e3b513d149 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badModulePrefix.qml @@ -0,0 +1,7 @@ +import QtQml +import TestTypes as T + +QtObject { + id: self + property string baz: self.T.CppSingleton.objectName +} diff --git a/tests/auto/qml/qmllint/data/badModulePrefix2.qml b/tests/auto/qml/qmllint/data/badModulePrefix2.qml new file mode 100644 index 0000000000..f7bf73e180 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badModulePrefix2.qml @@ -0,0 +1,7 @@ +import QtQml +import TestTypes as T + +QtObject { + property rect rr + property date foo: rr.T.BirthdayParty.rsvp +} diff --git a/tests/auto/qml/qmllint/data/badScript.attached.qml b/tests/auto/qml/qmllint/data/badScript.attached.qml new file mode 100644 index 0000000000..f3183430fc --- /dev/null +++ b/tests/auto/qml/qmllint/data/badScript.attached.qml @@ -0,0 +1,4 @@ +import QtQuick +Text { + font.pixelSize: 10 + pointSize * 0.1 // pointSize does not exist in the scope of the binding +} diff --git a/tests/auto/qml/qmllint/data/badScriptBinding.attached.qml b/tests/auto/qml/qmllint/data/badScriptBinding.attached.qml new file mode 100644 index 0000000000..a5ec7d9050 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badScriptBinding.attached.qml @@ -0,0 +1,6 @@ +import QtQuick.Layouts +RowLayout { + function returnTrue() { return true; } + Layout.fillWidth: returnTrue() + Layout.bogusProperty: returnTrue() +} diff --git a/tests/auto/qml/qmllint/data/badScriptBinding.attachedSignalHandler.qml b/tests/auto/qml/qmllint/data/badScriptBinding.attachedSignalHandler.qml new file mode 100644 index 0000000000..56d89a81da --- /dev/null +++ b/tests/auto/qml/qmllint/data/badScriptBinding.attachedSignalHandler.qml @@ -0,0 +1,7 @@ +import QtQuick +Rectangle { + Keys.onBogusSignal: function(event) { + // the handler is good, but the signal doesn't exist + console.log(event); + } +} diff --git a/tests/auto/qml/qmllint/data/badScriptBinding.group.qml b/tests/auto/qml/qmllint/data/badScriptBinding.group.qml new file mode 100644 index 0000000000..d92feb81f0 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badScriptBinding.group.qml @@ -0,0 +1,4 @@ +import QtQuick +Text { + font.bogusProperty: "foo" + "bar" +} diff --git a/tests/auto/qml/qmllint/data/badTemplateStringSimple.qml b/tests/auto/qml/qmllint/data/badTemplateStringSimple.qml new file mode 100644 index 0000000000..21c98943f2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badTemplateStringSimple.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property int i: `hallo` +} diff --git a/tests/auto/qml/qmllint/data/bad_QT_TR_NOOP.qml b/tests/auto/qml/qmllint/data/bad_QT_TR_NOOP.qml new file mode 100644 index 0000000000..1e7b315dc5 --- /dev/null +++ b/tests/auto/qml/qmllint/data/bad_QT_TR_NOOP.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property int i: QT_TR_NOOP("fail") +} diff --git a/tests/auto/qml/qmllint/data/bad_builtins/builtins.qmltypes b/tests/auto/qml/qmllint/data/bad_builtins/builtins.qmltypes new file mode 100644 index 0000000000..96f98dd14e --- /dev/null +++ b/tests/auto/qml/qmllint/data/bad_builtins/builtins.qmltypes @@ -0,0 +1,513 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by: +// 'qmlplugindump -builtins' + +Module { + dependencies: [] + Component { + name: "Qt" + Enum { + name: "GlobalColor" + values: { + "color0": 0, + "color1": 1, + "black": 2, + "white": 3, + "darkGray": 4, + "gray": 5, + "lightGray": 6, + "red": 7, + "green": 8, + "blue": 9, + "cyan": 10, + "magenta": 11, + "yellow": 12, + "darkRed": 13, + "darkGreen": 14, + "darkBlue": 15, + "darkCyan": 16, + "darkMagenta": 17, + "darkYellow": 18, + "transparent": 19 + } + } + Enum { + name: "KeyboardModifiers" + values: { + "NoModifier": 0, + "ShiftModifier": 33554432, + "ControlModifier": 67108864, + "AltModifier": 134217728, + "MetaModifier": 268435456, + "KeypadModifier": 536870912, + "GroupSwitchModifier": 1073741824, + "KeyboardModifierMask": -33554432 + } + } + Enum { + name: "MouseButtons" + values: { + "NoButton": 0, + "LeftButton": 1, + "RightButton": 2, + "MidButton": 4, // For backwards compatibility + "MiddleButton": 4, + "BackButton": 8, + "XButton1": 8, + "ExtraButton1": 8, + "ForwardButton": 16, + "XButton2": 16, + "ExtraButton2": 16, + "TaskButton": 32, + "ExtraButton3": 32, + "ExtraButton4": 64, + "ExtraButton5": 128, + "ExtraButton6": 256, + "ExtraButton7": 512, + "ExtraButton8": 1024, + "ExtraButton9": 2048, + "ExtraButton10": 4096, + "ExtraButton11": 8192, + "ExtraButton12": 16384, + "ExtraButton13": 32768, + "ExtraButton14": 65536, + "ExtraButton15": 131072, + "ExtraButton16": 262144, + "ExtraButton17": 524288, + "ExtraButton18": 1048576, + "ExtraButton19": 2097152, + "ExtraButton20": 4194304, + "ExtraButton21": 8388608, + "ExtraButton22": 16777216, + "ExtraButton23": 33554432, + "ExtraButton24": 67108864, + "AllButtons": 134217727, + "MaxMouseButton": 67108864, + "MouseButtonMask": -1 + } + } + Enum { + name: "Orientation" + values: { + "Horizontal": 1, + "Vertical": 2 + } + } + Enum { + name: "Orientations" + values: { + "Horizontal": 1, + "Vertical": 2 + } + } + Enum { + name: "FocusPolicy" + values: { + "NoFocus": 0, + "TabFocus": 1, + "ClickFocus": 2, + "StrongFocus": 11, + "WheelFocus": 15 + } + } + Enum { + name: "TabFocusBehavior" + values: { + "NoTabFocus": 0, + "TabFocusTextControls": 1, + "TabFocusListControls": 2, + "TabFocusAllControls": 255 + } + } + Enum { + name: "SortOrder" + values: { + "AscendingOrder": 0, + "DescendingOrder": 1 + } + } + Enum { + name: "SplitBehavior" + values: { + "KeepEmptyParts": 0, + "SkipEmptyParts": 1 + } + } + Enum { + name: "Alignment" + values: { + "AlignLeft": 1, + "AlignLeading": 1, + "AlignRight": 2, + "AlignTrailing": 2, + "AlignHCenter": 4, + "AlignJustify": 8, + "AlignAbsolute": 16, + "AlignHorizontal_Mask": 31, + "AlignTop": 32, + "AlignBottom": 64, + "AlignVCenter": 128, + "AlignBaseline": 256, + "AlignVertical_Mask": 480, + "AlignCenter": 132 + } + } + Enum { + name: "TextFlag" + values: { + "TextSingleLine": 256, + "TextDontClip": 512, + "TextExpandTabs": 1024, + "TextShowMnemonic": 2048, + "TextWordWrap": 4096, + "TextWrapAnywhere": 8192, + "TextDontPrint": 16384, + "TextIncludeTrailingSpaces": 134217728, + "TextHideMnemonic": 32768, + "TextJustificationForced": 65536, + "TextForceLeftToRight": 131072, + "TextForceRightToLeft": 262144, + "TextLongestVariant": 524288, + "TextBypassShaping": 1048576 + } + } + Enum { + name: "TextElideMode" + values: { + "ElideLeft": 0, + "ElideRight": 1, + "ElideMiddle": 2, + "ElideNone": 3 + } + } + Enum { + name: "WindowType" + values: { + "Widget": 0, + "Window": 1, + "Dialog": 3, + "Sheet": 5, + "Drawer": 7, + "Popup": 9, + "Tool": 11, + "ToolTip": 13, + "SplashScreen": 15, + "Desktop": 17, + "SubWindow": 18, + "ForeignWindow": 33, + "CoverWindow": 65, + "WindowType_Mask": 255, + "MSWindowsFixedSizeDialogHint": 256, + "MSWindowsOwnDC": 512, + "BypassWindowManagerHint": 1024, + "X11BypassWindowManagerHint": 1024, + "FramelessWindowHint": 2048, + "WindowTitleHint": 4096, + "WindowSystemMenuHint": 8192, + "WindowMinimizeButtonHint": 16384, + "WindowMaximizeButtonHint": 32768, + "WindowMinMaxButtonsHint": 49152, + "WindowContextHelpButtonHint": 65536, + "WindowShadeButtonHint": 131072, + "WindowStaysOnTopHint": 262144, + "WindowTransparentForInput": 524288, + "WindowOverridesSystemGestures": 1048576, + "WindowDoesNotAcceptFocus": 2097152, + "MaximizeUsingFullscreenGeometryHint": 4194304, + "CustomizeWindowHint": 33554432, + "WindowStaysOnBottomHint": 67108864, + "WindowCloseButtonHint": 134217728, + "MacWindowToolBarButtonHint": 268435456, + "BypassGraphicsProxyWidget": 536870912, + "NoDropShadowWindowHint": 1073741824, + "WindowFullscreenButtonHint": -2147483648 + } + } + Enum { + name: "WindowFlags" + values: { + "Widget": 0, + "Window": 1, + "Dialog": 3, + "Sheet": 5, + "Drawer": 7, + "Popup": 9, + "Tool": 11, + "ToolTip": 13, + "SplashScreen": 15, + "Desktop": 17, + "SubWindow": 18, + "ForeignWindow": 33, + "CoverWindow": 65, + "WindowType_Mask": 255, + "MSWindowsFixedSizeDialogHint": 256, + "MSWindowsOwnDC": 512, + "BypassWindowManagerHint": 1024, + "X11BypassWindowManagerHint": 1024, + "FramelessWindowHint": 2048, + "WindowTitleHint": 4096, + "WindowSystemMenuHint": 8192, + "WindowMinimizeButtonHint": 16384, + "WindowMaximizeButtonHint": 32768, + "WindowMinMaxButtonsHint": 49152, + "WindowContextHelpButtonHint": 65536, + "WindowShadeButtonHint": 131072, + "WindowStaysOnTopHint": 262144, + "WindowTransparentForInput": 524288, + "WindowOverridesSystemGestures": 1048576, + "WindowDoesNotAcceptFocus": 2097152, + "MaximizeUsingFullscreenGeometryHint": 4194304, + "CustomizeWindowHint": 33554432, + "WindowStaysOnBottomHint": 67108864, + "WindowCloseButtonHint": 134217728, + "MacWindowToolBarButtonHint": 268435456, + "BypassGraphicsProxyWidget": 536870912, + "NoDropShadowWindowHint": 1073741824, + "WindowFullscreenButtonHint": -2147483648 + } + } + Enum { + name: "WindowState" + values: { + "WindowNoState": 0, + "WindowMinimized": 1, + "WindowMaximized": 2, + "WindowFullScreen": 4, + "WindowActive": 8 + } + } + Enum { + name: "WindowStates" + values: { + "WindowNoState": 0, + "WindowMinimized": 1, + "WindowMaximized": 2, + "WindowFullScreen": 4, + "WindowActive": 8 + } + } + Enum { + name: "ApplicationState" + values: { + "ApplicationSuspended": 0, + "ApplicationHidden": 1, + "ApplicationInactive": 2, + "ApplicationActive": 4 + } + } + Enum { + name: "ScreenOrientation" + values: { + "PrimaryOrientation": 0, + "PortraitOrientation": 1, + "LandscapeOrientation": 2, + "InvertedPortraitOrientation": 4, + "InvertedLandscapeOrientation": 8 + } + } + Enum { + name: "ScreenOrientations" + values: { + "PrimaryOrientation": 0, + "PortraitOrientation": 1, + "LandscapeOrientation": 2, + "InvertedPortraitOrientation": 4, + "InvertedLandscapeOrientation": 8 + } + } + Enum { + name: "WidgetAttribute" + values: { + "WA_Disabled": 0, + "WA_UnderMouse": 1, + "WA_MouseTracking": 2, + "WA_ContentsPropagated": 3, + "WA_OpaquePaintEvent": 4, + "WA_NoBackground": 4, + "WA_StaticContents": 5, + "WA_LaidOut": 7, + "WA_PaintOnScreen": 8, + "WA_NoSystemBackground": 9, + "WA_UpdatesDisabled": 10, + "WA_Mapped": 11, + "WA_MacNoClickThrough": 12, + "WA_InputMethodEnabled": 14, + "WA_WState_Visible": 15, + "WA_WState_Hidden": 16, + "WA_ForceDisabled": 32, + "WA_KeyCompression": 33, + "WA_PendingMoveEvent": 34, + "WA_PendingResizeEvent": 35, + "WA_SetPalette": 36, + "WA_SetFont": 37, + "WA_SetCursor": 38, + "WA_NoChildEventsFromChildren": 39, + "WA_WindowModified": 41, + "WA_Resized": 42, + "WA_Moved": 43, + "WA_PendingUpdate": 44, + "WA_InvalidSize": 45, + "WA_MacBrushedMetal": 46, + "WA_MacMetalStyle": 46, + "WA_CustomWhatsThis": 47, + "WA_LayoutOnEntireRect": 48, + "WA_OutsideWSRange": 49, + "WA_GrabbedShortcut": 50, + "WA_TransparentForMouseEvents": 51, + "WA_PaintUnclipped": 52, + "WA_SetWindowIcon": 53, + "WA_NoMouseReplay": 54, + "WA_DeleteOnClose": 55, + "WA_RightToLeft": 56, + "WA_SetLayoutDirection": 57, + "WA_NoChildEventsForParent": 58, + "WA_ForceUpdatesDisabled": 59, + "WA_WState_Created": 60, + "WA_WState_CompressKeys": 61, + "WA_WState_InPaintEvent": 62, + "WA_WState_Reparented": 63, + "WA_WState_ConfigPending": 64, + "WA_WState_Polished": 66, + "WA_WState_DND": 67, + "WA_WState_OwnSizePolicy": 68, + "WA_WState_ExplicitShowHide": 69, + "WA_ShowModal": 70, + "WA_MouseNoMask": 71, + "WA_GroupLeader": 72, + "WA_NoMousePropagation": 73, + "WA_Hover": 74, + "WA_InputMethodTransparent": 75, + "WA_QuitOnClose": 76, + "WA_KeyboardFocusChange": 77, + "WA_AcceptDrops": 78, + "WA_DropSiteRegistered": 79, + "WA_ForceAcceptDrops": 79, + "WA_WindowPropagation": 80, + "WA_NoX11EventCompression": 81, + "WA_TintedBackground": 82, + "WA_X11OpenGLOverlay": 83, + "WA_AlwaysShowToolTips": 84, + "WA_MacOpaqueSizeGrip": 85, + "WA_SetStyle": 86, + "WA_SetLocale": 87, + "WA_MacShowFocusRect": 88, + "WA_MacNormalSize": 89, + "WA_MacSmallSize": 90, + "WA_MacMiniSize": 91, + "WA_LayoutUsesWidgetRect": 92, + "WA_StyledBackground": 93, + "WA_MSWindowsUseDirect3D": 94, + "WA_CanHostQMdiSubWindowTitleBar": 95, + "WA_MacAlwaysShowToolWindow": 96, + "WA_StyleSheet": 97, + "WA_ShowWithoutActivating": 98, + "WA_X11BypassTransientForHint": 99, + "WA_NativeWindow": 100, + "WA_DontCreateNativeAncestors": 101, + "WA_MacVariableSize": 102, + "WA_DontShowOnScreen": 103, + "WA_X11NetWmWindowTypeDesktop": 104, + "WA_X11NetWmWindowTypeDock": 105, + "WA_X11NetWmWindowTypeToolBar": 106, + "WA_X11NetWmWindowTypeMenu": 107, + "WA_X11NetWmWindowTypeUtility": 108, + "WA_X11NetWmWindowTypeSplash": 109, + "WA_X11NetWmWindowTypeDialog": 110, + "WA_X11NetWmWindowTypeDropDownMenu": 111, + "WA_X11NetWmWindowTypePopupMenu": 112, + "WA_X11NetWmWindowTypeToolTip": 113, + "WA_X11NetWmWindowTypeNotification": 114, + "WA_X11NetWmWindowTypeCombo": 115, + "WA_X11NetWmWindowTypeDND": 116, + "WA_MacFrameworkScaled": 117, + "WA_SetWindowModality": 118, + "WA_WState_WindowOpacitySet": 119, + "WA_TranslucentBackground": 120, + "WA_AcceptTouchEvents": 121, + "WA_WState_AcceptedTouchBeginEvent": 122, + "WA_TouchPadAcceptSingleTouchEvents": 123, + "WA_X11DoNotAcceptFocus": 126, + "WA_MacNoShadow": 127, + "WA_AlwaysStackOnTop": 128, + "WA_TabletTracking": 129, + "WA_ContentsMarginsRespectsSafeArea": 130, + "WA_StyleSheetTarget": 131, + "WA_AttributeCount": 132 + } + } + Enum { + name: "ApplicationAttribute" + values: { + "AA_ImmediateWidgetCreation": 0, + "AA_MSWindowsUseDirect3DByDefault": 1, + "AA_DontShowIconsInMenus": 2, + "AA_NativeWindows": 3, + "AA_DontCreateNativeWidgetSiblings": 4, + "AA_PluginApplication": 5, + "AA_MacPluginApplication": 5, + "AA_DontUseNativeMenuBar": 6, + "AA_MacDontSwapCtrlAndMeta": 7, + "AA_Use96Dpi": 8, + "AA_X11InitThreads": 10, + "AA_SynthesizeTouchForUnhandledMouseEvents": 11, + "AA_SynthesizeMouseForUnhandledTouchEvents": 12, + "AA_UseHighDpiPixmaps": 13, + "AA_ForceRasterWidgets": 14, + "AA_UseDesktopOpenGL": 15, + "AA_UseOpenGLES": 16, + "AA_UseSoftwareOpenGL": 17, + "AA_ShareOpenGLContexts": 18, + "AA_SetPalette": 19, + "AA_EnableHighDpiScaling": 20, + "AA_DisableHighDpiScaling": 21, + "AA_UseStyleSheetPropagationInWidgetStyles": 22, + "AA_DontUseNativeDialogs": 23, + "AA_SynthesizeMouseForUnhandledTabletEvents": 24, + "AA_CompressHighFrequencyEvents": 25, + "AA_DontCheckOpenGLContextThreadAffinity": 26, + "AA_DisableShaderDiskCache": 27, + "AA_DontShowShortcutsInContextMenus": 28, + "AA_CompressTabletEvents": 29, + "AA_DisableWindowContextHelpButton": 30, + "AA_DisableSessionManager": 31, + "AA_AttributeCount": 32 + } + } + Enum { + name: "ImageConversionFlags" + values: { + "ColorMode_Mask": 3, + "AutoColor": 0, + "ColorOnly": 3, + "MonoOnly": 2, + "AlphaDither_Mask": 12, + "ThresholdAlphaDither": 0, + "OrderedAlphaDither": 4, + "DiffuseAlphaDither": 8, + "NoAlpha": 12, + "Dither_Mask": 48, + "DiffuseDither": 0, + "OrderedDither": 16, + "ThresholdDither": 32, + "DitherMode_Mask": 192, + "AutoDither": 0, + "PreferDither": 64, + "AvoidDither": 128, + "NoOpaqueDetection": 256, + "NoFormatConversion": 512 + } + } + Enum { + name: "BGMode" + values: { + "TransparentMode": 0, + "OpaqueMode": 1 + } + } + } + Component { name: "QEasingCurve"; prototype: "QQmlEasingValueType" } +} diff --git a/tests/auto/qml/qmllint/data/bad_qsTr.qml b/tests/auto/qml/qmllint/data/bad_qsTr.qml new file mode 100644 index 0000000000..3723324a72 --- /dev/null +++ b/tests/auto/qml/qmllint/data/bad_qsTr.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property int i: qsTr("fail") +} diff --git a/tests/auto/qml/qmllint/data/badlyBoundComponents.qml b/tests/auto/qml/qmllint/data/badlyBoundComponents.qml new file mode 100644 index 0000000000..4f25f1d508 --- /dev/null +++ b/tests/auto/qml/qmllint/data/badlyBoundComponents.qml @@ -0,0 +1,25 @@ +pragma ComponentBehavior: Bound + +import QtQml + +QtObject { + id: root + property string foo: "bar" + property Component c1: Component { + QtObject { + id: cc + objectName: root.foo + property int i: 12 + } + } + + property Component c2: Component { + QtObject { + objectName: root.foo + cc.i + } + } + + property QtObject o1: c1.createObject() + property QtObject o2: c2.createObject() + +} diff --git a/tests/auto/qml/qmllint/data/bareQt.qml b/tests/auto/qml/qmllint/data/bareQt.qml new file mode 100644 index 0000000000..331a66345d --- /dev/null +++ b/tests/auto/qml/qmllint/data/bareQt.qml @@ -0,0 +1,5 @@ +import QML + +QtObject { + property var a: Qt.application +} diff --git a/tests/auto/qml/qmllint/data/bindingBeforeDeclaration.qml b/tests/auto/qml/qmllint/data/bindingBeforeDeclaration.qml new file mode 100644 index 0000000000..7fc592d7f0 --- /dev/null +++ b/tests/auto/qml/qmllint/data/bindingBeforeDeclaration.qml @@ -0,0 +1,6 @@ +import QtQuick + +Item { + binding: QtObject {} + property QtObject binding +} diff --git a/tests/auto/qml/qmllint/data/bindingTypeMismatch.qml b/tests/auto/qml/qmllint/data/bindingTypeMismatch.qml new file mode 100644 index 0000000000..ffde545e7d --- /dev/null +++ b/tests/auto/qml/qmllint/data/bindingTypeMismatch.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + property int number: 3 + "Hello" +} diff --git a/tests/auto/qml/qmllint/data/bindingTypeMismatchFunction.qml b/tests/auto/qml/qmllint/data/bindingTypeMismatchFunction.qml new file mode 100644 index 0000000000..74d5be4edb --- /dev/null +++ b/tests/auto/qml/qmllint/data/bindingTypeMismatchFunction.qml @@ -0,0 +1,6 @@ +import QtQuick + +Item { + function returnsString() : string {} + property int number: returnsString() +} diff --git a/tests/auto/qml/qmllint/data/boundComponents.qml b/tests/auto/qml/qmllint/data/boundComponents.qml new file mode 100644 index 0000000000..2ffa2f4124 --- /dev/null +++ b/tests/auto/qml/qmllint/data/boundComponents.qml @@ -0,0 +1,23 @@ +pragma ComponentBehavior: Bound + +import QtQml + +QtObject { + id: root + property string foo: "bar" + property Component c1: Component { + QtObject { + id: c1 + objectName: root.foo + property int i: 12 + property Component c2: Component { + QtObject { + objectName: root.foo + c1.i + } + } + property QtObject o: c2.createObject() + } + } + + property QtObject o: c1.createObject() +} diff --git a/tests/auto/qml/qmllint/data/bytearray.qml b/tests/auto/qml/qmllint/data/bytearray.qml new file mode 100644 index 0000000000..31c41028db --- /dev/null +++ b/tests/auto/qml/qmllint/data/bytearray.qml @@ -0,0 +1,5 @@ +import TestTypes + +HasByteArray { + property int l: byteArray.byteLength +} diff --git a/tests/auto/qml/qmllint/data/cachedDependency.qml b/tests/auto/qml/qmllint/data/cachedDependency.qml new file mode 100644 index 0000000000..5a15a66997 --- /dev/null +++ b/tests/auto/qml/qmllint/data/cachedDependency.qml @@ -0,0 +1,23 @@ +import QtQuick.Controls.impl // Caches QtQuick as depedency, without QML names +import QtQuick + +Item { + QtObject { id: object } + Item { id: item } + Rectangle { id: rectangle } + + // Various ways to cast between types contained in QtQuick and QtQml + // The QML names of both have to be available for this to work + + property QtObject objectAsObject: object as QtObject + property QtObject objectAsItem: object as Item + property QtObject objectAsRectangle: object as Rectangle + + property QtObject itemAsObject: item as QtObject + property QtObject itemAsItem: item as Item + property QtObject itemAsRectangle: item as Rectangle + + property QtObject rectangleAsObject: rectangle as QtObject + property QtObject rectangleAsItem: rectangle as Item + property QtObject rectangleAsRectangle: rectangle as Rectangle +} diff --git a/tests/auto/qml/qmllint/data/callBase.qml b/tests/auto/qml/qmllint/data/callBase.qml new file mode 100644 index 0000000000..435a5f04dd --- /dev/null +++ b/tests/auto/qml/qmllint/data/callBase.qml @@ -0,0 +1,7 @@ +import QtQml + +QtObject { + function bar(foo : Foo) { + var state = foo.whatSUp() + } +} diff --git a/tests/auto/qml/qmllint/data/callJSValueProp.qml b/tests/auto/qml/qmllint/data/callJSValueProp.qml new file mode 100644 index 0000000000..57a828fec4 --- /dev/null +++ b/tests/auto/qml/qmllint/data/callJSValueProp.qml @@ -0,0 +1,6 @@ +import QtQuick + +Rectangle { + // Note: gradient is not actually callable + Component.onCompleted: gradient(42); +} diff --git a/tests/auto/qml/qmllint/data/callLater.qml b/tests/auto/qml/qmllint/data/callLater.qml new file mode 100644 index 0000000000..6f654ebdb1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/callLater.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + Component.onCompleted: Qt.callLater(console.log, "hello, World") +} diff --git a/tests/auto/qml/qmllint/data/callVarProp.qml b/tests/auto/qml/qmllint/data/callVarProp.qml new file mode 100644 index 0000000000..ad69e2a679 --- /dev/null +++ b/tests/auto/qml/qmllint/data/callVarProp.qml @@ -0,0 +1,7 @@ +import QtQml + +QtObject { + property var foo: () => {} + + Component.onCompleted: foo() +} diff --git a/tests/auto/qml/qmllint/data/coercetovoid.qml b/tests/auto/qml/qmllint/data/coercetovoid.qml new file mode 100644 index 0000000000..f1b593ea3a --- /dev/null +++ b/tests/auto/qml/qmllint/data/coercetovoid.qml @@ -0,0 +1,8 @@ +pragma Strict +import QtQml + +QtObject { + function touchThisAndReturnSomething(x: int) { + return x + 1; + } +} diff --git a/tests/auto/qml/qmllint/data/compositesingleton.qml b/tests/auto/qml/qmllint/data/compositesingleton.qml new file mode 100644 index 0000000000..42db13154e --- /dev/null +++ b/tests/auto/qml/qmllint/data/compositesingleton.qml @@ -0,0 +1,8 @@ +import QtQml +import QmlBench + +QtObject { + property real x: Globals.realProp + property real y: Globals.intProp + property bool smooth: Globals.boolProp +} diff --git a/tests/auto/qml/qmllint/data/connectionNoParent.qml b/tests/auto/qml/qmllint/data/connectionNoParent.qml new file mode 100644 index 0000000000..27f7e22cf3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/connectionNoParent.qml @@ -0,0 +1,5 @@ +import QtQuick + +Connections { + function onClicked() {} +} diff --git a/tests/auto/qml/qmllint/data/constructorProperty.qml b/tests/auto/qml/qmllint/data/constructorProperty.qml new file mode 100644 index 0000000000..d7ef884283 --- /dev/null +++ b/tests/auto/qml/qmllint/data/constructorProperty.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property double f: Number.EPSILON +} diff --git a/tests/auto/qml/qmllint/data/controlsWithQuick_pluginTest.qml b/tests/auto/qml/qmllint/data/controlsWithQuick_pluginTest.qml new file mode 100644 index 0000000000..2897174a54 --- /dev/null +++ b/tests/auto/qml/qmllint/data/controlsWithQuick_pluginTest.qml @@ -0,0 +1,4 @@ +import QtQuick.Controls as QQC +import QtQuick.Window + +QQC.Control {} diff --git a/tests/auto/qml/qmllint/data/controlsWithoutQuick_pluginTest.qml b/tests/auto/qml/qmllint/data/controlsWithoutQuick_pluginTest.qml new file mode 100644 index 0000000000..c84e5527ba --- /dev/null +++ b/tests/auto/qml/qmllint/data/controlsWithoutQuick_pluginTest.qml @@ -0,0 +1,3 @@ +import QtQuick.Controls + +Control {} diff --git a/tests/auto/qml/qmllint/data/customParser.qml b/tests/auto/qml/qmllint/data/customParser.qml new file mode 100644 index 0000000000..324ca20953 --- /dev/null +++ b/tests/auto/qml/qmllint/data/customParser.qml @@ -0,0 +1,17 @@ +import QtQuick 2.0 + +Rectangle { + id: root + width: 100; height: 100 + + states: [ + State { + name: "red_color" + PropertyChanges { root.color: "red" } + }, + State { + name: "blue_color" + PropertyChanges { root.color: "blue" } + } + ] +} diff --git a/tests/auto/qml/qmllint/data/customParser.recursive.qml b/tests/auto/qml/qmllint/data/customParser.recursive.qml new file mode 100644 index 0000000000..aa15460021 --- /dev/null +++ b/tests/auto/qml/qmllint/data/customParser.recursive.qml @@ -0,0 +1,16 @@ +import QtQuick 2.0 + +ListModel { + id: listModel + ListElement { dataType: "rect"; color: "green"; font.color: "red"; ListElement {} Behavior on FooBar {} } + ListElement { dataType: "image"; source: "../shared/images/qt-logo.png" } + ListElement { dataType: "rect"; color: "green" } + ListElement { dataType: "image"; source: "../shared/images/qt-logo.png" } + ListElement { dataType: "rect"; color: "blue" } + ListElement { dataType: "rect"; color: "blue" } + ListElement { dataType: "rect"; color: "blue" } + ListElement { dataType: "rect"; color: "blue" } + ListElement { dataType: "rect"; color: "blue" } + ListElement { dataType: "rect"; color: "blue" } +} + diff --git a/tests/auto/qml/qmllint/data/customParserUnqualifiedAccess.qml b/tests/auto/qml/qmllint/data/customParserUnqualifiedAccess.qml new file mode 100644 index 0000000000..dc8f814c91 --- /dev/null +++ b/tests/auto/qml/qmllint/data/customParserUnqualifiedAccess.qml @@ -0,0 +1,5 @@ +import Things + +CustomParserThing { + foo: does.not.exist +} diff --git a/tests/auto/qml/qmllint/data/cycleHead.qml b/tests/auto/qml/qmllint/data/cycleHead.qml new file mode 100644 index 0000000000..080eab381f --- /dev/null +++ b/tests/auto/qml/qmllint/data/cycleHead.qml @@ -0,0 +1,7 @@ +import Cycle +import QtQuick + +Item { + property MenuItem item: a + MenuItem { id: a } +} diff --git a/tests/auto/qml/qmllint/data/optionalImport.qml b/tests/auto/qml/qmllint/data/defaultImport.qml index 2be7cd444a..2be7cd444a 100644 --- a/tests/auto/qml/qmllint/data/optionalImport.qml +++ b/tests/auto/qml/qmllint/data/defaultImport.qml diff --git a/tests/auto/qml/qmllint/data/defaultProperty.qml b/tests/auto/qml/qmllint/data/defaultProperty.qml new file mode 100644 index 0000000000..be9368c7aa --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultProperty.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 + +TypeWithDefaultProperty { + QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/defaultPropertyComponent.2.qml b/tests/auto/qml/qmllint/data/defaultPropertyComponent.2.qml new file mode 100644 index 0000000000..1c3736e703 --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyComponent.2.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Item { + Component { + Rectangle {} + } +} diff --git a/tests/auto/qml/qmllint/data/defaultPropertyComponent.qml b/tests/auto/qml/qmllint/data/defaultPropertyComponent.qml new file mode 100644 index 0000000000..b57225ff4f --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyComponent.qml @@ -0,0 +1,5 @@ +import QtQuick + +Repeater { + QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/defaultPropertyList.qml b/tests/auto/qml/qmllint/data/defaultPropertyList.qml new file mode 100644 index 0000000000..ebf6357c34 --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyList.qml @@ -0,0 +1,7 @@ +import QtQml 2.0 +import QtQuick 2.15 + +TypeWithDefaultListProperty { + QtObject {} + Rectangle {} +} diff --git a/tests/auto/qml/qmllint/data/defaultPropertyListModel.qml b/tests/auto/qml/qmllint/data/defaultPropertyListModel.qml new file mode 100644 index 0000000000..f0bac0fdf7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyListModel.qml @@ -0,0 +1,6 @@ +import QtQuick 2.15 +import QtQml.Models 2.15 + +Item { + ListModel {} +} diff --git a/tests/auto/qml/qmllint/data/defaultPropertyVar.qml b/tests/auto/qml/qmllint/data/defaultPropertyVar.qml new file mode 100644 index 0000000000..1202d5384d --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyVar.qml @@ -0,0 +1,5 @@ +import QtQml 2.0 + +TypeWithDefaultVarProperty { + QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/defaultPropertyWithDoubleAssignment.qml b/tests/auto/qml/qmllint/data/defaultPropertyWithDoubleAssignment.qml new file mode 100644 index 0000000000..8c2d09fb97 --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyWithDoubleAssignment.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 + +TypeWithDefaultProperty { + QtObject {} + QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/defaultPropertyWithWrongType.qml b/tests/auto/qml/qmllint/data/defaultPropertyWithWrongType.qml new file mode 100644 index 0000000000..d04fecda49 --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyWithWrongType.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 + +TypeWithDefaultStringProperty { + // default property has type `string`, so cannot assing an object to it + QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/defaultPropertyWithinTheSameType.qml b/tests/auto/qml/qmllint/data/defaultPropertyWithinTheSameType.qml new file mode 100644 index 0000000000..6284cca15c --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyWithinTheSameType.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 + +QtObject { + default property QtObject child + QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/defaultPropertyWithoutKeyword.qml b/tests/auto/qml/qmllint/data/defaultPropertyWithoutKeyword.qml new file mode 100644 index 0000000000..38f7a55984 --- /dev/null +++ b/tests/auto/qml/qmllint/data/defaultPropertyWithoutKeyword.qml @@ -0,0 +1,6 @@ +import QtQml 2.0 + +QtObject { + property QtObject child + QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/delegateContextProperties.qml b/tests/auto/qml/qmllint/data/delegateContextProperties.qml new file mode 100644 index 0000000000..4e133a38de --- /dev/null +++ b/tests/auto/qml/qmllint/data/delegateContextProperties.qml @@ -0,0 +1,9 @@ +import QtQuick + +ListView { + model: ListModel {} + delegate: Text { + text: model.text + color: index % 2 ? "red" : "blue" + } +} diff --git a/tests/auto/qml/qmllint/data/deprecatedFunction.qml b/tests/auto/qml/qmllint/data/deprecatedFunction.qml new file mode 100644 index 0000000000..9face2edf7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/deprecatedFunction.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 + +DeprecatedFunctions { + @Deprecated { reason: "No particular reason." } + function deprecated(foobar) {} + + Component.onCompleted: { + deprecated(); + } +} diff --git a/tests/auto/qml/qmllint/data/deprecatedFunctionInherited.qml b/tests/auto/qml/qmllint/data/deprecatedFunctionInherited.qml new file mode 100644 index 0000000000..0164530720 --- /dev/null +++ b/tests/auto/qml/qmllint/data/deprecatedFunctionInherited.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +DeprecatedFunctions { + Component.onCompleted: { + deprecatedInherited(); + } +} diff --git a/tests/auto/qml/qmllint/data/deprecatedFunctionOverride.qml b/tests/auto/qml/qmllint/data/deprecatedFunctionOverride.qml new file mode 100644 index 0000000000..f5c88b763e --- /dev/null +++ b/tests/auto/qml/qmllint/data/deprecatedFunctionOverride.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +DeprecatedFunctions { + function deprecatedOverride(x, y, z) {} + Component.onCompleted: { + deprecatedOverride(); + } +} diff --git a/tests/auto/qml/qmllint/data/deprecatedProperty.qml b/tests/auto/qml/qmllint/data/deprecatedProperty.qml new file mode 100644 index 0000000000..539e7abb38 --- /dev/null +++ b/tests/auto/qml/qmllint/data/deprecatedProperty.qml @@ -0,0 +1,10 @@ +import QtQml + +QtObject { + @Deprecated {} + property int deprecated: 10 + + Component.onCompleted: { + console.log(deprecated); + } +} diff --git a/tests/auto/qml/qmllint/data/deprecatedPropertyBinding.qml b/tests/auto/qml/qmllint/data/deprecatedPropertyBinding.qml new file mode 100644 index 0000000000..ba3fbe6024 --- /dev/null +++ b/tests/auto/qml/qmllint/data/deprecatedPropertyBinding.qml @@ -0,0 +1,3 @@ +DeprProp { + deprecated: 200 +} diff --git a/tests/auto/qml/qmllint/data/deprecatedPropertyBindingReason.qml b/tests/auto/qml/qmllint/data/deprecatedPropertyBindingReason.qml new file mode 100644 index 0000000000..543afde5e3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/deprecatedPropertyBindingReason.qml @@ -0,0 +1,3 @@ +DeprProp { + deprecatedReason: 200 +} diff --git a/tests/auto/qml/qmllint/data/deprecatedPropertyReason.qml b/tests/auto/qml/qmllint/data/deprecatedPropertyReason.qml new file mode 100644 index 0000000000..0e1edad6d0 --- /dev/null +++ b/tests/auto/qml/qmllint/data/deprecatedPropertyReason.qml @@ -0,0 +1,12 @@ +import QtQml + +QtObject { + @Deprecated { + reason: "Test" + } + property int deprecated: 10 + + Component.onCompleted: { + console.log(deprecated); + } +} diff --git a/tests/auto/qml/qmllint/data/deprecatedType.qml b/tests/auto/qml/qmllint/data/deprecatedType.qml new file mode 100644 index 0000000000..997e5d1ff2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/deprecatedType.qml @@ -0,0 +1,3 @@ +import QtQml + +TypeDeprecated {} diff --git a/tests/auto/qml/qmllint/data/deprecatedTypeReason.qml b/tests/auto/qml/qmllint/data/deprecatedTypeReason.qml new file mode 100644 index 0000000000..faa84a4127 --- /dev/null +++ b/tests/auto/qml/qmllint/data/deprecatedTypeReason.qml @@ -0,0 +1,3 @@ +import QtQml + +TypeDeprecatedReason {} diff --git a/tests/auto/qml/qmllint/data/didYouMeanBinding.qml b/tests/auto/qml/qmllint/data/didYouMeanBinding.qml new file mode 100644 index 0000000000..b5bb9b44ea --- /dev/null +++ b/tests/auto/qml/qmllint/data/didYouMeanBinding.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + witdh: 50 +} diff --git a/tests/auto/qml/qmllint/data/didYouMeanComponent.qml b/tests/auto/qml/qmllint/data/didYouMeanComponent.qml new file mode 100644 index 0000000000..42f21c4969 --- /dev/null +++ b/tests/auto/qml/qmllint/data/didYouMeanComponent.qml @@ -0,0 +1,4 @@ +import QtQuick 2.0 + +Itym { +} diff --git a/tests/auto/qml/qmllint/data/didYouMeanEnum.qml b/tests/auto/qml/qmllint/data/didYouMeanEnum.qml new file mode 100644 index 0000000000..5e6bcb4c87 --- /dev/null +++ b/tests/auto/qml/qmllint/data/didYouMeanEnum.qml @@ -0,0 +1,5 @@ +import QtQuick + +Image { + property bool isReady: status === Image.Readx +} diff --git a/tests/auto/qml/qmllint/data/didYouMeanProperty.qml b/tests/auto/qml/qmllint/data/didYouMeanProperty.qml new file mode 100644 index 0000000000..c27f10b978 --- /dev/null +++ b/tests/auto/qml/qmllint/data/didYouMeanProperty.qml @@ -0,0 +1,6 @@ +import QtQuick + +Item { + Rectangle { id: rect } + width: rect.hoight * 2 +} diff --git a/tests/auto/qml/qmllint/data/didYouMeanPropertyCall.qml b/tests/auto/qml/qmllint/data/didYouMeanPropertyCall.qml new file mode 100644 index 0000000000..2bd6f796f2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/didYouMeanPropertyCall.qml @@ -0,0 +1,7 @@ +import QtQuick + +Item { + Component.onCompleted: { + console.lgg("Hello World!"); + } +} diff --git a/tests/auto/qml/qmllint/data/didYouMeanUnqualified.qml b/tests/auto/qml/qmllint/data/didYouMeanUnqualified.qml new file mode 100644 index 0000000000..ca92f525f3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/didYouMeanUnqualified.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + width: hoight * 2 +} diff --git a/tests/auto/qml/qmllint/data/didYouMeanUnqualifiedCall.qml b/tests/auto/qml/qmllint/data/didYouMeanUnqualifiedCall.qml new file mode 100644 index 0000000000..6baff8f74a --- /dev/null +++ b/tests/auto/qml/qmllint/data/didYouMeanUnqualifiedCall.qml @@ -0,0 +1,6 @@ +import QtQuick + +Item { + function func() {} + width: funk() * 2 +} diff --git a/tests/auto/qml/qmllint/data/dontCheckJSTypes.qml b/tests/auto/qml/qmllint/data/dontCheckJSTypes.qml new file mode 100644 index 0000000000..dc582936b9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/dontCheckJSTypes.qml @@ -0,0 +1,11 @@ +import QtQuick + +import "SharedFunctions.js" as Functions + +Item { + Rectangle { + color: Functions.setColorAlpha(Qt.color("orange"), 0.15) + x: Functions.setColorAlpha.asdfg + y: Functions.asdfg + } +} diff --git a/tests/auto/qml/qmllint/data/duplicateId.qml b/tests/auto/qml/qmllint/data/duplicateId.qml new file mode 100644 index 0000000000..0cd822b5ef --- /dev/null +++ b/tests/auto/qml/qmllint/data/duplicateId.qml @@ -0,0 +1,8 @@ +import QtQuick + +Item { + id: root + Item { + id: root + } +} diff --git a/tests/auto/qml/qmllint/data/duplicatedPropertyName.qml b/tests/auto/qml/qmllint/data/duplicatedPropertyName.qml new file mode 100644 index 0000000000..18a4435f5f --- /dev/null +++ b/tests/auto/qml/qmllint/data/duplicatedPropertyName.qml @@ -0,0 +1,9 @@ +import QtQuick + +Item { + property int cat: 12 + property string cat: "mutantx" + + signal clicked() + signal clicked(a: int) +}
\ No newline at end of file diff --git a/tests/auto/qml/qmllint/data/elementpass_pluginTest.qml b/tests/auto/qml/qmllint/data/elementpass_pluginTest.qml new file mode 100644 index 0000000000..b9250a2d11 --- /dev/null +++ b/tests/auto/qml/qmllint/data/elementpass_pluginTest.qml @@ -0,0 +1,7 @@ +import QtQuick + +Item { + Rectangle { + radius: 5 + } +} diff --git a/tests/auto/qml/qmllint/data/enumInvalid.qml b/tests/auto/qml/qmllint/data/enumInvalid.qml new file mode 100644 index 0000000000..a14955d3e2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/enumInvalid.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + property bool c: Qt.red > 4 + property bool d: Qt.red < 2 +} diff --git a/tests/auto/qml/qmllint/data/enumsOfScrollBar.qml b/tests/auto/qml/qmllint/data/enumsOfScrollBar.qml new file mode 100644 index 0000000000..d0cd5591b9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/enumsOfScrollBar.qml @@ -0,0 +1,7 @@ +import QtQuick +import QtQuick.Controls + +Item { + Component.onCompleted: console.log(ScrollBar.AlwaysOn) +} + diff --git a/tests/auto/qml/qmllint/data/findMemberPrint.qml b/tests/auto/qml/qmllint/data/findMemberPrint.qml new file mode 100644 index 0000000000..69146eb06b --- /dev/null +++ b/tests/auto/qml/qmllint/data/findMemberPrint.qml @@ -0,0 +1,13 @@ +import QtQml + +import TestTypes + +QtObject { + property var foooooooo: Foo { + id: foo + } + + function f(): void { + foo.print() + } +} diff --git a/tests/auto/qml/qmllint/data/generalizedGroupHint.qml b/tests/auto/qml/qmllint/data/generalizedGroupHint.qml new file mode 100644 index 0000000000..5fec03f7f3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/generalizedGroupHint.qml @@ -0,0 +1,23 @@ +import QtQuick + +Window { + width: 640 + height: 480 + visible: true + title: 'Resolve my color type' + + Item { + id: foo + + states: [ + State { + PropertyChanges { + target: foo + myColor: Qt.rgba(0.5, 0.5, 0.5, 0.16) + } + } + ] + + property color myColor: 'black' + } +} diff --git a/tests/auto/qml/qmllint/data/goodAttachedProperty.qml b/tests/auto/qml/qmllint/data/goodAttachedProperty.qml new file mode 100644 index 0000000000..8472aabb10 --- /dev/null +++ b/tests/auto/qml/qmllint/data/goodAttachedProperty.qml @@ -0,0 +1,13 @@ +import AttachedProperties 1.0 +QtObject { + TestType.object: Component {} + TestType.count: 42 + 2 + Component.onCompleted: { + TestType.count = 42; + // TestType here is an attached type, not this object's instance of it. + // This attached type has an unchanged property object of type QtObject, + // so accessing Component's specific property 'progress' is only + // possible with a cast to Component type + console.log((TestType.object as Component).progress); + } +} diff --git a/tests/auto/qml/qmllint/data/goodAttachedPropertyAccess.qml b/tests/auto/qml/qmllint/data/goodAttachedPropertyAccess.qml new file mode 100644 index 0000000000..b7f64d9acb --- /dev/null +++ b/tests/auto/qml/qmllint/data/goodAttachedPropertyAccess.qml @@ -0,0 +1,14 @@ +import AttachedProperties 1.0 +QtObject { + id: root + TestType.object: QtObject { + property int progress: 42 + } + + Component.onCompleted: { + // NB: this currently fails as TestType.object is recognized as QtObject + // *exactly*, ignoring the QML code above and thus there's no 'progress' + // property on TestType.object + console.log(TestType.object.progress); + } +} diff --git a/tests/auto/qml/qmllint/data/goodAttachedPropertyNested.qml b/tests/auto/qml/qmllint/data/goodAttachedPropertyNested.qml new file mode 100644 index 0000000000..98d7726063 --- /dev/null +++ b/tests/auto/qml/qmllint/data/goodAttachedPropertyNested.qml @@ -0,0 +1,20 @@ +import AttachedProperties 1.0 +QtObject { + id: root + TestType.object: Component {} + TestType.count: 42 + 2 + + Component.onCompleted: { + TestType.count = 42; + console.log(TestType.object.progress); + } + + QtObject { + TestType.count: 43 + Component.onCompleted: { + console.log(TestType.count); + console.log(root.TestType.count); + console.log(root.TestType.object.progress); + } + } +} diff --git a/tests/auto/qml/qmllint/data/goodBindingsOnGroupAndAttached.qml b/tests/auto/qml/qmllint/data/goodBindingsOnGroupAndAttached.qml new file mode 100644 index 0000000000..7a89b82f6e --- /dev/null +++ b/tests/auto/qml/qmllint/data/goodBindingsOnGroupAndAttached.qml @@ -0,0 +1,11 @@ +import QtQuick +Rectangle { + Text { + font.pixelSize: 42 + } + + Keys.enabled: false + Keys.onPressed: function(event) { + console.log(event); + } +} diff --git a/tests/auto/qml/qmllint/data/goodCppPropertyChangeHandlers.qml b/tests/auto/qml/qmllint/data/goodCppPropertyChangeHandlers.qml new file mode 100644 index 0000000000..1ec2284c7d --- /dev/null +++ b/tests/auto/qml/qmllint/data/goodCppPropertyChangeHandlers.qml @@ -0,0 +1,26 @@ +import PropertyChangeHandlers 1.0 +import QtQuick +Item { + TypeWithProperties { + onAChanged: { console.log("OK"); } + onBChanged: { console.log("OK"); } + onCChanged: { console.log("OK"); } + onDChanged: { console.log("OK"); } + onEChanged: { console.log("OK"); } + } + + TypeWithProperties { + onCWeirdSignal: { console.log("OK"); } + onDSignal: { console.log("OK"); } + } + + TypeWithProperties { + onCWeirdSignal: function(value) { console.log("OK?", value); } + onDSignal: function(value, str) { console.log("OK?", value, str); } + } + + TypeWithProperties { + onCChanged: function(value) { console.log("OK?", value); } + onDChanged: function(value, str) { console.log("OK?", value, str); } + } +} diff --git a/tests/auto/qml/qmllint/data/goodGeneralizedGroup.qml b/tests/auto/qml/qmllint/data/goodGeneralizedGroup.qml new file mode 100644 index 0000000000..97c821adb7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/goodGeneralizedGroup.qml @@ -0,0 +1,9 @@ +import QtQuick +import Things + +Item { + id: self + WithImmediate { + self.x: 15 - 1 + } +} diff --git a/tests/auto/qml/qmllint/data/goodModulePrefix.qml b/tests/auto/qml/qmllint/data/goodModulePrefix.qml new file mode 100644 index 0000000000..251bcd82c0 --- /dev/null +++ b/tests/auto/qml/qmllint/data/goodModulePrefix.qml @@ -0,0 +1,9 @@ +import QtQml +import TestTypes as T + +QtObject { + id: self + property date foo: self.T.BirthdayParty.rsvp + property date bar: T.BirthdayParty.rsvp + property string baz: T.CppSingleton.objectName +} diff --git a/tests/auto/qml/qmllint/data/groupedAttachedLayout.qml b/tests/auto/qml/qmllint/data/groupedAttachedLayout.qml new file mode 100644 index 0000000000..7cfe98d4f8 --- /dev/null +++ b/tests/auto/qml/qmllint/data/groupedAttachedLayout.qml @@ -0,0 +1,20 @@ +import QtQuick +import QtQuick.Layouts + +Window { + id: root + + Rectangle { + id: redRect + } + + Item { + states: [ + State { + PropertyChanges { + redRect.Layout.fillWidth: true + } + } + ] + } +} diff --git a/tests/auto/qml/qmllint/data/groupedPropertyAssignments.qml b/tests/auto/qml/qmllint/data/groupedPropertyAssignments.qml new file mode 100644 index 0000000000..8874960d63 --- /dev/null +++ b/tests/auto/qml/qmllint/data/groupedPropertyAssignments.qml @@ -0,0 +1,5 @@ +import QtQuick +Text { + font.pixelSize: 24 + font.underline: true +} diff --git a/tests/auto/qml/qmllint/data/groupedProperty_valueSource_interceptor.qml b/tests/auto/qml/qmllint/data/groupedProperty_valueSource_interceptor.qml new file mode 100644 index 0000000000..4150df1aa3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/groupedProperty_valueSource_interceptor.qml @@ -0,0 +1,6 @@ +import QtQuick 2.0 + +Text { + Behavior on font.bold {} + NumberAnimation on font.letterSpacing {} +} diff --git a/tests/auto/qml/qmllint/data/here.qml b/tests/auto/qml/qmllint/data/here.qml new file mode 100644 index 0000000000..1ead2eedd1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/here.qml @@ -0,0 +1,3 @@ +import Things.Nested + +A {} diff --git a/tests/auto/qml/qmllint/data/hidden/moduleWithQrc/main.qml b/tests/auto/qml/qmllint/data/hidden/moduleWithQrc/main.qml new file mode 100644 index 0000000000..d018110b86 --- /dev/null +++ b/tests/auto/qml/qmllint/data/hidden/moduleWithQrc/main.qml @@ -0,0 +1,11 @@ +import QtQuick +import QtQuick.Controls + +Window { + width: 640; height: 480 + visible: true + + Button { + text: "a" + } +} diff --git a/tests/auto/qml/qmllint/data/hidden/moduleWithQrc/qmldir b/tests/auto/qml/qmllint/data/hidden/moduleWithQrc/qmldir new file mode 100644 index 0000000000..acb456ffd9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/hidden/moduleWithQrc/qmldir @@ -0,0 +1,3 @@ +module moduleWithQrc +prefer :/qt/qml/moduleWithQrc/ + diff --git a/tests/auto/qml/qmllint/data/hidden/moduleWithQrc_raw_qml_0.qrc b/tests/auto/qml/qmllint/data/hidden/moduleWithQrc_raw_qml_0.qrc new file mode 100644 index 0000000000..43d3ec805c --- /dev/null +++ b/tests/auto/qml/qmllint/data/hidden/moduleWithQrc_raw_qml_0.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/qt/qml/qmllint65/"> + <file alias="main.qml">moduleWithQrc/main.qml</file> + </qresource> +</RCC> + diff --git a/tests/auto/qml/qmllint/data/hidden/qmake_moduleWithQrc.qrc b/tests/auto/qml/qmllint/data/hidden/qmake_moduleWithQrc.qrc new file mode 100644 index 0000000000..cb362e2d55 --- /dev/null +++ b/tests/auto/qml/qmllint/data/hidden/qmake_moduleWithQrc.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/qt/qml/qmllint65"> + <file alias="qmldir">moduleWithQrc/qmldir</file> + </qresource> +</RCC> + diff --git a/tests/auto/qml/qmllint/data/ignoreWarnings.qml b/tests/auto/qml/qmllint/data/ignoreWarnings.qml new file mode 100644 index 0000000000..90bb9a5436 --- /dev/null +++ b/tests/auto/qml/qmllint/data/ignoreWarnings.qml @@ -0,0 +1,24 @@ +import QtQuick 2.0 +import QtTest 2.0 // qmllint disable unused-imports +import QtTest 2.0 // qmllint disable + +Item { + @Deprecated {} + property string deprecated + + property string a: root.a // qmllint disable unqualified + property string b: root.a // qmllint disable + + // qmllint disable unqualified + property string c: root.a + property string d: root.a + // qmllint enable unqualified + + //qmllint disable + property string e: root.a + Component.onCompleted: { + console.log(deprecated); + } + // qmllint enable + +} diff --git a/tests/auto/qml/qmllint/data/implicitImportResource.qrc b/tests/auto/qml/qmllint/data/implicitImportResource.qrc new file mode 100644 index 0000000000..026c8c4d4f --- /dev/null +++ b/tests/auto/qml/qmllint/data/implicitImportResource.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/"> + <file>additionalImplicitImport.qml</file> + <file alias="qmldir">Things/qmldir</file> + </qresource> +</RCC> diff --git a/tests/auto/qml/qmllint/data/importNonexistentFile.qml b/tests/auto/qml/qmllint/data/importNonexistentFile.qml new file mode 100644 index 0000000000..847023936a --- /dev/null +++ b/tests/auto/qml/qmllint/data/importNonexistentFile.qml @@ -0,0 +1,3 @@ +import "¯\(ツ)/¯:/invalid/url" + +QtObject {} diff --git a/tests/auto/qml/qmllint/data/importNullDevice.qml b/tests/auto/qml/qmllint/data/importNullDevice.qml new file mode 100644 index 0000000000..5ff3090d75 --- /dev/null +++ b/tests/auto/qml/qmllint/data/importNullDevice.qml @@ -0,0 +1,3 @@ +import "/dev/null" + +QtObject {} diff --git a/tests/auto/qml/qmllint/data/importQMLModule.qml b/tests/auto/qml/qmllint/data/importQMLModule.qml new file mode 100644 index 0000000000..842183ed5b --- /dev/null +++ b/tests/auto/qml/qmllint/data/importQMLModule.qml @@ -0,0 +1,2 @@ +import QML +QtObject {} diff --git a/tests/auto/qml/qmllint/data/importing_js.qml b/tests/auto/qml/qmllint/data/importing_js.qml index b2d7a34fe6..3f226f1566 100644 --- a/tests/auto/qml/qmllint/data/importing_js.qml +++ b/tests/auto/qml/qmllint/data/importing_js.qml @@ -3,4 +3,6 @@ import QtQuick Item { id: root + + property var foo: JSTest.foo("Test") } diff --git a/tests/auto/qml/qmllint/data/inaccessibleId.qml b/tests/auto/qml/qmllint/data/inaccessibleId.qml new file mode 100644 index 0000000000..a3489f4741 --- /dev/null +++ b/tests/auto/qml/qmllint/data/inaccessibleId.qml @@ -0,0 +1,12 @@ +import QtQml + +QtObject { + id: a + + property Component c: Component { + QtObject { + property int a: 5 + objectName: a.objectName + } + } +} diff --git a/tests/auto/qml/qmllint/data/inaccessibleId2.qml b/tests/auto/qml/qmllint/data/inaccessibleId2.qml new file mode 100644 index 0000000000..b8f381b0b7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/inaccessibleId2.qml @@ -0,0 +1,10 @@ +import QtQml + +QtObject { + id: a + + component Handle: QtObject { + property int a: 5 + objectName: a.objectName + } +} diff --git a/tests/auto/qml/qmllint/data/incompleteQmltypes2.qml b/tests/auto/qml/qmllint/data/incompleteQmltypes2.qml new file mode 100644 index 0000000000..1cbe89dadb --- /dev/null +++ b/tests/auto/qml/qmllint/data/incompleteQmltypes2.qml @@ -0,0 +1,6 @@ +import Things 1.0 + +SomethingEntirelyStrange { + id: self + property var a: self.palette2.weDontKnowIt +} diff --git a/tests/auto/qml/qmllint/data/incompleteQmltypes3.qml b/tests/auto/qml/qmllint/data/incompleteQmltypes3.qml new file mode 100644 index 0000000000..142134d49e --- /dev/null +++ b/tests/auto/qml/qmllint/data/incompleteQmltypes3.qml @@ -0,0 +1,6 @@ +import Things 1.0 + +SomethingEntirelyStrange { + id: self + property var a: palette +} diff --git a/tests/auto/qml/qmllint/data/initReadonly.qml b/tests/auto/qml/qmllint/data/initReadonly.qml new file mode 100644 index 0000000000..a9a2a0016b --- /dev/null +++ b/tests/auto/qml/qmllint/data/initReadonly.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + readonly property int i: 14 + readonly property int j: i + 20 +} diff --git a/tests/auto/qml/qmllint/data/inlineComponent.qml b/tests/auto/qml/qmllint/data/inlineComponent.qml new file mode 100644 index 0000000000..364d5319de --- /dev/null +++ b/tests/auto/qml/qmllint/data/inlineComponent.qml @@ -0,0 +1,15 @@ +import QtQuick 2.0 + +Item { + component MyIC: IC {} + component IC : QtObject {} + QtObject { + component IC2: QtObject {} + + property IC ic: IC {} + property IC2 ic2: IC2 {} + } + + property IC ic : IC {} + property IC2 ic2: IC2 {} +} diff --git a/tests/auto/qml/qmllint/data/inlineComponentNoComponent.qml b/tests/auto/qml/qmllint/data/inlineComponentNoComponent.qml new file mode 100644 index 0000000000..f72b0a27c5 --- /dev/null +++ b/tests/auto/qml/qmllint/data/inlineComponentNoComponent.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 +Item { + component Base : eItm { } +} + diff --git a/tests/auto/qml/qmllint/data/inlineComponentWithComponents.qml b/tests/auto/qml/qmllint/data/inlineComponentWithComponents.qml new file mode 100644 index 0000000000..431d3ee076 --- /dev/null +++ b/tests/auto/qml/qmllint/data/inlineComponentWithComponents.qml @@ -0,0 +1,11 @@ +import QtQuick 2.0 + +Item { + component IC : Text { + text: "Hello world!" + MouseArea {} // Previously this would overwrite the IC + } + + property IC ic: IC {} + property string icText: ic.text // Check that we can access a property not contained in the component that would overwrite +} diff --git a/tests/auto/qml/qmllint/data/inlineComponentsChained.qml b/tests/auto/qml/qmllint/data/inlineComponentsChained.qml new file mode 100644 index 0000000000..cc063b1bc2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/inlineComponentsChained.qml @@ -0,0 +1,10 @@ +import QtQuick + +Item { + component A : B { required foo } + component B : C { property QtObject foo } + component C : Item { + } + A { foo: QtObject {} } +} + diff --git a/tests/auto/qml/qmllint/data/interceptor.qml b/tests/auto/qml/qmllint/data/interceptor.qml new file mode 100644 index 0000000000..89b4c0e54a --- /dev/null +++ b/tests/auto/qml/qmllint/data/interceptor.qml @@ -0,0 +1,10 @@ +import QtQuick 2.0 + +Image { + transform: Rotation { + angle: 6 + Behavior on angle { + SpringAnimation { spring: 2; damping: 0.2; modulus: 360 } + } + } +} diff --git a/tests/auto/qml/qmllint/data/interceptor_valueSource.qml b/tests/auto/qml/qmllint/data/interceptor_valueSource.qml new file mode 100644 index 0000000000..876ef37734 --- /dev/null +++ b/tests/auto/qml/qmllint/data/interceptor_valueSource.qml @@ -0,0 +1,23 @@ +import QtQuick 2.0 + +Item { + Image { + transform: Rotation { + Behavior on angle { + SpringAnimation { spring: 2; damping: 0.2; modulus: 360 } + } + NumberAnimation on angle { + } + } + } + + Image { + transform: Rotation { + NumberAnimation on angle { + } + Behavior on angle { + SpringAnimation { spring: 2; damping: 0.2; modulus: 360 } + } + } + } +} diff --git a/tests/auto/qml/qmllint/data/invalidAliasTarget.qml b/tests/auto/qml/qmllint/data/invalidAliasTarget.qml new file mode 100644 index 0000000000..e6ad63b518 --- /dev/null +++ b/tests/auto/qml/qmllint/data/invalidAliasTarget.qml @@ -0,0 +1,11 @@ +import QtQuick + +Item { + Item { + + property alias innerinner + property alias name: function f() {} + + property alias innerObj: 1+1 + } +} diff --git a/tests/auto/qml/qmllint/data/invalidId1.qml b/tests/auto/qml/qmllint/data/invalidId1.qml new file mode 100644 index 0000000000..61c45530f1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/invalidId1.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + id: foo.bar +} diff --git a/tests/auto/qml/qmllint/data/invalidId2.qml b/tests/auto/qml/qmllint/data/invalidId2.qml new file mode 100644 index 0000000000..dc4b05be24 --- /dev/null +++ b/tests/auto/qml/qmllint/data/invalidId2.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Item { + id: { + console.log("hi"); + } +} diff --git a/tests/auto/qml/qmllint/data/invalidIdLookup.qml b/tests/auto/qml/qmllint/data/invalidIdLookup.qml new file mode 100644 index 0000000000..b351e5cfea --- /dev/null +++ b/tests/auto/qml/qmllint/data/invalidIdLookup.qml @@ -0,0 +1,10 @@ +import Things +import QtQml + +QtObject { + property MediaPlayerStateMachine m: MediaPlayerStateMachine { + id: stateMachine + } + + objectName: stateMachine.objectName +} diff --git a/tests/auto/qml/qmllint/data/invalidImport.qml b/tests/auto/qml/qmllint/data/invalidImport.qml new file mode 100644 index 0000000000..f4db5d519c --- /dev/null +++ b/tests/auto/qml/qmllint/data/invalidImport.qml @@ -0,0 +1,4 @@ +import QtQml +import FooBar + +QtObject {} diff --git a/tests/auto/qml/qmllint/data/invalidInterceptor.qml b/tests/auto/qml/qmllint/data/invalidInterceptor.qml new file mode 100644 index 0000000000..e648e9f9bb --- /dev/null +++ b/tests/auto/qml/qmllint/data/invalidInterceptor.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +Image { + transform: Rotation { + angle: 6 + Item on angle {} + } +} diff --git a/tests/auto/qml/qmllint/data/javascriptVariableArgs.qml b/tests/auto/qml/qmllint/data/javascriptVariableArgs.qml new file mode 100644 index 0000000000..a9dc79dbba --- /dev/null +++ b/tests/auto/qml/qmllint/data/javascriptVariableArgs.qml @@ -0,0 +1,9 @@ +import QtQml + +QtObject { + function varArgs() {} + Component.onCompleted: { + console.log("It works!"); + varArgs("This works", 2); + } +} diff --git a/tests/auto/qml/qmllint/data/jsLibrary.qml b/tests/auto/qml/qmllint/data/jsLibrary.qml new file mode 100644 index 0000000000..3878b24616 --- /dev/null +++ b/tests/auto/qml/qmllint/data/jsLibrary.qml @@ -0,0 +1,8 @@ +import QtQml +import JsLibrary as JLib +import "JsLibrary/HelperLibrary.js" as HelperLib + +QtObject { + property string text1: JLib.HelperLibrary.foo() + property string text2: HelperLib.foo() +} diff --git a/tests/auto/qml/qmllint/data/jsVarDeclarations.js b/tests/auto/qml/qmllint/data/jsVarDeclarations.js new file mode 100644 index 0000000000..6c01b9f9a5 --- /dev/null +++ b/tests/auto/qml/qmllint/data/jsVarDeclarations.js @@ -0,0 +1,3 @@ +var varProp = 5; +let letProp = [ 1, 2, 3, 4 ]; +const constProp = "unchangable"; diff --git a/tests/auto/qml/qmllint/data/jsVarDeclarations.qml b/tests/auto/qml/qmllint/data/jsVarDeclarations.qml new file mode 100644 index 0000000000..6297bf002c --- /dev/null +++ b/tests/auto/qml/qmllint/data/jsVarDeclarations.qml @@ -0,0 +1,9 @@ +import QtQuick + +import "jsVarDeclarations.js" as JSVars + +Item { + property int varProp: JSVars.varProp + property var letProp: JSVars.letProp + property string constProp: JSVars.constProp +} diff --git a/tests/auto/qml/qmllint/data/jsVarDeclarationsWriteConst.qml b/tests/auto/qml/qmllint/data/jsVarDeclarationsWriteConst.qml new file mode 100644 index 0000000000..207bb55ff7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/jsVarDeclarationsWriteConst.qml @@ -0,0 +1,7 @@ +import QtQuick + +import "jsVarDeclarations.js" as JSVars + +Item { + Component.onCompleted: { JSVars.constProp = "new value"; } +} diff --git a/tests/auto/qml/qmllint/data/listIndices.qml b/tests/auto/qml/qmllint/data/listIndices.qml new file mode 100644 index 0000000000..b5fda4ef0d --- /dev/null +++ b/tests/auto/qml/qmllint/data/listIndices.qml @@ -0,0 +1,14 @@ +pragma Strict +import QtQml + +QtObject { + id: self + property list<QtObject> items + property int numItems: items.length + + Component.onCompleted: { + items.length = 3 + for (var i = 0; i < 3; ++i) + items[i] = self + } +} diff --git a/tests/auto/qml/qmllint/data/listPropertyMethods.qml b/tests/auto/qml/qmllint/data/listPropertyMethods.qml new file mode 100644 index 0000000000..1e203d4de0 --- /dev/null +++ b/tests/auto/qml/qmllint/data/listPropertyMethods.qml @@ -0,0 +1,87 @@ +import QtQml + +QtObject { + id: self + + required property real i + required property real j + required property real k + + property QtObject r1: QtObject {} + property QtObject r2: QtObject {} + property QtObject r3: QtObject {} + + property list<QtObject> listProperty: [r1, r2, r3] + property list<QtObject> listPropertySlice: listProperty.slice(i, j) + property int listPropertyIndexOf: listProperty.indexOf(r2, i) + property int listPropertyLastIndexOf: listProperty.lastIndexOf(r3, i) + property string listPropertyToString: listProperty.toString() + property string listPropertyToLocaleString: listProperty.toLocaleString() + property list<QtObject> listPropertyConcat: listProperty.concat(listProperty) + property QtObject listPropertyFind: listProperty.find(element => element.objectName === "") + property int listPropertyFindIndex: listProperty.findIndex(element => element === r2) + property bool listPropertyIncludes: listProperty.includes(r3) + property string listPropertyJoin: listProperty.join() + + property bool entriesMatch: { + var iterator = listProperty.entries(); + for (var [index, element] of listProperty.entries()) { + var v = iterator.next().value; + if (index !== v[0] || element !== v[1]) { + console.log(index, v[0], element, v[1]); + return false; + } + } + + return true; + } + + property bool keysMatch: { + var iterator = listProperty.keys(); + for (var index of listProperty.keys()) { + var v = iterator.next().value; + if (index !== v) { + console.log(index, v); + return false; + } + } + + return true; + } + + property bool valuesMatch: { + var iterator = listProperty.values(); + for (var obj of listProperty.values()) { + var v = iterator.next().value; + if (obj !== v) { + console.log(obj, v); + return false; + } + } + + return true; + } + + property bool listPropertyEvery: listProperty.every((element) => element != null) + property bool listPropertySome: listProperty.some((element) => element.objectName === "") + + property list<int> listPropertyMap: listProperty.map(((element) => element.objectName.length)) + property list<QtObject> listPropertyFilter: listProperty.filter((element) => element.objectName.length != 1) + property string listPropertyReduceRight: listProperty.reduceRight((element, v) => v + '-' + element.objectName + 'v', "") + property string listPropertyReduce: listProperty.reduce((element, v) => v + '-' + element.objectName + 'v', "") + property list<string> listPropertyOwnPropertyNames: Object.getOwnPropertyNames(listProperty) + + Component.onCompleted: { + listProperty.reverse(); + listProperty.pop(); + listProperty.push(self); + listProperty.shift(); + listProperty.unshift(self); + listProperty.forEach((element) => { console.log("-" + element.objectName + "-") }); + listProperty.sort(); + listProperty.sort((a, b) => (a.objectName.length - b.objectName.length)) + listProperty.copyWithin(i, j, k); + listProperty.fill(self, i, Math.min(j, 1024)); + listProperty.splice(i, j, self, self, self); + } +} diff --git a/tests/auto/qml/qmllint/data/locale.qml b/tests/auto/qml/qmllint/data/locale.qml new file mode 100644 index 0000000000..4ff9e6392c --- /dev/null +++ b/tests/auto/qml/qmllint/data/locale.qml @@ -0,0 +1,6 @@ +import QtQml +import LocaleTest + +QtObject { + property int monday: AppManager.primaryLocale.firstDayOfWeek +} diff --git a/tests/auto/qml/qmllint/data/lowerCaseQualifiedImport.qml b/tests/auto/qml/qmllint/data/lowerCaseQualifiedImport.qml new file mode 100644 index 0000000000..14c716c35d --- /dev/null +++ b/tests/auto/qml/qmllint/data/lowerCaseQualifiedImport.qml @@ -0,0 +1,9 @@ +import QtQuick as test + +test.Rectangle { // crashed qqmljsimportvisitor + id: mainRect + width: 100 + height: 100 + visible: true + rotation: 11 +} diff --git a/tests/auto/qml/qmllint/data/lowerCaseQualifiedImport2.qml b/tests/auto/qml/qmllint/data/lowerCaseQualifiedImport2.qml new file mode 100644 index 0000000000..4e03d8091d --- /dev/null +++ b/tests/auto/qml/qmllint/data/lowerCaseQualifiedImport2.qml @@ -0,0 +1,9 @@ +import QtQuick as test + +test.Item { + property test.color c + + property var p: test.Grid {} + + component IC: test.Rectangle {} +} diff --git a/tests/auto/qml/qmllint/data/matchByName.qml b/tests/auto/qml/qmllint/data/matchByName.qml new file mode 100644 index 0000000000..92e00129d7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/matchByName.qml @@ -0,0 +1,8 @@ +import QtQuick +import QtQuick.Controls.Fusion + +Button { + Image { + anchors.centerIn: parent + } +} diff --git a/tests/auto/qml/qmllint/data/missingBuiltinsNoCrash.qml b/tests/auto/qml/qmllint/data/missingBuiltinsNoCrash.qml new file mode 100644 index 0000000000..a2f7d422b3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/missingBuiltinsNoCrash.qml @@ -0,0 +1,3 @@ +import QtQuick // This can't be found if --bare is specified and no paths are provided + +Item {} diff --git a/tests/auto/qml/qmllint/data/missingComponentBehaviorBound.qml b/tests/auto/qml/qmllint/data/missingComponentBehaviorBound.qml new file mode 100644 index 0000000000..0a66ec140d --- /dev/null +++ b/tests/auto/qml/qmllint/data/missingComponentBehaviorBound.qml @@ -0,0 +1,10 @@ +import QtQuick +Item { + id: barsty + property int fooInt: 42 + + Repeater { + model: 5 + Text { text: "Foo=" + barsty.fooInt } + } +} diff --git a/tests/auto/qml/qmllint/data/missingQmltypes.qml b/tests/auto/qml/qmllint/data/missingQmltypes.qml new file mode 100644 index 0000000000..8605b3fddd --- /dev/null +++ b/tests/auto/qml/qmllint/data/missingQmltypes.qml @@ -0,0 +1,4 @@ +import QtQml +import Fake5Compat.GraphicalEffects.private + +QtObject {} diff --git a/tests/auto/qml/qmllint/data/missingRequiredAlias.qml b/tests/auto/qml/qmllint/data/missingRequiredAlias.qml new file mode 100644 index 0000000000..adb0f65198 --- /dev/null +++ b/tests/auto/qml/qmllint/data/missingRequiredAlias.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + RequiredWithRootLevelAlias {} +} diff --git a/tests/auto/qml/qmllint/data/missingSingletonPragma.qml b/tests/auto/qml/qmllint/data/missingSingletonPragma.qml new file mode 100644 index 0000000000..0c691baa76 --- /dev/null +++ b/tests/auto/qml/qmllint/data/missingSingletonPragma.qml @@ -0,0 +1,6 @@ +import QtQml +import Singletons + +QtObject { + Component.onCompleted: console.log(MissingPragma) +} diff --git a/tests/auto/qml/qmllint/data/missingSingletonQmldir.qml b/tests/auto/qml/qmllint/data/missingSingletonQmldir.qml new file mode 100644 index 0000000000..6bbda963a8 --- /dev/null +++ b/tests/auto/qml/qmllint/data/missingSingletonQmldir.qml @@ -0,0 +1,6 @@ +import QtQml +import Singletons + +QtObject { + Component.onCompleted: console.log(MissingQmldirSingleton) +} diff --git a/tests/auto/qml/qmllint/data/multiDefaultPropertyOk.qml b/tests/auto/qml/qmllint/data/multiDefaultPropertyOk.qml new file mode 100644 index 0000000000..64748a5f39 --- /dev/null +++ b/tests/auto/qml/qmllint/data/multiDefaultPropertyOk.qml @@ -0,0 +1,8 @@ +import QML + +MultiDefaultProperty { + Simple {} + Simple {} + Simple {} + NotSoSimple {} +} diff --git a/tests/auto/qml/qmllint/data/multiDefaultPropertyWithWrongType.qml b/tests/auto/qml/qmllint/data/multiDefaultPropertyWithWrongType.qml new file mode 100644 index 0000000000..f5e881d201 --- /dev/null +++ b/tests/auto/qml/qmllint/data/multiDefaultPropertyWithWrongType.qml @@ -0,0 +1,8 @@ +import QtQml + +MultiDefaultProperty { + Simple {} + Simple {} + QtObject {} + Simple {} +} diff --git a/tests/auto/qml/qmllint/data/multiGrouped.qml b/tests/auto/qml/qmllint/data/multiGrouped.qml new file mode 100644 index 0000000000..ab6bd5bd02 --- /dev/null +++ b/tests/auto/qml/qmllint/data/multiGrouped.qml @@ -0,0 +1,6 @@ +import QtQuick + +Item { + anchors.verticalCenter: parent.verticalCenter + anchors { right: parent.left } +} diff --git a/tests/auto/qml/qmllint/data/multifix.fixed.qml b/tests/auto/qml/qmllint/data/multifix.fixed.qml new file mode 100644 index 0000000000..d2188f2318 --- /dev/null +++ b/tests/auto/qml/qmllint/data/multifix.fixed.qml @@ -0,0 +1,14 @@ +pragma ComponentBehavior: Bound +import QtQml + +QtObject { + id: root + + property Component cursorDelegate: QtObject { + objectName: root.objectName + } + + property Component background: QtObject { + objectName: root.objectName + } +} diff --git a/tests/auto/qml/qmllint/data/multifix.qml b/tests/auto/qml/qmllint/data/multifix.qml new file mode 100644 index 0000000000..5f05ae7e62 --- /dev/null +++ b/tests/auto/qml/qmllint/data/multifix.qml @@ -0,0 +1,13 @@ +import QtQml + +QtObject { + id: root + + property Component cursorDelegate: QtObject { + objectName: root.objectName + } + + property Component background: QtObject { + objectName: root.objectName + } +} diff --git a/tests/auto/qml/qmllint/data/multilineString.fixed.qml b/tests/auto/qml/qmllint/data/multilineString.fixed.qml new file mode 100644 index 0000000000..e1d15a926e --- /dev/null +++ b/tests/auto/qml/qmllint/data/multilineString.fixed.qml @@ -0,0 +1,21 @@ +import QtQml + +QtObject { + property string multipart: `Foo +multiline\` +string` + `another\` +part +of it`; + + property string quote: ` +quote: " \\" \\\\" +ticks: \` \` \\\` \\\` +singleTicks: ' \' \\' \\\' +expression: \${expr} \${expr} \\\${expr} \\\${expr}` + + property string tick: ` +quote: " \" \\" \\\" +ticks: \` \` \\\` \\\` +singleTicks: ' \\' \\\\' +expression: \${expr} \${expr} \\\${expr} \\\${expr}` +} diff --git a/tests/auto/qml/qmllint/data/multilineString.qml b/tests/auto/qml/qmllint/data/multilineString.qml new file mode 100644 index 0000000000..758a71f868 --- /dev/null +++ b/tests/auto/qml/qmllint/data/multilineString.qml @@ -0,0 +1,21 @@ +import QtQml + +QtObject { + property string multipart: "Foo +multiline` +string" + "another` +part +of it"; + + property string quote: " +quote: \" \\\" \\\\\" +ticks: ` \` \\\` \\\` +singleTicks: ' \' \\' \\\' +expression: \${expr} \${expr} \\\${expr} \\\${expr}" + + property string tick: ' +quote: " \" \\" \\\" +ticks: \` \` \\\` \\\` +singleTicks: \' \\\' \\\\\' +expression: \${expr} \${expr} \\\${expr} \\\${expr}' +} diff --git a/tests/auto/qml/qmllint/data/multilineStringEscaped.qml b/tests/auto/qml/qmllint/data/multilineStringEscaped.qml new file mode 100644 index 0000000000..e155476b3d --- /dev/null +++ b/tests/auto/qml/qmllint/data/multilineStringEscaped.qml @@ -0,0 +1,8 @@ +import QtQml + +QtObject { + property string test: "Foo\nmultiline\nString" + property string template: `Foo +multiline +string` +} diff --git a/tests/auto/qml/qmllint/data/nestedInlineComponents.qml b/tests/auto/qml/qmllint/data/nestedInlineComponents.qml new file mode 100644 index 0000000000..e2a32df092 --- /dev/null +++ b/tests/auto/qml/qmllint/data/nestedInlineComponents.qml @@ -0,0 +1,7 @@ +import QtQml + +QtObject { + component IC: QtObject { + component IC2: QtObject {} + } +} diff --git a/tests/auto/qml/qmllint/data/nonExistentListProperty.qml b/tests/auto/qml/qmllint/data/nonExistentListProperty.qml new file mode 100644 index 0000000000..a4f549b664 --- /dev/null +++ b/tests/auto/qml/qmllint/data/nonExistentListProperty.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +Item { + objs: [ QtObject {} ] +} diff --git a/tests/auto/qml/qmllint/data/nonNullStored.qml b/tests/auto/qml/qmllint/data/nonNullStored.qml new file mode 100644 index 0000000000..04388103a1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/nonNullStored.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + property Foozle foozle + function barzle() { return foozle.objectName } +} diff --git a/tests/auto/qml/qmllint/data/notQmlRootMethods.qml b/tests/auto/qml/qmllint/data/notQmlRootMethods.qml new file mode 100644 index 0000000000..6d067d572d --- /dev/null +++ b/tests/auto/qml/qmllint/data/notQmlRootMethods.qml @@ -0,0 +1,8 @@ +import QtQml + +QtObject { + id: self + + function a() { self.deleteLater(); } + function b() { self.destroyed(); } +} diff --git a/tests/auto/qml/qmllint/data/nothing_pluginTest.qml b/tests/auto/qml/qmllint/data/nothing_pluginTest.qml new file mode 100644 index 0000000000..3052615aef --- /dev/null +++ b/tests/auto/qml/qmllint/data/nothing_pluginTest.qml @@ -0,0 +1,3 @@ +import QtQuick + +Item {} diff --git a/tests/auto/qml/qmllint/data/nullBinding.qml b/tests/auto/qml/qmllint/data/nullBinding.qml new file mode 100644 index 0000000000..f185ce9eda --- /dev/null +++ b/tests/auto/qml/qmllint/data/nullBinding.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + x: null +} diff --git a/tests/auto/qml/qmllint/data/nullBindingFunction.qml b/tests/auto/qml/qmllint/data/nullBindingFunction.qml new file mode 100644 index 0000000000..89142bd581 --- /dev/null +++ b/tests/auto/qml/qmllint/data/nullBindingFunction.qml @@ -0,0 +1,5 @@ +import QtQuick + +Item { + x: { return null } +} diff --git a/tests/auto/qml/qmllint/data/numberToStringProperty.qml b/tests/auto/qml/qmllint/data/numberToStringProperty.qml new file mode 100644 index 0000000000..6da8566ce3 --- /dev/null +++ b/tests/auto/qml/qmllint/data/numberToStringProperty.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property string i: 1 +} diff --git a/tests/auto/qml/qmllint/data/objectArray.qml b/tests/auto/qml/qmllint/data/objectArray.qml new file mode 100644 index 0000000000..051b20d1d1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/objectArray.qml @@ -0,0 +1,9 @@ +import QtQml 2.15 + +QtObject { + property list<QtObject> objects + objects: [ + QtObject { property string foo: "bar" }, + QtObject { property string bar: "foo" } + ] +} diff --git a/tests/auto/qml/qmllint/data/objectBoundToVar.qml b/tests/auto/qml/qmllint/data/objectBoundToVar.qml new file mode 100644 index 0000000000..405a06a1c4 --- /dev/null +++ b/tests/auto/qml/qmllint/data/objectBoundToVar.qml @@ -0,0 +1,4 @@ +import QtQml +QtObject { + property var child: QtObject { } +} diff --git a/tests/auto/qml/qmllint/data/onBindingInGroupedProperty.qml b/tests/auto/qml/qmllint/data/onBindingInGroupedProperty.qml new file mode 100644 index 0000000000..186b8a557f --- /dev/null +++ b/tests/auto/qml/qmllint/data/onBindingInGroupedProperty.qml @@ -0,0 +1,10 @@ +import QtQuick + +Rectangle +{ + id: root + border + { + ColorAnimation on color { } + } +} diff --git a/tests/auto/qml/qmllint/data/onlyMajorVersion.qml b/tests/auto/qml/qmllint/data/onlyMajorVersion.qml new file mode 100644 index 0000000000..4066f8f097 --- /dev/null +++ b/tests/auto/qml/qmllint/data/onlyMajorVersion.qml @@ -0,0 +1,8 @@ +import QtQuick.Controls 2 as QQC2 + +QQC2.ApplicationWindow { + height: 400 + width: 400 + visible: true + QQC2.Action {} // Action because it appeared in version 2.3 +} diff --git a/tests/auto/qml/qmllint/data/optionalChainingCall.qml b/tests/auto/qml/qmllint/data/optionalChainingCall.qml new file mode 100644 index 0000000000..fe9716293d --- /dev/null +++ b/tests/auto/qml/qmllint/data/optionalChainingCall.qml @@ -0,0 +1,9 @@ +import QtQuick 2.0 + +MouseArea { + id: ma + function f() {} + onClicked: { + f?.() + } +} diff --git a/tests/auto/qml/qmllint/data/overridescript.qml b/tests/auto/qml/qmllint/data/overridescript.qml index b85333b95f..d88f905aa7 100644 --- a/tests/auto/qml/qmllint/data/overridescript.qml +++ b/tests/auto/qml/qmllint/data/overridescript.qml @@ -1,5 +1,4 @@ import QtQml -import QtTest import "testlogger.js" as TestLogger QtObject { diff --git a/tests/auto/qml/qmllint/data/pluginQuick_anchors.qml b/tests/auto/qml/qmllint/data/pluginQuick_anchors.qml new file mode 100644 index 0000000000..927b422a06 --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_anchors.qml @@ -0,0 +1,9 @@ +import QtQuick + +Item { + PluginQuickAnchorsBase { + anchors.horizontalCenter: null + anchors.verticalCenter: null + anchors.baseline: parent.baseline + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_anchorsUndefined.qml b/tests/auto/qml/qmllint/data/pluginQuick_anchorsUndefined.qml new file mode 100644 index 0000000000..b6c0f59c7f --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_anchorsUndefined.qml @@ -0,0 +1,10 @@ +import QtQuick + +Item { + PluginQuickAnchorsBase { + anchors.horizontalCenter: undefined + anchors.verticalCenter: undefined + anchors.baseline: undefined + Component.onCompleted: anchors.bottom = undefined + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_attached.qml b/tests/auto/qml/qmllint/data/pluginQuick_attached.qml new file mode 100644 index 0000000000..c5f4e0d552 --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_attached.qml @@ -0,0 +1,27 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +Item { + QtObject { + // QtQuick + Accessible.name: "Foo" + LayoutMirroring.enabled: true + EnterKey.type: Qt.EnterKeyGo + + // QtQuick.Layouts + Layout.minimumHeight: 3 + property bool stackLayout: StackLayout.isCurrentItem // Read-only + + // QtQuick.Templates + ScrollBar.vertical: ScrollBar {} + ScrollIndicator.vertical: ScrollIndicator {} + SplitView.fillWidth: true + StackView.visible: true + property int swipeView: SwipeView.index // Read-only + TextArea.flickable: TextArea {} + ToolTip.delay: 50 + property bool tumbler: Tumbler.displacement // Read-only + property bool swipeDelegate: SwipeDelegate.pressed // Read-only + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_attachedClean.qml b/tests/auto/qml/qmllint/data/pluginQuick_attachedClean.qml new file mode 100644 index 0000000000..5114628428 --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_attachedClean.qml @@ -0,0 +1,31 @@ +import QtQuick +import QtQuick.Layouts +import QtQuick.Controls + +Item { + // QtQuick + Accessible.name: "Foo" + LayoutMirroring.enabled: true + EnterKey.type: Qt.EnterKeyGo + + //QtQuick.Layouts + Layout.minimumHeight: 3 + property bool stackLayout: StackLayout.isCurrentItem // Read-only + + // QtQuick.Templates + SplitView.fillWidth: true + StackView.visible: true + property int swipeView: SwipeView.index // Read only, enforceable but complicated + Flickable { + TextArea.flickable: TextArea {} + ScrollIndicator.vertical: ScrollIndicator {} + ScrollBar.vertical: ScrollBar {} + } + ToolTip.delay: 50 + TableView { + delegate: Item { + property bool tumbler: Tumbler.displacement // Read only, enforceable but complicated + } + } + property bool swipeDelegate: SwipeDelegate.pressed // Read only +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_attachedIgnore.qml b/tests/auto/qml/qmllint/data/pluginQuick_attachedIgnore.qml new file mode 100644 index 0000000000..28612a129a --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_attachedIgnore.qml @@ -0,0 +1,15 @@ +import QtQuick +import QtQuick.Controls + +Item { + id: delegate + property bool tumbler: Tumbler.displacement // Read-only + QtObject { + property bool tumbler2: delegate.Tumbler.displacement + } + QtObject { + Component.onCompleted: { + delegate.Accessible.name = "Foo" + } + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_layoutChildren.qml b/tests/auto/qml/qmllint/data/pluginQuick_layoutChildren.qml new file mode 100644 index 0000000000..5a70b05d79 --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_layoutChildren.qml @@ -0,0 +1,29 @@ +import QtQuick +import QtQuick.Layouts + +Item { + RowLayout { + Item { + anchors.fill: parent + x: 10 + y: 20 + width: 100 + height: 200 + } + } + + Grid { + Item { + anchors.fill: parent + x: 10 + y: 20 + } + } + + Flow { + Item { anchors.fill: parent; + x: 10 + y: 20 + } + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_noCrashOnUneresolved.qml b/tests/auto/qml/qmllint/data/pluginQuick_noCrashOnUneresolved.qml new file mode 100644 index 0000000000..7e04394350 --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_noCrashOnUneresolved.qml @@ -0,0 +1,10 @@ +import QtQuick.Controls + +Item { + + Tumbler { + + contentItem: Item { + } + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_propertyChangesInvalidTarget.qml b/tests/auto/qml/qmllint/data/pluginQuick_propertyChangesInvalidTarget.qml new file mode 100644 index 0000000000..fa7d4ef1ac --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_propertyChangesInvalidTarget.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +Rectangle { + State { + name: "test" + PropertyChanges { target: root; color: "blue" } + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_propertyChangesParsed.qml b/tests/auto/qml/qmllint/data/pluginQuick_propertyChangesParsed.qml new file mode 100644 index 0000000000..94873463f1 --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_propertyChangesParsed.qml @@ -0,0 +1,19 @@ +import QtQuick + +Window { + Item { + id: foo + property color myColor: 'black' + + states: [ + State { + PropertyChanges { + target: foo + myColor: Qt.rgba(0.5, 0.5, 0.5, 0.16) + notThere: "a" + } + } + ] + + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_swipeDelegate.qml b/tests/auto/qml/qmllint/data/pluginQuick_swipeDelegate.qml new file mode 100644 index 0000000000..a6c3b2c743 --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_swipeDelegate.qml @@ -0,0 +1,19 @@ +import QtQuick.Controls +import QtQuick + +Item { + SwipeDelegate { + contentItem: Item { anchors.left: parent.left } + background: Item { anchors.right: parent.right } + + swipe.left: Item {} + swipe.behind: Item {} + } + SwipeDelegate { + contentItem: Item { anchors.centerIn: parent } + background: Item { anchors.fill: parent } + + swipe.right: Item {} + swipe.behind: Item {} + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_varProp.qml b/tests/auto/qml/qmllint/data/pluginQuick_varProp.qml new file mode 100644 index 0000000000..17b5d99d6b --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_varProp.qml @@ -0,0 +1,16 @@ +import QtQuick +import QtQuick.Controls + +Item { + SpinBox { + textFromValue: null + valueFromText: { return 6; } + } + TableView { + columnWidthProvider: null + rowHeightProvider: { return 3; } + } + Tumbler { + contentItem: Item {} + } +} diff --git a/tests/auto/qml/qmllint/data/pluginQuick_varPropClean.qml b/tests/auto/qml/qmllint/data/pluginQuick_varPropClean.qml new file mode 100644 index 0000000000..b17f7e6dd7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/pluginQuick_varPropClean.qml @@ -0,0 +1,16 @@ +import QtQuick +import QtQuick.Controls + +Item { + SpinBox { + textFromValue: function(value, locale) { return Number(value).toLocaleString(locale, 'f', 0); } + valueFromText: function(text, locale) { return Number.fromLocaleString(locale, text); } + } + TableView { + columnWidthProvider: function(column) { return column*50; } + rowHeightProvider: function(row) { return row*3; } + } + Tumbler { + contentItem: PathView {} + } +} diff --git a/tests/auto/qml/qmllint/data/pragmaStrict.qml b/tests/auto/qml/qmllint/data/pragmaStrict.qml new file mode 100644 index 0000000000..d50fe9b717 --- /dev/null +++ b/tests/auto/qml/qmllint/data/pragmaStrict.qml @@ -0,0 +1,7 @@ +pragma Strict + +import QtQml + +QtObject { + function add(a, b) { return a + b; } +} diff --git a/tests/auto/qml/qmllint/data/prefixedAttachedProperty.qml b/tests/auto/qml/qmllint/data/prefixedAttachedProperty.qml new file mode 100644 index 0000000000..1f9634e280 --- /dev/null +++ b/tests/auto/qml/qmllint/data/prefixedAttachedProperty.qml @@ -0,0 +1,5 @@ +import QtQuick as T + +T.Item { + T.Accessible.name: "Example" +} diff --git a/tests/auto/qml/qmllint/data/propertyBindingValue.qml b/tests/auto/qml/qmllint/data/propertyBindingValue.qml new file mode 100644 index 0000000000..eb461e8fdd --- /dev/null +++ b/tests/auto/qml/qmllint/data/propertyBindingValue.qml @@ -0,0 +1,3 @@ +PropertyBase2 { + property int bar: foo.bar +} diff --git a/tests/auto/qml/qmllint/data/propertyDelegate.qml b/tests/auto/qml/qmllint/data/propertyDelegate.qml new file mode 100644 index 0000000000..aa4d2c35c8 --- /dev/null +++ b/tests/auto/qml/qmllint/data/propertyDelegate.qml @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Repeater { + delegate: Item {} +} diff --git a/tests/auto/qml/qmllint/data/propertyOverride.qml b/tests/auto/qml/qmllint/data/propertyOverride.qml new file mode 100644 index 0000000000..04c28485bb --- /dev/null +++ b/tests/auto/qml/qmllint/data/propertyOverride.qml @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +PropertyBase2 { + foo: Item {} +} diff --git a/tests/auto/qml/qmllint/data/propertypass_pluginTest.qml b/tests/auto/qml/qmllint/data/propertypass_pluginTest.qml new file mode 100644 index 0000000000..728b014b85 --- /dev/null +++ b/tests/auto/qml/qmllint/data/propertypass_pluginTest.qml @@ -0,0 +1,24 @@ +import QtQuick 2.0 + +Item { + Text { + id: foo + text: "Foo" // Specific property we're targeting in one element + x: 5 // Property we're targeting regardless of type + y: x + 5 // Property used in a binding + font.bold: true // Not targeted + } + x: 5 // Property we're targeting regardless of type + + ListModel { id: listModel } + + ListView { // Entire type covered + model: listModel + height: 50 + } + + Component.onCompleted: { + console.log(foo.x); // Reading property from another component + foo.x = 30; // Writing property from another component + } +} diff --git a/tests/auto/qml/qmllint/data/qEventPoint.qml b/tests/auto/qml/qmllint/data/qEventPoint.qml new file mode 100644 index 0000000000..086e710b48 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qEventPoint.qml @@ -0,0 +1,9 @@ +import QtQuick + +TapHandler { + acceptedButtons: Qt.LeftButton | Qt.RightButton + onSingleTapped: (eventPoint, button) => { + console.log("Single tap at", eventPoint, "with button", button) + } + onTapped: console.log("tapped") +} diff --git a/tests/auto/qml/qmllint/data/qjsroot.qml b/tests/auto/qml/qmllint/data/qjsroot.qml new file mode 100644 index 0000000000..c5995b9576 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qjsroot.qml @@ -0,0 +1,20 @@ +import QtQuick + +QtObject { + property var locale: Qt.locale() + property date currentDate: new Date() + property RegularExpressionValidator validator: RegularExpressionValidator { regularExpression: /20([0-9]+)/ }; + property double pi: 3.14 + + // Test date + property string dateString: currentDate.toLocaleDateString(); + + // Test string + property int dateStringDotIndex: dateString.indexOf(".") + + // Test regularExpression + property var dateStringReplace: validator.regularExpression.exec(dateString) + + // Test double + property string fixedPi: pi.toFixed(1) +} diff --git a/tests/auto/qml/qmllint/data/qmlRootMethods.qml b/tests/auto/qml/qmllint/data/qmlRootMethods.qml new file mode 100644 index 0000000000..5541de3a32 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qmlRootMethods.qml @@ -0,0 +1,12 @@ +import QtQml + +QtObject { + id: self + + objectName: self.toString() + + Component.onCompleted: { + self.destroy(); + self.destroy(25); + } +} diff --git a/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml b/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml index 4847fc9196..ad88f1c58c 100644 --- a/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml +++ b/tests/auto/qml/qmllint/data/qmldirAndQmltypes.qml @@ -2,5 +2,5 @@ import Things 1.0 Something { property var a: SomethingEntirelyStrange {} - property var b: SomethingEntirelyStrange.AAA + property var b: SomethingEntirelyStrange.AnEnum.AAA } diff --git a/tests/auto/qml/qmllint/data/qmldirImport/QtObjectWithDefaultProperty.qml b/tests/auto/qml/qmllint/data/qmldirImport/QtObjectWithDefaultProperty.qml new file mode 100644 index 0000000000..d33d0b5c94 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qmldirImport/QtObjectWithDefaultProperty.qml @@ -0,0 +1,4 @@ +import DuplicateImport // imports QtQml +QtObject { + default property QtObject child +} diff --git a/tests/auto/qml/qmllint/data/qmldirImport/duplicate.qml b/tests/auto/qml/qmllint/data/qmldirImport/duplicate.qml new file mode 100644 index 0000000000..22f454ad44 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qmldirImport/duplicate.qml @@ -0,0 +1,7 @@ +import DuplicateImport // imports QtQml directly and indirectly via QtQuick + +QtObjectWithDefaultProperty { // for default property + ItemDerived { // item derived has compatible QtObject type + x: 4 + } +} diff --git a/tests/auto/qml/qmllint/data/qmldirImportAndDepend/QtObjectWithDefaultProperty.qml b/tests/auto/qml/qmllint/data/qmldirImportAndDepend/QtObjectWithDefaultProperty.qml new file mode 100644 index 0000000000..fb856d0b29 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qmldirImportAndDepend/QtObjectWithDefaultProperty.qml @@ -0,0 +1,4 @@ +import Things // imports QtQml +QtObject { + default property QtObject child +} diff --git a/tests/auto/qml/qmllint/data/qmldirImportAndDepend/good.qml b/tests/auto/qml/qmllint/data/qmldirImportAndDepend/good.qml index 275b531845..987301ef76 100644 --- a/tests/auto/qml/qmllint/data/qmldirImportAndDepend/good.qml +++ b/tests/auto/qml/qmllint/data/qmldirImportAndDepend/good.qml @@ -1,6 +1,6 @@ import Things -QtObject { +QtObjectWithDefaultProperty { // for default property objectName: "QtQml was imported from Things/qmldir" ItemDerived { diff --git a/tests/auto/qml/qmllint/data/qmodelIndex.qml b/tests/auto/qml/qmllint/data/qmodelIndex.qml new file mode 100644 index 0000000000..e0df84b68b --- /dev/null +++ b/tests/auto/qml/qmllint/data/qmodelIndex.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + property ItemSelectionModel itemSelectionModel; + function row() { return itemSelectionModel.currentIndex.row; } +} diff --git a/tests/auto/qml/qmllint/data/qobjectHasOwnProperty.qml b/tests/auto/qml/qmllint/data/qobjectHasOwnProperty.qml new file mode 100644 index 0000000000..b985c1354f --- /dev/null +++ b/tests/auto/qml/qmllint/data/qobjectHasOwnProperty.qml @@ -0,0 +1,7 @@ +import QtQml + +QtObject { + id: root + + property bool hasFooProperty: root.hasOwnProperty('foo') +} diff --git a/tests/auto/qml/qmllint/data/qtquickWindow20.qml b/tests/auto/qml/qmllint/data/qtquickWindow20.qml new file mode 100644 index 0000000000..3019e3037b --- /dev/null +++ b/tests/auto/qml/qmllint/data/qtquickWindow20.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property var win: Window.window +} diff --git a/tests/auto/qml/qmllint/data/qtquickWindow21.qml b/tests/auto/qml/qmllint/data/qtquickWindow21.qml new file mode 100644 index 0000000000..7047436da2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qtquickWindow21.qml @@ -0,0 +1,5 @@ +import QtQuick 2.1 + +QtObject { + property var win: Window.window +} diff --git a/tests/auto/qml/qmllint/data/qtquickdialog.qml b/tests/auto/qml/qmllint/data/qtquickdialog.qml new file mode 100644 index 0000000000..4579719d06 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qtquickdialog.qml @@ -0,0 +1,5 @@ +import QtQuick.Dialogs + +MessageDialog { + buttons:MessageDialog.Ok + } diff --git a/tests/auto/qml/qmllint/data/qvariant.qml b/tests/auto/qml/qmllint/data/qvariant.qml new file mode 100644 index 0000000000..a9a2978876 --- /dev/null +++ b/tests/auto/qml/qmllint/data/qvariant.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property int len: Qt.color().length +} diff --git a/tests/auto/qml/qmllint/data/relPathQrc/Bar/Thing2.qml b/tests/auto/qml/qmllint/data/relPathQrc/Bar/Thing2.qml new file mode 100644 index 0000000000..3052615aef --- /dev/null +++ b/tests/auto/qml/qmllint/data/relPathQrc/Bar/Thing2.qml @@ -0,0 +1,3 @@ +import QtQuick + +Item {} diff --git a/tests/auto/qml/qmllint/data/relPathQrc/Foo/Thing.qml b/tests/auto/qml/qmllint/data/relPathQrc/Foo/Thing.qml new file mode 100644 index 0000000000..f89ee92e3e --- /dev/null +++ b/tests/auto/qml/qmllint/data/relPathQrc/Foo/Thing.qml @@ -0,0 +1,3 @@ +import "../Bar" as Bar + +Bar.Thing2 {} diff --git a/tests/auto/qml/qmllint/data/relPathQrc/resources.qrc b/tests/auto/qml/qmllint/data/relPathQrc/resources.qrc new file mode 100644 index 0000000000..42cab37c29 --- /dev/null +++ b/tests/auto/qml/qmllint/data/relPathQrc/resources.qrc @@ -0,0 +1,7 @@ +<RCC> + <qresource prefix="/fooBar/"> + <file alias="Foo/Thing1.qml">Foo/Thing.qml</file> + <file alias="Bar/Thing2.qml">Bar/Thing2.qml</file> + </qresource> +</RCC> + diff --git a/tests/auto/qml/qmllint/data/requiredProperty.qml b/tests/auto/qml/qmllint/data/requiredProperty.qml index b10f0f67cd..f1e82bb402 100644 --- a/tests/auto/qml/qmllint/data/requiredProperty.qml +++ b/tests/auto/qml/qmllint/data/requiredProperty.qml @@ -1,6 +1,9 @@ -import QtQml 2.15 +import QtQuick 2.15 -QtObject { - property int x - required x +Item { + component Required : QtObject { + property int x + required x + } + Required { x: 5 } } diff --git a/tests/auto/qml/qmllint/data/requiredPropertyBindings.qml b/tests/auto/qml/qmllint/data/requiredPropertyBindings.qml new file mode 100644 index 0000000000..3bba84f412 --- /dev/null +++ b/tests/auto/qml/qmllint/data/requiredPropertyBindings.qml @@ -0,0 +1,24 @@ +import QtQuick 2.0 + +Item { + component Base : Item { + required property string required_now_string + property string required_later_string + + required property QtObject required_now_object + property QtObject required_later_object + } + + component Derived : Base { + required required_later_string + required required_later_object + } + + Derived { + required_now_string: "" + required_later_string: "" + + required_now_object: QtObject {} + required_later_object: QtObject {} + } +} diff --git a/tests/auto/qml/qmllint/data/requiredPropertyBindingsLater.qml b/tests/auto/qml/qmllint/data/requiredPropertyBindingsLater.qml new file mode 100644 index 0000000000..65c59d7161 --- /dev/null +++ b/tests/auto/qml/qmllint/data/requiredPropertyBindingsLater.qml @@ -0,0 +1,18 @@ +import QtQuick 2.0 + +Item { + component Base : Item { + required property string required_now_string + property string required_later_string + property string required_even_later_string + } + + component Derived : Base { + required required_later_string + } + + Derived { + required required_even_later_string + required_now_string: "" + } +} diff --git a/tests/auto/qml/qmllint/data/requiredPropertyBindingsNow.qml b/tests/auto/qml/qmllint/data/requiredPropertyBindingsNow.qml new file mode 100644 index 0000000000..701760b4e7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/requiredPropertyBindingsNow.qml @@ -0,0 +1,17 @@ +import QtQuick 2.0 + +Item { + component Base : Item { + required property string required_now_string + property string required_later_string + } + + component Derived : Base { + required required_later_string + } + + Derived { + required property string required_defined_here_string + required_later_string: "" + } +} diff --git a/tests/auto/qml/qmllint/data/requiredPropertyInComponent.qml b/tests/auto/qml/qmllint/data/requiredPropertyInComponent.qml new file mode 100644 index 0000000000..24ecf9d706 --- /dev/null +++ b/tests/auto/qml/qmllint/data/requiredPropertyInComponent.qml @@ -0,0 +1,25 @@ +import QtQuick 2.0 + +Row { + // explicit component + Component { + id: foo + Item { + required property int i + } + } + + // implicit component, plain property + property Component com: Item {} + + Repeater { + model: 3 + // implicit component, default property + Text { + required property int index + height: 40 + color: "black" + text: "I'm item " + index + } + } +} diff --git a/tests/auto/qml/qmllint/data/returnTypeAnnotation_component.qml b/tests/auto/qml/qmllint/data/returnTypeAnnotation_component.qml new file mode 100644 index 0000000000..de142337b4 --- /dev/null +++ b/tests/auto/qml/qmllint/data/returnTypeAnnotation_component.qml @@ -0,0 +1,9 @@ +import QtQml +import QtQuick + +QtObject { + id: root + component Comp : Item { } + property Comp c: Comp{ } + function comp() { return root.c } +} diff --git a/tests/auto/qml/qmllint/data/returnTypeAnnotation_enum.qml b/tests/auto/qml/qmllint/data/returnTypeAnnotation_enum.qml new file mode 100644 index 0000000000..0585ceceb2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/returnTypeAnnotation_enum.qml @@ -0,0 +1,5 @@ +import QtQuick + +QtObject { + function enumeration() { return Text.AlignRight } +} diff --git a/tests/auto/qml/qmllint/data/returnTypeAnnotation_method.qml b/tests/auto/qml/qmllint/data/returnTypeAnnotation_method.qml new file mode 100644 index 0000000000..dc03311e73 --- /dev/null +++ b/tests/auto/qml/qmllint/data/returnTypeAnnotation_method.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + function f() { } + function method() { return f } +} diff --git a/tests/auto/qml/qmllint/data/returnTypeAnnotation_property.qml b/tests/auto/qml/qmllint/data/returnTypeAnnotation_property.qml new file mode 100644 index 0000000000..bb79978d85 --- /dev/null +++ b/tests/auto/qml/qmllint/data/returnTypeAnnotation_property.qml @@ -0,0 +1,7 @@ +import QtQml + +QtObject { + id: root + property int i: 1 + function prop() { return root.i } +} diff --git a/tests/auto/qml/qmllint/data/returnTypeAnnotation_type.qml b/tests/auto/qml/qmllint/data/returnTypeAnnotation_type.qml new file mode 100644 index 0000000000..78f02a8b67 --- /dev/null +++ b/tests/auto/qml/qmllint/data/returnTypeAnnotation_type.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + function type() { return 1 + 1 } +} diff --git a/tests/auto/qml/qmllint/data/scriptInTemplate.qml b/tests/auto/qml/qmllint/data/scriptInTemplate.qml new file mode 100644 index 0000000000..ba333dcd3e --- /dev/null +++ b/tests/auto/qml/qmllint/data/scriptInTemplate.qml @@ -0,0 +1,6 @@ +import QtQml +import scripts + +QtObject { + objectName: `Result: ${Foo.getText()}` +} diff --git a/tests/auto/qml/qmllint/data/scripts/Foo.js b/tests/auto/qml/qmllint/data/scripts/Foo.js new file mode 100644 index 0000000000..1d5106f733 --- /dev/null +++ b/tests/auto/qml/qmllint/data/scripts/Foo.js @@ -0,0 +1,6 @@ +.pragma library + +function getText() { + return "whohoooooo" +} + diff --git a/tests/auto/qml/qmllint/data/scripts/qmldir b/tests/auto/qml/qmllint/data/scripts/qmldir new file mode 100644 index 0000000000..b4bf844348 --- /dev/null +++ b/tests/auto/qml/qmllint/data/scripts/qmldir @@ -0,0 +1,4 @@ +module scripts +typeinfo scripts.qmltypes +Foo 1.0 Foo.js + diff --git a/tests/auto/qml/qmllint/data/scripts/scripts.qmltypes b/tests/auto/qml/qmllint/data/scripts/scripts.qmltypes new file mode 100644 index 0000000000..ebbfc41eb2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/scripts/scripts.qmltypes @@ -0,0 +1,22 @@ +import QtQuick.tooling 1.2 + +// This file describes the plugin-supplied types contained in the library. +// It is used for QML tooling purposes only. +// +// This file was auto-generated by qmltyperegistrar. + +Module { + Component { + file: "value.h" + name: "ValueType" + accessSemantics: "value" + exports: ["scripts/vvv 1.0"] + exportMetaObjectRevisions: [256] + Method { + name: "ValueType" + isConstructor: true + Parameter { name: "v"; type: "QString" } + } + Method { name: "ValueType"; isCloned: true; isConstructor: true } + } +} diff --git a/tests/auto/qml/qmllint/data/scriptstring.qml b/tests/auto/qml/qmllint/data/scriptstring.qml new file mode 100644 index 0000000000..733434e924 --- /dev/null +++ b/tests/auto/qml/qmllint/data/scriptstring.qml @@ -0,0 +1,73 @@ +import QtQuick + +Window { + id: root + + Rectangle { + id: main + + MouseArea { + id: mouse + property int clickCount: 0 + onClicked: { + clickCount++ + + switch ( clickCount % 3 ) { + case 1 : + main.state = "middleState" + break + case 2 : + main.state = "rightState" + break + default : + main.state = "leftState" + } + } + } + + Rectangle { + id: mover + anchors { + left: undefined + right: undefined + horizontalCenter: undefined + top: main.top + bottom: main.bottom + } + } + + states: [ + State { + name: "leftState" + AnchorChanges { + target: mover + anchors.left: main.left + anchors.right: undefined + anchors.horizontalCenter: undefined + } + }, + State { + name: "middleState" + AnchorChanges { + target: mover + anchors { + left: undefined + right: undefined + horizontalCenter: main.horizontalCenter + } + } + }, + State { + name: "rightState" + AnchorChanges { + target: mover + anchors { + left: undefined + right: main.right + horizontalCenter: undefined + } + } + } + ] + } +} diff --git a/tests/auto/qml/qmllint/data/settings/bare/.qmllint.ini b/tests/auto/qml/qmllint/data/settings/bare/.qmllint.ini new file mode 100644 index 0000000000..2dc9ff658c --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/bare/.qmllint.ini @@ -0,0 +1,2 @@ +[General] +DisableDefaultImports=true diff --git a/tests/auto/qml/qmllint/data/settings/bare/bare.qml b/tests/auto/qml/qmllint/data/settings/bare/bare.qml new file mode 100644 index 0000000000..852b8339b9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/bare/bare.qml @@ -0,0 +1,3 @@ +import QtQuick // Should fail because Bare is specified with no import + +Item {} diff --git a/tests/auto/qml/qmllint/data/settings/plugin/.qmllint.ini b/tests/auto/qml/qmllint/data/settings/plugin/.qmllint.ini new file mode 100644 index 0000000000..a72e0e29e2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/plugin/.qmllint.ini @@ -0,0 +1,2 @@ +[Warnings] +TestWarning=disable diff --git a/tests/auto/qml/qmllint/data/settings/plugin/elemenpass_pluginSettingTest.qml b/tests/auto/qml/qmllint/data/settings/plugin/elemenpass_pluginSettingTest.qml new file mode 100644 index 0000000000..b9250a2d11 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/plugin/elemenpass_pluginSettingTest.qml @@ -0,0 +1,7 @@ +import QtQuick + +Item { + Rectangle { + radius: 5 + } +} diff --git a/tests/auto/qml/qmllint/data/settings/qmlimports/.qmllint.ini b/tests/auto/qml/qmllint/data/settings/qmlimports/.qmllint.ini new file mode 100644 index 0000000000..c2f9d81743 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmlimports/.qmllint.ini @@ -0,0 +1,2 @@ +[General] +AdditionalQmlImportPaths=subdir diff --git a/tests/auto/qml/qmllint/data/settings/qmlimports/qmlimports.qml b/tests/auto/qml/qmllint/data/settings/qmlimports/qmlimports.qml new file mode 100644 index 0000000000..221ddff254 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmlimports/qmlimports.qml @@ -0,0 +1,3 @@ +import Custom + +Thing {} diff --git a/tests/auto/qml/qmllint/data/settings/qmlimports/subdir/Custom/custom.qmltypes b/tests/auto/qml/qmllint/data/settings/qmlimports/subdir/Custom/custom.qmltypes new file mode 100644 index 0000000000..b3839652dc --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmlimports/subdir/Custom/custom.qmltypes @@ -0,0 +1,11 @@ +import QtQuick.tooling 1.2 +Module { + dependencies: [] + Component { + name: "Thing" + prototype: "QObject" + exports: [ + "Custom/Thing 1.0", + ] + } +} diff --git a/tests/auto/qml/qmllint/data/settings/qmlimports/subdir/Custom/qmldir b/tests/auto/qml/qmllint/data/settings/qmlimports/subdir/Custom/qmldir new file mode 100644 index 0000000000..6ad407fd38 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmlimports/subdir/Custom/qmldir @@ -0,0 +1,2 @@ +module Custom +typeinfo custom.qmltypes diff --git a/tests/auto/qml/qmllint/data/settings/qmltypes/.qmllint.ini b/tests/auto/qml/qmllint/data/settings/qmltypes/.qmllint.ini new file mode 100644 index 0000000000..3dc2c8fd1b --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmltypes/.qmllint.ini @@ -0,0 +1,3 @@ +[General] +OverwriteImportTypes=subdir/custom.qmltypes + diff --git a/tests/auto/qml/qmllint/data/settings/qmltypes/qmltypes.qml b/tests/auto/qml/qmllint/data/settings/qmltypes/qmltypes.qml new file mode 100644 index 0000000000..221ddff254 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmltypes/qmltypes.qml @@ -0,0 +1,3 @@ +import Custom + +Thing {} diff --git a/tests/auto/qml/qmllint/data/settings/qmltypes/subdir/custom.qmltypes b/tests/auto/qml/qmllint/data/settings/qmltypes/subdir/custom.qmltypes new file mode 100644 index 0000000000..b3839652dc --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/qmltypes/subdir/custom.qmltypes @@ -0,0 +1,11 @@ +import QtQuick.tooling 1.2 +Module { + dependencies: [] + Component { + name: "Thing" + prototype: "QObject" + exports: [ + "Custom/Thing 1.0", + ] + } +} diff --git a/tests/auto/qml/qmllint/data/settings/unqualifiedSilent/.qmllint.ini b/tests/auto/qml/qmllint/data/settings/unqualifiedSilent/.qmllint.ini new file mode 100644 index 0000000000..92c03b2490 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/unqualifiedSilent/.qmllint.ini @@ -0,0 +1,2 @@ +[Warnings] +UnqualifiedAccess=disable diff --git a/tests/auto/qml/qmllint/data/settings/unqualifiedSilent/unqualified.qml b/tests/auto/qml/qmllint/data/settings/unqualifiedSilent/unqualified.qml new file mode 100644 index 0000000000..5a68b757a9 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/unqualifiedSilent/unqualified.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property int foo: root.x +} diff --git a/tests/auto/qml/qmllint/data/settings/unusedImportWarning/.qmllint.ini b/tests/auto/qml/qmllint/data/settings/unusedImportWarning/.qmllint.ini new file mode 100644 index 0000000000..c012a1fc28 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/unusedImportWarning/.qmllint.ini @@ -0,0 +1,2 @@ +[Warnings] +UnusedImports=warning diff --git a/tests/auto/qml/qmllint/data/settings/unusedImportWarning/unused.qml b/tests/auto/qml/qmllint/data/settings/unusedImportWarning/unused.qml new file mode 100644 index 0000000000..715ebf29d7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/settings/unusedImportWarning/unused.qml @@ -0,0 +1,5 @@ +import QtQml +import QtQml.Models + +QtObject { +} diff --git a/tests/auto/qml/qmllint/data/shadowable.qml b/tests/auto/qml/qmllint/data/shadowable.qml new file mode 100644 index 0000000000..d9c5f78016 --- /dev/null +++ b/tests/auto/qml/qmllint/data/shadowable.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + property NotSoSimple a: NotSoSimple {} + property int b: a.complicated +} diff --git a/tests/auto/qml/qmllint/data/shadowedMethod.qml b/tests/auto/qml/qmllint/data/shadowedMethod.qml new file mode 100644 index 0000000000..72f18aaec7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/shadowedMethod.qml @@ -0,0 +1,8 @@ +import QtQuick + +QtObject { + function foo() {} + property bool foo: false + + Component.onCompleted: foo() +} diff --git a/tests/auto/qml/qmllint/data/shadowedSignal.qml b/tests/auto/qml/qmllint/data/shadowedSignal.qml new file mode 100644 index 0000000000..e4bb003495 --- /dev/null +++ b/tests/auto/qml/qmllint/data/shadowedSignal.qml @@ -0,0 +1,6 @@ +import QtQuick + +MouseArea { + id: mouseArea + Component.onCompleted: pressed() +} diff --git a/tests/auto/qml/qmllint/data/shadowedSignalWithId.qml b/tests/auto/qml/qmllint/data/shadowedSignalWithId.qml new file mode 100644 index 0000000000..ed7cc9f6c4 --- /dev/null +++ b/tests/auto/qml/qmllint/data/shadowedSignalWithId.qml @@ -0,0 +1,6 @@ +import QtQuick + +MouseArea { + id: mouseArea + Component.onCompleted: mouseArea.pressed() +} diff --git a/tests/auto/qml/qmllint/data/shadowedSlot.qml b/tests/auto/qml/qmllint/data/shadowedSlot.qml new file mode 100644 index 0000000000..cb09645746 --- /dev/null +++ b/tests/auto/qml/qmllint/data/shadowedSlot.qml @@ -0,0 +1,6 @@ +import QtQml + +ObjectModel { + property bool move: false + Component.onCompleted: move() +} diff --git a/tests/auto/qml/qmllint/data/storeNameMethod.qml b/tests/auto/qml/qmllint/data/storeNameMethod.qml new file mode 100644 index 0000000000..fca02b288f --- /dev/null +++ b/tests/auto/qml/qmllint/data/storeNameMethod.qml @@ -0,0 +1,12 @@ +import QtQuick 2.15 +import QtQuick.Window 2.15 + +Window { + Rectangle { + + Timer { + function foo() {} + onTriggered: foo = 1 + } + } +} diff --git a/tests/auto/qml/qmllint/data/stringAsId.qml b/tests/auto/qml/qmllint/data/stringAsId.qml new file mode 100644 index 0000000000..58ea28cb17 --- /dev/null +++ b/tests/auto/qml/qmllint/data/stringAsId.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + id: "aString" +} diff --git a/tests/auto/qml/qmllint/data/stringIdUsedInWarning.qml b/tests/auto/qml/qmllint/data/stringIdUsedInWarning.qml new file mode 100644 index 0000000000..672c00f39b --- /dev/null +++ b/tests/auto/qml/qmllint/data/stringIdUsedInWarning.qml @@ -0,0 +1,9 @@ +import QtQml + +QtObject { + id: "stringy" + property int i + property QtObject o: QtObject { + Component.onCompleted: console.log(i) + } +} diff --git a/tests/auto/qml/qmllint/data/stringLength.qml b/tests/auto/qml/qmllint/data/stringLength.qml new file mode 100644 index 0000000000..354fed7b22 --- /dev/null +++ b/tests/auto/qml/qmllint/data/stringLength.qml @@ -0,0 +1,9 @@ +import QtQuick 2.15 + +TextInput { + id: textInput + + Component.onCompleted: { + console.log("text.length", textInput.text.length); + } +} diff --git a/tests/auto/qml/qmllint/data/stringLength2.qml b/tests/auto/qml/qmllint/data/stringLength2.qml new file mode 100644 index 0000000000..6dc2942b37 --- /dev/null +++ b/tests/auto/qml/qmllint/data/stringLength2.qml @@ -0,0 +1,10 @@ +import QtQuick 2.15 + +Item { + id: foo + + property string s + Component.onCompleted: { + console.log("s.length", foo.s.length); + } +} diff --git a/tests/auto/qml/qmllint/data/stringLength3.qml b/tests/auto/qml/qmllint/data/stringLength3.qml new file mode 100644 index 0000000000..292a163145 --- /dev/null +++ b/tests/auto/qml/qmllint/data/stringLength3.qml @@ -0,0 +1,8 @@ +import QtQuick 2.11 +import QtQuick.Window 2.3 + +Item { + InfoItemTextEdit { + textStrColor: valueStr.length === 0 ? "#f5a71e" : "#f5a715" + } +} diff --git a/tests/auto/qml/qmllint/data/stringToByteArray.qml b/tests/auto/qml/qmllint/data/stringToByteArray.qml new file mode 100644 index 0000000000..b36da28f0d --- /dev/null +++ b/tests/auto/qml/qmllint/data/stringToByteArray.qml @@ -0,0 +1,7 @@ +import QtQuick + +Item { + objectName: layer.samplerName + layer.samplerName: "source" +} + diff --git a/tests/auto/qml/qmllint/data/stringToDateTime.qml b/tests/auto/qml/qmllint/data/stringToDateTime.qml new file mode 100644 index 0000000000..dc4bd6cda5 --- /dev/null +++ b/tests/auto/qml/qmllint/data/stringToDateTime.qml @@ -0,0 +1,7 @@ +import StringToDateTime + +StringToDateTime { + aDate: "2023-03-29" + aTime: "15:10:41" + aDateTime: "2023-03-29 15:10:41" +} diff --git a/tests/auto/qml/qmllint/data/switcher.qml b/tests/auto/qml/qmllint/data/switcher.qml new file mode 100644 index 0000000000..260b00fb84 --- /dev/null +++ b/tests/auto/qml/qmllint/data/switcher.qml @@ -0,0 +1,5 @@ +import QML + +Switch { + onLabel: qsTr("Power on") +} diff --git a/tests/auto/qml/qmllint/data/templateStringSubstitution.qml b/tests/auto/qml/qmllint/data/templateStringSubstitution.qml new file mode 100644 index 0000000000..64d6e0158d --- /dev/null +++ b/tests/auto/qml/qmllint/data/templateStringSubstitution.qml @@ -0,0 +1,6 @@ +import QtQml + +QtObject { + property int i + property int j: `hallo ${i}` +} diff --git a/tests/auto/qml/qmllint/data/tooFewParams.qml b/tests/auto/qml/qmllint/data/tooFewParams.qml new file mode 100644 index 0000000000..15e1bb0616 --- /dev/null +++ b/tests/auto/qml/qmllint/data/tooFewParams.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property var a: Qt.hsla(12) +} diff --git a/tests/auto/qml/qmllint/data/typePropertyAccess.qml b/tests/auto/qml/qmllint/data/typePropertyAccess.qml new file mode 100644 index 0000000000..80913806f7 --- /dev/null +++ b/tests/auto/qml/qmllint/data/typePropertyAccess.qml @@ -0,0 +1,6 @@ +import QtQml +import QmlBench + +QtObject { + property real x: Locals.realProp +} diff --git a/tests/auto/qml/qmllint/data/unaryMinusToStringProperty.qml b/tests/auto/qml/qmllint/data/unaryMinusToStringProperty.qml new file mode 100644 index 0000000000..c1c51fa796 --- /dev/null +++ b/tests/auto/qml/qmllint/data/unaryMinusToStringProperty.qml @@ -0,0 +1,5 @@ +import QtQml + +QtObject { + property string i: -1 +} diff --git a/tests/auto/qml/qmllint/data/unboundComponents.qml b/tests/auto/qml/qmllint/data/unboundComponents.qml new file mode 100644 index 0000000000..f4ce8c6f5d --- /dev/null +++ b/tests/auto/qml/qmllint/data/unboundComponents.qml @@ -0,0 +1,22 @@ +pragma ComponentBehavior: Unbound +import QtQml + +QtObject { + id: root + property string foo: "bar" + property Component c1: Component { + QtObject { + id: c1 + objectName: root.foo + property int i: 12 + property Component c2: Component { + QtObject { + objectName: root.foo + c1.i + } + } + property QtObject o: c2.createObject() + } + } + + property QtObject o: c1.createObject() +} diff --git a/tests/auto/qml/qmllint/data/unexportedCppBase.qml b/tests/auto/qml/qmllint/data/unexportedCppBase.qml new file mode 100644 index 0000000000..c8530fd865 --- /dev/null +++ b/tests/auto/qml/qmllint/data/unexportedCppBase.qml @@ -0,0 +1,5 @@ +import QtQuick 2.0 + +QtObject { + property QtObject i: Image {} +} diff --git a/tests/auto/qml/qmllint/data/unknownParentDefaultPropertyCheck.qml b/tests/auto/qml/qmllint/data/unknownParentDefaultPropertyCheck.qml new file mode 100644 index 0000000000..45e738ceae --- /dev/null +++ b/tests/auto/qml/qmllint/data/unknownParentDefaultPropertyCheck.qml @@ -0,0 +1,6 @@ +import QtQuick + +Alien { // does -intentionally- not exist + Item {} + Item {} +} diff --git a/tests/auto/qml/qmllint/data/unknownTypeCustomParser.qml b/tests/auto/qml/qmllint/data/unknownTypeCustomParser.qml new file mode 100644 index 0000000000..9dbb7a9835 --- /dev/null +++ b/tests/auto/qml/qmllint/data/unknownTypeCustomParser.qml @@ -0,0 +1,7 @@ +import QtQuick + +ListModel { + property var x: TypeDoesNotExist { + property string s: DoesNotExistEither.value; + } +} diff --git a/tests/auto/qml/qmllint/data/unknownTypeInRegister.qml b/tests/auto/qml/qmllint/data/unknownTypeInRegister.qml new file mode 100644 index 0000000000..72902d292b --- /dev/null +++ b/tests/auto/qml/qmllint/data/unknownTypeInRegister.qml @@ -0,0 +1,7 @@ +import QtQuick + +ListModel { + function foo(index) { + move(index, 1, 1); + } +} diff --git a/tests/auto/qml/qmllint/data/unresolvedArrayBinding.qml b/tests/auto/qml/qmllint/data/unresolvedArrayBinding.qml new file mode 100644 index 0000000000..5f099f3a55 --- /dev/null +++ b/tests/auto/qml/qmllint/data/unresolvedArrayBinding.qml @@ -0,0 +1,10 @@ +import QtQuick + +Item { + states : [ + foo{}, + bar {}, + State {}, + foo {} + ] +}
\ No newline at end of file diff --git a/tests/auto/qml/qmllint/data/unresolvedAttachedType.qml b/tests/auto/qml/qmllint/data/unresolvedAttachedType.qml new file mode 100644 index 0000000000..7786aff3d2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/unresolvedAttachedType.qml @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Flickable { + UnresolvedAttachedType.property: QtObject {} +} diff --git a/tests/auto/qml/qmllint/data/unresolvedType.qml b/tests/auto/qml/qmllint/data/unresolvedType.qml new file mode 100644 index 0000000000..63282bc262 --- /dev/null +++ b/tests/auto/qml/qmllint/data/unresolvedType.qml @@ -0,0 +1,14 @@ +import QtQuick 2.0 + +Item { + UnresolvedType { + unresolvedProperty: 5 + Item {} + Item {} + } + Repeater { + model: 10 + delegate: UnresolvedType {} + } + property UnresolvedType foo: Item {} +} diff --git a/tests/auto/qml/qmllint/data/untitled/components/Foo.qml b/tests/auto/qml/qmllint/data/untitled/components/Foo.qml new file mode 100644 index 0000000000..10e5741900 --- /dev/null +++ b/tests/auto/qml/qmllint/data/untitled/components/Foo.qml @@ -0,0 +1,5 @@ +import QtQuick + +Text { + text: "Here I am!" +} diff --git a/tests/auto/qml/qmllint/data/untitled/main.qml b/tests/auto/qml/qmllint/data/untitled/main.qml new file mode 100644 index 0000000000..cf8980ab55 --- /dev/null +++ b/tests/auto/qml/qmllint/data/untitled/main.qml @@ -0,0 +1,9 @@ +pragma Strict + +import QtQuick +import 'qrc:/untitled/components' as C + +Window { + id: root + C.Foo {} +} diff --git a/tests/auto/qml/qmllint/data/untitled/qrcUrlImport.qrc b/tests/auto/qml/qmllint/data/untitled/qrcUrlImport.qrc new file mode 100644 index 0000000000..0ad0d57fbb --- /dev/null +++ b/tests/auto/qml/qmllint/data/untitled/qrcUrlImport.qrc @@ -0,0 +1,6 @@ +<RCC> + <qresource prefix="/untitled/"> + <file alias="main.qml">main.qml</file> + <file alias="components/Foo.qml">components/Foo.qml</file> + </qresource> +</RCC> diff --git a/tests/auto/qml/qmllint/data/unused_multi.qml b/tests/auto/qml/qmllint/data/unused_multi.qml new file mode 100644 index 0000000000..f078eadf0c --- /dev/null +++ b/tests/auto/qml/qmllint/data/unused_multi.qml @@ -0,0 +1,7 @@ +// This is the one kind of unused import we currently do not warn about: +// If two imports provide the same type, one of them could be considered unused. +// We do not however warn here because there might be legitimate reasons why a user would want this. +import QtQuick +import QtQml + +QtObject {} diff --git a/tests/auto/qml/qmllint/data/unused_prefix.qml b/tests/auto/qml/qmllint/data/unused_prefix.qml new file mode 100644 index 0000000000..a54d74390a --- /dev/null +++ b/tests/auto/qml/qmllint/data/unused_prefix.qml @@ -0,0 +1,5 @@ +import QtQml as Qml // Unused due to being prefixed +import QtQuick + +QtObject { +} diff --git a/tests/auto/qml/qmllint/data/unused_simple.qml b/tests/auto/qml/qmllint/data/unused_simple.qml new file mode 100644 index 0000000000..c2a931f3ed --- /dev/null +++ b/tests/auto/qml/qmllint/data/unused_simple.qml @@ -0,0 +1,5 @@ +import QtTest // This import is not used. +import QtQuick + +QtObject { +} diff --git a/tests/auto/qml/qmllint/data/unused_static.qml b/tests/auto/qml/qmllint/data/unused_static.qml new file mode 100644 index 0000000000..57c4bcba2e --- /dev/null +++ b/tests/auto/qml/qmllint/data/unused_static.qml @@ -0,0 +1,4 @@ +import QtQuick +import Qt.labs.sharedimage + +Item {} diff --git a/tests/auto/qml/qmllint/data/unversionChangedSignalSansArguments.qml b/tests/auto/qml/qmllint/data/unversionChangedSignalSansArguments.qml new file mode 100644 index 0000000000..c91713fa55 --- /dev/null +++ b/tests/auto/qml/qmllint/data/unversionChangedSignalSansArguments.qml @@ -0,0 +1,5 @@ +import QtQuick 2.15 + +Item { + onWidthChanged: () => {} +} diff --git a/tests/auto/qml/qmllint/data/useConstInvokable.qml b/tests/auto/qml/qmllint/data/useConstInvokable.qml new file mode 100644 index 0000000000..4f89e89918 --- /dev/null +++ b/tests/auto/qml/qmllint/data/useConstInvokable.qml @@ -0,0 +1,5 @@ +import Things + +ConstInvokable { + objectName: getObject().objectName +} diff --git a/tests/auto/qml/qmllint/data/used.qml b/tests/auto/qml/qmllint/data/used.qml new file mode 100644 index 0000000000..f5c74b0352 --- /dev/null +++ b/tests/auto/qml/qmllint/data/used.qml @@ -0,0 +1,17 @@ +import QtQml as Qml +import QtQuick as Quick +import QtQuick 2.0 as QuickLegacy +import QtQuick +import Things + +Item { + property var bar: Qml.QtObject {} + Item { + property var foo: Quick.Screen.pixelDensity + property var foo2: parent.QuickLegacy.Screen.pixelDensity + } + required property Something moo + property bool boolVar: false + property real realVar: 17.17 + property double doubleVar: 18.18 +} diff --git a/tests/auto/qml/qmllint/data/v4SequenceMethods.qml b/tests/auto/qml/qmllint/data/v4SequenceMethods.qml new file mode 100644 index 0000000000..fb4b28b674 --- /dev/null +++ b/tests/auto/qml/qmllint/data/v4SequenceMethods.qml @@ -0,0 +1,87 @@ +import QtQml + +QtObject { + property rect self: Qt.rect(9, 9, 9, 9) + + required property real i + required property real j + required property real k + + property rect r1: Qt.rect(1, 2, 3, 4) + property rect r2: Qt.rect(5, 6, 7, 8) + property rect r3: Qt.rect(9, 10, 11, 12) + + property list<rect> v4Sequence: [r1, r2, r3] + property list<rect> v4SequenceSlice: v4Sequence.slice(i, j) + property int v4SequenceIndexOf: v4Sequence.indexOf(r2, i) + property int v4SequenceLastIndexOf: v4Sequence.lastIndexOf(r3, i) + property string v4SequenceToString: v4Sequence.toString() + property string v4SequenceToLocaleString: v4Sequence.toLocaleString() + property list<rect> v4SequenceConcat: v4Sequence.concat(v4Sequence) + property rect v4SequenceFind: v4Sequence.find(element => element.x === 1) + property int v4SequenceFindIndex: v4Sequence.findIndex(element => element === r2) + property bool v4SequenceIncludes: v4Sequence.includes(r3) + property string v4SequenceJoin: v4Sequence.join() + + property bool entriesMatch: { + var iterator = v4Sequence.entries(); + for (var [index, element] of v4Sequence.entries()) { + var v = iterator.next().value; + if (index !== v[0] || element !== v[1]) { + console.log(index, v[0], element, v[1]); + return false; + } + } + + return true; + } + + property bool keysMatch: { + var iterator = v4Sequence.keys(); + for (var index of v4Sequence.keys()) { + var v = iterator.next().value; + if (index !== v) { + console.log(index, v); + return false; + } + } + + return true; + } + + property bool valuesMatch: { + var iterator = v4Sequence.values(); + for (var obj of v4Sequence.values()) { + var v = iterator.next().value; + if (obj !== v) { + console.log(obj, v); + return false; + } + } + + return true; + } + + property bool v4SequenceEvery: v4Sequence.every((element) => element != null) + property bool v4SequenceSome: v4Sequence.some((element) => element.x === 1) + + property list<int> v4SequenceMap: v4Sequence.map(((element) => element.x)) + property list<rect> v4SequenceFilter: v4Sequence.filter((element) => element.x != 1) + property string v4SequenceReduceRight: v4Sequence.reduceRight((element, v) => v + '-' + element.x + 'v', "") + property string v4SequenceReduce: v4Sequence.reduce((element, v) => v + '-' + element.x + 'v', "") + property list<string> v4SequenceOwnPropertyNames: Object.getOwnPropertyNames(v4Sequence) + + Component.onCompleted: { + v4Sequence.reverse(); + v4Sequence.pop(); + v4Sequence.push(self); + v4Sequence.shift(); + v4Sequence.unshift(self); + v4Sequence.forEach((element) => { console.log("-" + element.x + "-") }); + v4Sequence.sort(); + v4Sequence.sort((a, b) => (a.x - b.x)) + v4Sequence.copyWithin(i, j, k); + v4Sequence.fill(self, i, Math.min(j, 1024)); + v4Sequence.splice(i, j, self, self, self); + } +} diff --git a/tests/auto/qml/qmllint/data/validLiterals.qml b/tests/auto/qml/qmllint/data/validLiterals.qml new file mode 100644 index 0000000000..55792eaae2 --- /dev/null +++ b/tests/auto/qml/qmllint/data/validLiterals.qml @@ -0,0 +1,37 @@ +import QtQuick + +QtObject { + property string string1: "Hello" + + property int int1: 3 + + property double double1: 1 + + property real real1: 5.3 + + property var var1: null + property var var2: 3 + + property Item item: null + + property Gradient gradient: null + + property bool b1: true + property bool b2: false + property bool b3 + b3: true + + property TextInput edit: TextInput { validator: RegularExpressionValidator { regularExpression: /.*/ } } + + property url url1: "http://google.com" + + property color color1: "red" + + property date date1: "2021-08-13T14:16:21.435Z" + + property point point1: ({ x: 1, y: 2 }) + + property size size1: ({ width: 50, height: 50 }) + + property rect rect1: ({ x: 10, y: 20, width: 30, height: 30 }) +} diff --git a/tests/auto/qml/qmllint/data/valueSource.qml b/tests/auto/qml/qmllint/data/valueSource.qml new file mode 100644 index 0000000000..3551dde74d --- /dev/null +++ b/tests/auto/qml/qmllint/data/valueSource.qml @@ -0,0 +1,8 @@ +import QtQuick 2.0 + +Image { + transform: Rotation { + NumberAnimation on angle { + } + } +} diff --git a/tests/auto/qml/qmllint/data/valueSourceBetween2interceptors.qml b/tests/auto/qml/qmllint/data/valueSourceBetween2interceptors.qml new file mode 100644 index 0000000000..eaa24ef339 --- /dev/null +++ b/tests/auto/qml/qmllint/data/valueSourceBetween2interceptors.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Item { + Behavior on x {} + SequentialAnimation on x {} + Behavior on x {} +} diff --git a/tests/auto/qml/qmllint/data/valueSource_Value.qml b/tests/auto/qml/qmllint/data/valueSource_Value.qml new file mode 100644 index 0000000000..a2ca81b814 --- /dev/null +++ b/tests/auto/qml/qmllint/data/valueSource_Value.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Item { + property QtObject obj: QtObject {} + NumberAnimation on obj { + } +} diff --git a/tests/auto/qml/qmllint/data/valueSource_listValue.qml b/tests/auto/qml/qmllint/data/valueSource_listValue.qml new file mode 100644 index 0000000000..5bf339e202 --- /dev/null +++ b/tests/auto/qml/qmllint/data/valueSource_listValue.qml @@ -0,0 +1,7 @@ +import QtQuick 2.0 + +Item { + property list<QtObject> objs: [ QtObject {} ] + NumberAnimation on objs { // Note: poor example but it should error anyway + } +} diff --git a/tests/auto/qml/qmllint/data/valueTypesFromString.qml b/tests/auto/qml/qmllint/data/valueTypesFromString.qml new file mode 100644 index 0000000000..fc013f858f --- /dev/null +++ b/tests/auto/qml/qmllint/data/valueTypesFromString.qml @@ -0,0 +1,7 @@ +import QtQuick + +Item { + property point p: "30,50" + property rect p3: "10, 20, 30x50" + property size p4: "30x50" +} diff --git a/tests/auto/qml/qmllint/data/varargs.qml b/tests/auto/qml/qmllint/data/varargs.qml new file mode 100644 index 0000000000..a10bd23932 --- /dev/null +++ b/tests/auto/qml/qmllint/data/varargs.qml @@ -0,0 +1,7 @@ +import QtQml +import TestTypes + +MyComponent { + id: self + Component.onCompleted: createObject({a : 12}, self, 1, 2, 3) +} diff --git a/tests/auto/qml/qmllint/data/variantMapLookup.qml b/tests/auto/qml/qmllint/data/variantMapLookup.qml new file mode 100644 index 0000000000..7f50879932 --- /dev/null +++ b/tests/auto/qml/qmllint/data/variantMapLookup.qml @@ -0,0 +1,13 @@ +pragma Strict +import TestTypes +import QtQuick + +Item { + VariantMapLookupFoo { + id: moo + } + Component.onCompleted: { + moo.data.value = 5 + moo.data["value"] = 6 + } +} diff --git a/tests/auto/qml/qmllint/data/writeListProperty.qml b/tests/auto/qml/qmllint/data/writeListProperty.qml new file mode 100644 index 0000000000..8015fdf51b --- /dev/null +++ b/tests/auto/qml/qmllint/data/writeListProperty.qml @@ -0,0 +1,7 @@ +import QtQuick + +Item { + id: self + property Item a: Item { id: a } + Component.onCompleted: self.data = [ a ] +} diff --git a/tests/auto/qml/qmllint/lintplugin.cpp b/tests/auto/qml/qmllint/lintplugin.cpp new file mode 100644 index 0000000000..65795c103c --- /dev/null +++ b/tests/auto/qml/qmllint/lintplugin.cpp @@ -0,0 +1,131 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#include "lintplugin.h" + +using namespace Qt::StringLiterals; + +static constexpr QQmlSA::LoggerWarningId plugin{ "testPlugin.test" }; + +class ElementTest : public QQmlSA::ElementPass +{ +public: + ElementTest(QQmlSA::PassManager *manager) : QQmlSA::ElementPass(manager) + { + m_rectangle = resolveType(u"QtQuick", u"Rectangle"); + } + + bool shouldRun(const QQmlSA::Element &element) override + { + return element.baseType() == m_rectangle; + } + + void run(const QQmlSA::Element &element) override + { + auto property = element.property(u"radius"_s); + if (!property.isValid() || element.property(u"radius"_s).typeName() != u"qreal") { + emitWarning(u"Failed to verify radius property", plugin, element.sourceLocation()); + return; + } + + auto bindings = element.propertyBindings(u"radius"_s); + if (bindings.isEmpty() || bindings.constFirst().numberValue() != 5) { + emitWarning(u"Failed to verify radius property binding", plugin, + element.sourceLocation()); + return; + } + + emitWarning(u"ElementTest OK", plugin, element.sourceLocation()); + } + +private: + QQmlSA::Element m_rectangle; +}; + +class PropertyTest : public QQmlSA::PropertyPass +{ +public: + PropertyTest(QQmlSA::PassManager *manager) : QQmlSA::PropertyPass(manager) { } + + void onBinding(const QQmlSA::Element &element, const QString &propertyName, + const QQmlSA::Binding &binding, const QQmlSA::Element &bindingScope, + const QQmlSA::Element &value) override + { + emitWarning(u"Saw binding on %1 property %2 with value %3 (and type %4) in scope %5"_s + .arg(element.baseTypeName(), propertyName, + value.isNull() + ? u"NULL"_s + : (value.name().isNull() ? value.baseTypeName() + : value.name())) + .arg(qToUnderlying(binding.bindingType())) + .arg(bindingScope.baseTypeName()), + plugin, bindingScope.sourceLocation()); + } + + void onRead(const QQmlSA::Element &element, const QString &propertyName, + const QQmlSA::Element &readScope, QQmlSA::SourceLocation location) override + { + emitWarning(u"Saw read on %1 property %2 in scope %3"_s.arg( + element.baseTypeName(), propertyName, readScope.baseTypeName()), + plugin, location); + } + + void onWrite(const QQmlSA::Element &element, const QString &propertyName, + const QQmlSA::Element &value, const QQmlSA::Element &writeScope, + QQmlSA::SourceLocation location) override + { + emitWarning(u"Saw write on %1 property %2 with value %3 in scope %4"_s.arg( + element.baseTypeName(), propertyName, + (value.name().isNull() ? value.baseTypeName() + : value.name()), + writeScope.baseTypeName()), + plugin, location); + } +}; + +class HasImportedModuleTest : public QQmlSA::ElementPass +{ +public: + HasImportedModuleTest(QQmlSA::PassManager *manager, QString message) + : QQmlSA::ElementPass(manager), m_message(message) + { + } + + bool shouldRun(const QQmlSA::Element &element) override + { + Q_UNUSED(element) + return true; + } + + void run(const QQmlSA::Element &element) override + { + Q_UNUSED(element) + emitWarning(m_message, plugin); + } + +private: + QString m_message; +}; + +void LintPlugin::registerPasses(QQmlSA::PassManager *manager, const QQmlSA::Element &rootElement) +{ + if (!rootElement.filePath().endsWith(u"_pluginTest.qml")) + return; + + manager->registerElementPass(std::make_unique<ElementTest>(manager)); + manager->registerPropertyPass(std::make_unique<PropertyTest>(manager), "QtQuick", "Text", + "text"); + manager->registerPropertyPass(std::make_unique<PropertyTest>(manager), "", "", "x"); + manager->registerPropertyPass(std::make_unique<PropertyTest>(manager), "QtQuick", "ListView"); + if (manager->hasImportedModule("QtQuick.Controls")) { + if (manager->hasImportedModule("QtQuick")) { + if (manager->hasImportedModule("QtQuick.Window")) { + manager->registerElementPass(std::make_unique<HasImportedModuleTest>( + manager, "QtQuick.Controls, QtQuick and QtQuick.Window present")); + } + } else { + manager->registerElementPass(std::make_unique<HasImportedModuleTest>( + manager, "QtQuick.Controls and NO QtQuick present")); + } + } +} diff --git a/tests/auto/qml/qmllint/lintplugin.h b/tests/auto/qml/qmllint/lintplugin.h new file mode 100644 index 0000000000..c121657456 --- /dev/null +++ b/tests/auto/qml/qmllint/lintplugin.h @@ -0,0 +1,21 @@ +// Copyright (C) 2022 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only + +#ifndef LINTPLUGIN_H +#define LINTPLUGIN_H + +#include <QtPlugin> +#include <QtCore/qobject.h> +#include <QtQmlCompiler/qqmlsa.h> + +class LintPlugin : public QObject, public QQmlSA::LintPlugin +{ + Q_OBJECT + Q_PLUGIN_METADATA(IID QmlLintPluginInterface_iid FILE "testPlugin.json") + Q_INTERFACES(QQmlSA::LintPlugin) + +public: + void registerPasses(QQmlSA::PassManager *manager, const QQmlSA::Element &rootElement) override; +}; + +#endif // LINTPLUGIN_H diff --git a/tests/auto/qml/qmllint/testPlugin.json b/tests/auto/qml/qmllint/testPlugin.json new file mode 100644 index 0000000000..b6958fb753 --- /dev/null +++ b/tests/auto/qml/qmllint/testPlugin.json @@ -0,0 +1,14 @@ +{ + "name": "testPlugin", + "author": "Qt", + "description": "A test plugin for tst_qmllint", + "version": "1.0", + "isInternal": true, + "loggingCategories": [ + { + "name": "test", + "settingsName": "TestWarning", + "description": "A warning type used in tests" + } + ] +} diff --git a/tests/auto/qml/qmllint/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp index 25776c5448..57cb7228d8 100644 --- a/tests/auto/qml/qmllint/tst_qmllint.cpp +++ b/tests/auto/qml/qmllint/tst_qmllint.cpp @@ -1,41 +1,53 @@ -/**************************************************************************** -** -** Copyright (C) 2016 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sergio Martins <sergio.martins@kdab.com> -** Contact: https://www.qt.io/licensing/ -** -** This file is part of the plugins 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$ -** -****************************************************************************/ +// Copyright (C) 2016 Klaralvdalens Datakonsult AB, a KDAB Group company, info@kdab.com, author Sergio Martins <sergio.martins@kdab.com> +// Copyright (C) 2021 The Qt Company Ltd. +// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only #include <QtTest/QtTest> #include <QProcess> #include <QString> +#include <QtQuickTestUtils/private/qmlutils_p.h> +#include <QtQmlCompiler/private/qqmljslinter_p.h> +#include <QtQmlCompiler/private/qqmlsa_p.h> +#include <QtCore/qplugin.h> -#include <util.h> +Q_IMPORT_PLUGIN(LintPlugin) + +using namespace Qt::StringLiterals; class TestQmllint: public QQmlDataTest { Q_OBJECT +public: + TestQmllint(); + + struct Message + { + QString text = QString(); + quint32 line = 0, column = 0; + QtMsgType severity = QtWarningMsg; + }; + + struct Result + { + enum Flag { ExitsNormally = 0x1, NoMessages = 0x2, AutoFixable = 0x4 }; + + Q_DECLARE_FLAGS(Flags, Flag) + + static Result clean() { return Result { {}, {}, {}, { NoMessages, ExitsNormally } }; } + + QList<Message> expectedMessages = {}; + QList<Message> badMessages = {}; + QList<Message> expectedReplacements = {}; + + Flags flags = {}; + }; + + struct Environment : public QList<QPair<QString, QString>> + { + using QList<QPair<QString, QString>>::QList; + }; + private Q_SLOTS: void initTestCase() override; @@ -48,6 +60,9 @@ private Q_SLOTS: void dirtyQmlCode_data(); void dirtyQmlCode(); + void compilerWarnings_data(); + void compilerWarnings(); + void testUnknownCausesFail(); void directoryPassedAsQmlTypesFile(); @@ -56,102 +71,255 @@ private Q_SLOTS: void qmltypes_data(); void qmltypes(); +#ifdef QT_QMLJSROOTGEN_PRESENT + void verifyJsRoot(); +#endif + void autoqmltypes(); void resources(); + void multiDirectory(); + void requiredProperty(); + void settingsFile(); + + void additionalImplicitImport(); + + void qrcUrlImport(); + + void incorrectImportFromHost_data(); + void incorrectImportFromHost(); + + void attachedPropertyReuse(); + + void missingBuiltinsNoCrash(); + void absolutePath(); + + void importMultipartUri(); + + void lintModule_data(); + void lintModule(); + + void testLineEndings(); + void valueTypesFromString(); + + void ignoreSettingsNotCommandLineOptions(); + + void environment_data(); + void environment(); + +#if QT_CONFIG(library) + void testPlugin(); + void quickPlugin(); +#endif private: - QString runQmllint(const QString &fileToLint, - std::function<void(QProcess &)> handleResult, - const QStringList &extraArgs = QStringList()); + enum DefaultImportOption { NoDefaultImports, UseDefaultImports }; + enum ContainOption { StringNotContained, StringContained }; + enum ReplacementOption { + NoReplacementSearch, + DoReplacementSearch, + }; + + enum LintType { LintFile, LintModule }; + + QString runQmllint(const QString &fileToLint, std::function<void(QProcess &)> handleResult, + const QStringList &extraArgs = QStringList(), bool ignoreSettings = true, + bool addImportDirs = true, bool absolutePath = true, + const Environment &env = {}); QString runQmllint(const QString &fileToLint, bool shouldSucceed, - const QStringList &extraArgs = QStringList()); + const QStringList &extraArgs = QStringList(), bool ignoreSettings = true, + bool addImportDirs = true, bool absolutePath = true, + const Environment &env = {}); + void callQmllint(const QString &fileToLint, bool shouldSucceed, QJsonArray *warnings = nullptr, + QStringList importDirs = {}, QStringList qmltypesFiles = {}, + QStringList resources = {}, + DefaultImportOption defaultImports = UseDefaultImports, + QList<QQmlJS::LoggerCategory> *categories = nullptr, bool autoFixable = false, + LintType type = LintFile); + + void searchWarnings(const QJsonArray &warnings, const QString &string, + QtMsgType type = QtWarningMsg, quint32 line = 0, quint32 column = 0, + ContainOption shouldContain = StringContained, + ReplacementOption searchReplacements = NoReplacementSearch); + + template<typename ExpectedMessageFailureHandler, typename BadMessageFailureHandler> + void checkResult(const QJsonArray &warnings, const Result &result, + ExpectedMessageFailureHandler onExpectedMessageFailures, + BadMessageFailureHandler onBadMessageFailures); + + void checkResult(const QJsonArray &warnings, const Result &result) + { + checkResult( + warnings, result, [] {}, [] {}); + } + + void runTest(const QString &testFile, const Result &result, QStringList importDirs = {}, + QStringList qmltypesFiles = {}, QStringList resources = {}, + DefaultImportOption defaultImports = UseDefaultImports, + QList<QQmlJS::LoggerCategory> *categories = nullptr); QString m_qmllintPath; + QString m_qmljsrootgenPath; + QString m_qmltyperegistrarPath; + + QStringList m_defaultImportPaths; + QQmlJSLinter m_linter; }; +Q_DECLARE_METATYPE(TestQmllint::Result) + +TestQmllint::TestQmllint() + : QQmlDataTest(QT_QMLTEST_DATADIR), + m_defaultImportPaths({ QLibraryInfo::path(QLibraryInfo::QmlImportsPath), dataDirectory() }), + m_linter(m_defaultImportPaths) + +{ +} + void TestQmllint::initTestCase() { QQmlDataTest::initTestCase(); m_qmllintPath = QLibraryInfo::path(QLibraryInfo::BinariesPath) + QLatin1String("/qmllint"); + m_qmljsrootgenPath = QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath) + + QLatin1String("/qmljsrootgen"); + m_qmltyperegistrarPath = QLibraryInfo::path(QLibraryInfo::LibraryExecutablesPath) + + QLatin1String("/qmltyperegistrar"); #ifdef Q_OS_WIN m_qmllintPath += QLatin1String(".exe"); + m_qmljsrootgenPath += QLatin1String(".exe"); + m_qmltyperegistrarPath += QLatin1String(".exe"); #endif if (!QFileInfo(m_qmllintPath).exists()) { QString message = QStringLiteral("qmllint executable not found (looked for %0)").arg(m_qmllintPath); QFAIL(qPrintable(message)); } + +#ifdef QT_QMLJSROOTGEN_PRESENT + if (!QFileInfo(m_qmljsrootgenPath).exists()) { + QString message = QStringLiteral("qmljsrootgen executable not found (looked for %0)").arg(m_qmljsrootgenPath); + QFAIL(qPrintable(message)); + } + if (!QFileInfo(m_qmltyperegistrarPath).exists()) { + QString message = QStringLiteral("qmltypesregistrar executable not found (looked for %0)").arg(m_qmltyperegistrarPath); + QFAIL(qPrintable(message)); + } +#endif } void TestQmllint::testUnqualified() { QFETCH(QString, filename); - QFETCH(QString, warningMessage); - QFETCH(int, warningLine); - QFETCH(int, warningColumn); + QFETCH(Result, result); - const QString output = runQmllint(filename, false); - QVERIFY(output.contains(QString::asprintf("Warning: unqualified access at %s:%d:%d", testFile(filename).toUtf8().constData(), warningLine, warningColumn))); - QVERIFY(output.contains(warningMessage)); + runTest(filename, result); } void TestQmllint::testUnqualified_data() { QTest::addColumn<QString>("filename"); - QTest::addColumn<QString>("warningMessage"); - QTest::addColumn<int>("warningLine"); - QTest::addColumn<int>("warningColumn"); + QTest::addColumn<Result>("result"); - // check for false positive due to and warning about with statement - QTest::newRow("WithStatement") << QStringLiteral("WithStatement.qml") << QStringLiteral("with statements are strongly discouraged") << 10 << 25; // id from nowhere (as with setContextProperty) - QTest::newRow("IdFromOuterSpaceDirect") << QStringLiteral("IdFromOuterSpace.qml") << "alien.x" << 4 << 8; - QTest::newRow("IdFromOuterSpaceAccess") << QStringLiteral("IdFromOuterSpace.qml") << "console.log(alien)" << 7 << 21; + QTest::newRow("IdFromOuterSpace") + << QStringLiteral("IdFromOuterSpace.qml") + << Result { { Message { QStringLiteral("Unqualified access"), 4, 8 }, + Message { QStringLiteral("Unqualified access"), 7, 21 } } }; // access property of root object - QTest::newRow("FromRootDirect") << QStringLiteral("FromRoot.qml") << QStringLiteral("x: root.unqualified") << 9 << 16; // new property - QTest::newRow("FromRootAccess") << QStringLiteral("FromRoot.qml") << QStringLiteral("property int check: root.x") << 13 << 33; // builtin property + QTest::newRow("FromRootDirect") + << QStringLiteral("FromRoot.qml") + << Result { + { + Message { QStringLiteral("Unqualified access"), 9, 16 }, // new property + Message { QStringLiteral("Unqualified access"), 13, + 33 } // builtin property + }, + {}, + { { Message { u"root."_s, 9, 16 } }, { Message { u"root."_s, 13, 33 } } } + }; // access injected name from signal - QTest::newRow("SignalHandler1") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onDoubleClicked: function(mouse) {...") << 5 << 21; - QTest::newRow("SignalHandler2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPositionChanged: function(mouse) {...") << 10 << 21; - QTest::newRow("SignalHandlerShort1") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onClicked: (mouse) => {...") << 8 << 29; - QTest::newRow("SignalHandlerShort2") << QStringLiteral("SignalHandler.qml") << QStringLiteral("onPressAndHold: (mouse) => {...") << 12 << 34; + QTest::newRow("SignalHandler") + << QStringLiteral("SignalHandler.qml") + << Result { { + Message { QStringLiteral("Unqualified access"), 5, 21 }, + Message { QStringLiteral("Unqualified access"), 10, 21 }, + Message { QStringLiteral("Unqualified access"), 8, 29 }, + Message { QStringLiteral("Unqualified access"), 12, 34 }, + }, + {}, + { + Message { QStringLiteral("function(mouse)"), 4, 22 }, + Message { QStringLiteral("function(mouse)"), 9, 24 }, + Message { QStringLiteral("(mouse) => "), 8, 16 }, + Message { QStringLiteral("(mouse) => "), 12, 21 }, + } }; // access catch identifier outside catch block - QTest::newRow("CatchStatement") << QStringLiteral("CatchStatement.qml") << QStringLiteral("err") << 6 << 21; - - QTest::newRow("NonSpuriousParent") << QStringLiteral("nonSpuriousParentWarning.qml") << QStringLiteral("property int x: <id>.parent.x") << 6 << 25; + QTest::newRow("CatchStatement") + << QStringLiteral("CatchStatement.qml") + << Result { { Message { QStringLiteral("Unqualified access"), 6, 21 } } }; + QTest::newRow("NonSpuriousParent") + << QStringLiteral("nonSpuriousParentWarning.qml") + << Result { { + Message { QStringLiteral("Unqualified access"), 6, 25 }, + }, + {}, + { { Message { u"<id>."_s, 6, 25 } } } }; QTest::newRow("crashConnections") - << QStringLiteral("crashConnections.qml") - << QStringLiteral("target: FirstRunDialog") << 4 << 13; + << QStringLiteral("crashConnections.qml") + << Result { { Message { QStringLiteral("Unqualified access"), 4, 13 } } }; + + QTest::newRow("delegateContextProperties") + << QStringLiteral("delegateContextProperties.qml") + << Result { { Message { QStringLiteral("Unqualified access"), 6, 14 }, + Message { QStringLiteral("Unqualified access"), 7, 15 }, + Message { QStringLiteral("model is implicitly injected into this " + "delegate. Add a required property instead.") }, + Message { + QStringLiteral("index is implicitly injected into this delegate. " + "Add a required property instead.") } } }; + QTest::newRow("storeSloppy") + << QStringLiteral("UnqualifiedInStoreSloppy.qml") + << Result{ { Message{ QStringLiteral("Unqualified access"), 9, 26} } }; + QTest::newRow("storeStrict") + << QStringLiteral("UnqualifiedInStoreStrict.qml") + << Result{ { Message{ QStringLiteral("Unqualified access"), 9, 52} } }; } void TestQmllint::testUnknownCausesFail() { - const QString unknownNotFound = runQmllint("unknownElement.qml", false); - QVERIFY(unknownNotFound.contains( - QStringLiteral("Warning: Unknown was not found. Did you add all import paths?"))); + runTest("unknownElement.qml", + Result { { Message { + QStringLiteral("Unknown was not found. Did you add all import paths?"), 4, 5, + QtWarningMsg } } }); + runTest("TypeWithUnknownPropertyType.qml", + Result { { Message { + QStringLiteral("Something was not found. Did you add all import paths?"), 4, 5, + QtWarningMsg } } }); } void TestQmllint::directoryPassedAsQmlTypesFile() { - const QStringList iArg = QStringList() << QStringLiteral("-i") << dataDirectory(); - const QString errorMessages = runQmllint("unknownElement.qml", false, iArg); - const QString expectedError = QStringLiteral("Warning: QML types file cannot be a directory: ") + dataDirectory(); - QVERIFY2(errorMessages.contains(expectedError), qPrintable(QString::fromLatin1( - "Expected error to contain \"%1\", but it didn't: %2").arg(expectedError, errorMessages))); + runTest("unknownElement.qml", + Result { { Message { QStringLiteral("QML types file cannot be a directory: ") + + dataDirectory() } } }, + {}, { dataDirectory() }); } void TestQmllint::oldQmltypes() { - const QString errors = runQmllint("oldQmltypes.qml", true); - QVERIFY(errors.contains(QStringLiteral("Warning: typeinfo not declared in qmldir file"))); - QVERIFY(!errors.contains(QStringLiteral("Warning: QQuickItem was not found. Did you add all import paths?"))); - QVERIFY(errors.contains(QStringLiteral("Warning: Found deprecated dependency specifications"))); - - // Checking for both lines separately so that we don't have to mess with the line endings.b - QVERIFY(errors.contains(QStringLiteral("Meta object revision and export version differ, ignoring the revision."))); - QVERIFY(errors.contains(QStringLiteral("Revision 0 corresponds to version 0.0; it should be 1.0."))); + runTest("oldQmltypes.qml", + Result { { + Message { QStringLiteral("typeinfo not declared in qmldir file") }, + Message { + QStringLiteral("Found deprecated dependency specifications") }, + Message { QStringLiteral( + "Meta object revision and export version differ.") }, + Message { QStringLiteral( + "Revision 0 corresponds to version 0.0; it should be 1.0.") }, + }, + { Message { QStringLiteral( + "QQuickItem was not found. Did you add all import paths?") } } }); } void TestQmllint::qmltypes_data() @@ -162,14 +330,80 @@ void TestQmllint::qmltypes_data() QDirIterator it(importsPath, { "*.qmltypes" }, QDir::Files, QDirIterator::Subdirectories); while (it.hasNext()) - QTest::addRow("%s", qPrintable(it.next().mid(importsPath.length()))) << it.filePath(); + QTest::addRow("%s", qPrintable(it.next().mid(importsPath.size()))) << it.filePath(); } void TestQmllint::qmltypes() { QFETCH(QString, file); - runQmllint(file, true); + // pass the warnings in, so that callQmllint() would show errors if any + QJsonArray warnings; + callQmllint(file, true, &warnings); +} + +#ifdef QT_QMLJSROOTGEN_PRESENT +void TestQmllint::verifyJsRoot() +{ + QProcess process; + + const QString importsPath = QLibraryInfo::path(QLibraryInfo::QmlImportsPath); + QDirIterator it(importsPath, { "jsroot.qmltypes" }, + QDir::Files, QDirIterator::Subdirectories); + + QVERIFY(it.hasNext()); + + QString currentJsRootPath = it.next(); + + QTemporaryDir dir; + + QProcess jsrootProcess; + connect(&jsrootProcess, &QProcess::errorOccurred, [&](QProcess::ProcessError error) { + qWarning() << error << jsrootProcess.errorString(); + }); + jsrootProcess.setWorkingDirectory(dir.path()); + jsrootProcess.start(m_qmljsrootgenPath, {"jsroot.json"}); + + jsrootProcess.waitForFinished(); + + QCOMPARE(jsrootProcess.exitStatus(), QProcess::NormalExit); + QCOMPARE(jsrootProcess.exitCode(), 0); + + + QProcess typeregistrarProcess; + typeregistrarProcess.setWorkingDirectory(dir.path()); + typeregistrarProcess.start(m_qmltyperegistrarPath, {"jsroot.json", "--generate-qmltypes", "jsroot.qmltypes"}); + + typeregistrarProcess.waitForFinished(); + + QCOMPARE(typeregistrarProcess.exitStatus(), QProcess::NormalExit); + QCOMPARE(typeregistrarProcess.exitCode(), 0); + + QString currentJsRootContent, generatedJsRootContent; + + QFile currentJsRoot(currentJsRootPath); + QVERIFY(currentJsRoot.open(QFile::ReadOnly | QIODevice::Text)); + currentJsRootContent = QString::fromUtf8(currentJsRoot.readAll()); + currentJsRoot.close(); + + QFile generatedJsRoot(dir.path() + QDir::separator() + "jsroot.qmltypes"); + QVERIFY(generatedJsRoot.open(QFile::ReadOnly | QIODevice::Text)); + generatedJsRootContent = QString::fromUtf8(generatedJsRoot.readAll()); + generatedJsRoot.close(); + + // If any of the following asserts fail you need to update jsroot.qmltypes using the following commands: + // + // qmljsrootgen jsroot.json + // qmltyperegistrar jsroot.json --generate-qmltypes src/imports/builtins/jsroot.qmltypes + QStringList currentLines = currentJsRootContent.split(QLatin1Char('\n')); + QStringList generatedLines = generatedJsRootContent.split(QLatin1Char('\n')); + + QCOMPARE(currentLines.size(), generatedLines.size()); + + for (qsizetype i = 0; i < currentLines.size(); i++) { + QCOMPARE(currentLines[i], generatedLines[i]); + } } +#endif void TestQmllint::autoqmltypes() { @@ -180,176 +414,785 @@ void TestQmllint::autoqmltypes() process.waitForFinished(); QCOMPARE(process.exitStatus(), QProcess::NormalExit); - QCOMPARE(process.exitCode(), 0); + QVERIFY(process.exitCode() != 0); - QVERIFY(process.readAllStandardError().isEmpty()); + QVERIFY(process.readAllStandardError() + .contains("is not a qmldir file. Assuming qmltypes")); QVERIFY(process.readAllStandardOutput().isEmpty()); + + { + QProcess bare; + bare.setWorkingDirectory(testFile("autoqmltypes")); + bare.start(m_qmllintPath, { QStringLiteral("--bare"), QStringLiteral("test.qml") }); + bare.waitForFinished(); + + const QByteArray errors = bare.readAllStandardError(); + QVERIFY(!errors.contains("is not a qmldir file. Assuming qmltypes")); + QVERIFY(errors.contains("Failed to import TestTest.")); + QVERIFY(bare.readAllStandardOutput().isEmpty()); + + QCOMPARE(bare.exitStatus(), QProcess::NormalExit); + QVERIFY(bare.exitCode() != 0); + } } void TestQmllint::resources() { - runQmllint(testFile("resource.qml"), true, - {QStringLiteral("--resource"), testFile("resource.qrc")}); - runQmllint(testFile("badResource.qml"), false, - {QStringLiteral("--resource"), testFile("resource.qrc")}); - runQmllint(testFile("resource.qml"), false, {}); - runQmllint(testFile("badResource.qml"), true, {}); + { + // We need to clear the import cache before we add a qrc file with different + // contents for the same paths. + const auto guard = qScopeGuard([this]() { m_linter.clearCache(); }); + + callQmllint(testFile("resource.qml"), true, nullptr, {}, {}, { testFile("resource.qrc") }); + callQmllint(testFile("badResource.qml"), false, nullptr, {}, {}, { testFile("resource.qrc") }); + } + + + callQmllint(testFile("resource.qml"), false); + callQmllint(testFile("badResource.qml"), true); + + { + const auto guard = qScopeGuard([this]() { m_linter.clearCache(); }); + callQmllint(testFile("T/b.qml"), true, nullptr, {}, {}, { testFile("T/a.qrc") }); + } + + { + const auto guard = qScopeGuard([this]() { m_linter.clearCache(); }); + callQmllint(testFile("relPathQrc/Foo/Thing.qml"), true, nullptr, {}, {}, + { testFile("relPathQrc/resources.qrc") }); + } +} + +void TestQmllint::multiDirectory() +{ + callQmllint( + testFile("MultiDirectory/qml/Inner.qml"), true, nullptr, + {}, {}, { testFile("MultiDirectory/multi.qrc") }); + + callQmllint( + testFile("MultiDirectory/qml/pages/Page.qml"), true, nullptr, + {}, {}, { testFile("MultiDirectory/multi.qrc") }); } void TestQmllint::dirtyQmlCode_data() { QTest::addColumn<QString>("filename"); - QTest::addColumn<QString>("warningMessage"); - QTest::addColumn<QString>("notContained"); + QTest::addColumn<Result>("result"); QTest::newRow("Invalid_syntax_QML") << QStringLiteral("failure1.qml") - << QStringLiteral("%1:4 : Expected token `:'") - << QString(); - QTest::newRow("Invalid_syntax_JS") - << QStringLiteral("failure1.js") - << QStringLiteral("%1:4 : Expected token `;'") - << QString(); + << Result { { Message { QStringLiteral("Expected token `:'"), 4, 8, QtCriticalMsg } } }; + QTest::newRow("Invalid_syntax_JS") << QStringLiteral("failure1.js") + << Result { { Message { QStringLiteral("Expected token `;'"), + 4, 12, QtCriticalMsg } } }; QTest::newRow("AutomatchedSignalHandler") << QStringLiteral("AutomatchedSignalHandler.qml") - << QString("Warning: unqualified access at %1:12:36") - << QStringLiteral("no matching signal found"); + << Result { { Message { QStringLiteral("Unqualified access"), 12, 36 } } }; + QTest::newRow("AutomatchedSignalHandler2") + << QStringLiteral("AutomatchedSignalHandler.qml") + << Result { { Message { + QStringLiteral("Implicitly defining onClicked as signal handler"), 0, 0, + QtInfoMsg } } }; QTest::newRow("MemberNotFound") << QStringLiteral("memberNotFound.qml") - << QString("Warning: Property \"foo\" not found on type \"QtObject\" at %1:6:31") - << QString(); + << Result { { Message { + QStringLiteral("Member \"foo\" not found on type \"QtObject\""), 6, + 31 } } }; QTest::newRow("UnknownJavascriptMethd") << QStringLiteral("unknownJavascriptMethod.qml") - << QString("Warning: Property \"foo2\" not found on type \"Methods\" at %1:5:25") - << QString(); + << Result { { Message { + QStringLiteral("Member \"foo2\" not found on type \"Methods\""), 5, + 25 } } }; QTest::newRow("badAlias") << QStringLiteral("badAlias.qml") - << QString("Warning: unqualified access at %1:4:27") - << QString(); - QTest::newRow("badAliasProperty") + << Result { { Message { QStringLiteral("Cannot resolve alias \"wrong\""), 3, 1 } } }; + QTest::newRow("badAliasProperty1") << QStringLiteral("badAliasProperty.qml") - << QString("Warning: Property \"nowhere\" not found on type \"QtObject\" at %1:5:32") - << QString(); + << Result { { Message { QStringLiteral("Cannot resolve alias \"wrong\""), 3, 1 } } }; + QTest::newRow("badAliasExpression") + << QStringLiteral("badAliasExpression.qml") + << Result { { Message { + QStringLiteral("Invalid alias expression. Only IDs and field member " + "expressions can be aliased"), + 5, 26 } } }; + QTest::newRow("badAliasNotAnExpression") + << QStringLiteral("badAliasNotAnExpression.qml") + << Result { { Message { + QStringLiteral("Invalid alias expression. Only IDs and field member " + "expressions can be aliased"), + 4, 30 } } }; + QTest::newRow("aliasCycle1") << QStringLiteral("aliasCycle.qml") + << Result { { Message { + QStringLiteral("Alias \"b\" is part of an alias cycle"), + 3, 1 } } }; + QTest::newRow("aliasCycle2") << QStringLiteral("aliasCycle.qml") + << Result { { Message { + QStringLiteral("Alias \"a\" is part of an alias cycle"), + 3, 1 } } }; + QTest::newRow("invalidAliasTarget1") << QStringLiteral("invalidAliasTarget.qml") + << Result { { Message { + QStringLiteral("Invalid alias expression – an initalizer is needed."), + 6, 18 } } }; + QTest::newRow("invalidAliasTarget2") << QStringLiteral("invalidAliasTarget.qml") + << Result { { Message { + QStringLiteral("Invalid alias expression. Only IDs and field member expressions can be aliased"), + 7, 30 } } }; + QTest::newRow("invalidAliasTarget3") << QStringLiteral("invalidAliasTarget.qml") + << Result { { Message { + QStringLiteral("Invalid alias expression. Only IDs and field member expressions can be aliased"), + 9, 34 } } }; QTest::newRow("badParent") << QStringLiteral("badParent.qml") - << QString("Warning: Property \"rrr\" not found on type \"Item\" at %1:5:34") - << QString(); + << Result { { Message { QStringLiteral("Member \"rrr\" not found on type \"Item\""), + 5, 34 } } }; QTest::newRow("parentIsComponent") << QStringLiteral("parentIsComponent.qml") - << QString("Warning: Property \"progress\" not found on type \"QQuickItem\" at %1:7:39") - << QString(); + << Result { { Message { + QStringLiteral("Member \"progress\" not found on type \"QQuickItem\""), 7, + 39 } } }; QTest::newRow("badTypeAssertion") << QStringLiteral("badTypeAssertion.qml") - << QString("Warning: Property \"rrr\" not found on type \"Item\" at %1:5:39") - << QString(); + << Result { { Message { + QStringLiteral("Member \"rrr\" not found on type \"QQuickItem\""), 5, + 39 } } }; QTest::newRow("incompleteQmltypes") << QStringLiteral("incompleteQmltypes.qml") - << QString("Warning: Type \"QPalette\" of base \"palette\" not found when accessing member \"weDontKnowIt\" at %1:5:34") - << QString(); - QTest::newRow("inheritanceCylce") + << Result { { Message { + QStringLiteral("Type \"QPalette\" of property \"palette\" not found"), 5, + 26 } } }; + QTest::newRow("incompleteQmltypes2") + << QStringLiteral("incompleteQmltypes2.qml") + << Result { { Message { QStringLiteral("Member \"weDontKnowIt\" " + "not found on type \"CustomPalette\""), + 5, 35 } } }; + QTest::newRow("incompleteQmltypes3") + << QStringLiteral("incompleteQmltypes3.qml") + << Result { { Message { + QStringLiteral("Type \"QPalette\" of property \"palette\" not found"), 5, + 21 } } }; + QTest::newRow("inheritanceCycle") << QStringLiteral("Cycle1.qml") - << QString("Warning: Cycle2 is part of an inheritance cycle: Cycle2 -> Cycle3 -> Cycle1 -> Cycle2") - << QString(); + << Result { { Message { + QStringLiteral("Cycle1 is part of an inheritance cycle: Cycle2 -> Cycle3 " + "-> Cycle1 -> Cycle2"), + 2, 1 } } }; QTest::newRow("badQmldirImportAndDepend") << QStringLiteral("qmldirImportAndDepend/bad.qml") - << QString("Warning: Item was not found. Did you add all import paths?") - << QString(); + << Result { { Message { + QStringLiteral("Item was not found. Did you add all import paths?"), 3, + 1 } } }; QTest::newRow("javascriptMethodsInModule") << QStringLiteral("javascriptMethodsInModuleBad.qml") - << QString("Warning: Property \"unknownFunc\" not found on type \"Foo\"") - << QString(); + << Result { { Message { + QStringLiteral("Member \"unknownFunc\" not found on type \"Foo\""), 5, + 21 } } }; QTest::newRow("badEnumFromQtQml") << QStringLiteral("badEnumFromQtQml.qml") - << QString("Warning: Property \"Linear123\" not found on type \"QQmlEasingEnums\"") - << QString(); + << Result { { Message { QStringLiteral("Member \"Linear123\" not " + "found on type \"QQmlEasingEnums\""), + 4, 30 } } }; QTest::newRow("anchors3") << QStringLiteral("anchors3.qml") - << QString() - << QString(); - QTest::newRow("nanchors1") - << QStringLiteral("nanchors1.qml") - << QString() - << QString(); - QTest::newRow("nanchors2") - << QStringLiteral("nanchors2.qml") - << QString("unknown grouped property scope nanchors.") - << QString(); - QTest::newRow("nanchors3") - << QStringLiteral("nanchors3.qml") - << QString("unknown grouped property scope nanchors.") - << QString(); + << Result { { Message { QStringLiteral( + "Cannot assign binding of type QQuickItem to QQuickAnchorLine") } } }; + QTest::newRow("nanchors1") << QStringLiteral("nanchors1.qml") + << Result { { Message { QStringLiteral( + "unknown grouped property scope nanchors.") } } }; + QTest::newRow("nanchors2") << QStringLiteral("nanchors2.qml") + << Result { { Message { QStringLiteral( + "unknown grouped property scope nanchors.") } } }; + QTest::newRow("nanchors3") << QStringLiteral("nanchors3.qml") + << Result { { Message { QStringLiteral( + "unknown grouped property scope nanchors.") } } }; QTest::newRow("badAliasObject") << QStringLiteral("badAliasObject.qml") - << QString("Warning: Property \"wrongwrongwrong\" not found on type \"QtObject\"") - << QString(); - QTest::newRow("badScript") - << QStringLiteral("badScript.qml") - << QString("Warning: Property \"stuff\" not found on type \"Empty\"") - << QString(); + << Result { { Message { QStringLiteral("Member \"wrongwrongwrong\" not " + "found on type \"QtObject\""), + 8, 40 } } }; + QTest::newRow("badScript") << QStringLiteral("badScript.qml") + << Result { { Message { + QStringLiteral( + "Member \"stuff\" not found on type \"Empty\""), + 5, 21 } } }; + QTest::newRow("badScriptOnAttachedProperty") + << QStringLiteral("badScript.attached.qml") + << Result { { Message { QStringLiteral("Unqualified access"), 3, 26 } } }; QTest::newRow("brokenNamespace") << QStringLiteral("brokenNamespace.qml") - << QString("Warning: type not found in namespace at %1:4:17") - << QString(); - // TODO: This fails but currently for the wrong reasons, make sure to add a warning message requirement - // once it does fail properly in order to avoid regressions. + << Result { { Message { QStringLiteral("Type not found in namespace"), 4, 19 } } }; QTest::newRow("segFault (bad)") << QStringLiteral("SegFault.bad.qml") - << QString() - << QString(); + << Result { { Message { QStringLiteral( + "Member \"foobar\" not found on type \"QQuickScreenAttached\"") } } }; QTest::newRow("VariableUsedBeforeDeclaration") << QStringLiteral("useBeforeDeclaration.qml") - << QStringLiteral("Variable \"argq\" is used before its declaration at 5:9. " - "The declaration is at 6:13.") - << QString(); + << Result { { Message { + QStringLiteral("Variable \"argq\" is used here before its declaration. " + "The declaration is at 6:13."), + 5, 9 } } }; QTest::newRow("SignalParameterMismatch") << QStringLiteral("namedSignalParameters.qml") - << QStringLiteral("Parameter 1 to signal handler for \"onSig\" is called \"argarg\". " - "The signal has a parameter of the same name in position 2.") - << QStringLiteral("onSig2"); + << Result { { Message { QStringLiteral( + "Parameter 1 to signal handler for \"onSig\" is called \"argarg\". " + "The signal has a parameter of the same name in position 2.") } }, + { Message { QStringLiteral("onSig2") } } }; QTest::newRow("TooManySignalParameters") << QStringLiteral("tooManySignalParameters.qml") - << QStringLiteral("Signal handler for \"onSig\" has more formal parameters " - "than the signal it handles.") - << QString(); - QTest::newRow("OnAssignment") - << QStringLiteral("onAssignment.qml") - << QStringLiteral("Property \"loops\" not found on type \"bool\"") - << QString(); - QTest::newRow("BadAttached") - << QStringLiteral("badAttached.qml") - << QStringLiteral("unknown attached property scope WrongAttached.") - << QString(); - QTest::newRow("BadBinding") - << QStringLiteral("badBinding.qml") - << QStringLiteral("Binding assigned to \"doesNotExist\", but no property " - "\"doesNotExist\" exists in the current element.") - << QString(); + << Result { { Message { + QStringLiteral("Signal handler for \"onSig\" has more formal parameters " + "than the signal it handles.") } } }; + QTest::newRow("OnAssignment") << QStringLiteral("onAssignment.qml") + << Result { { Message { QStringLiteral( + "Member \"loops\" not found on type \"bool\"") } } }; + QTest::newRow("BadAttached") << QStringLiteral("badAttached.qml") + << Result { { Message { QStringLiteral( + "unknown attached property scope WrongAttached.") } } }; + QTest::newRow("BadBinding") << QStringLiteral("badBinding.qml") + << Result { { Message { QStringLiteral( + "Binding assigned to \"doesNotExist\", but no property " + "\"doesNotExist\" exists in the current element.") } } }; + QTest::newRow("bad template literal (simple)") + << QStringLiteral("badTemplateStringSimple.qml") + << Result { { Message { + QStringLiteral("Cannot assign literal of type string to int") } } }; + QTest::newRow("bad constant number to string") + << QStringLiteral("numberToStringProperty.qml") + << Result { { Message { QStringLiteral( + "Cannot assign literal of type double to QString") } } }; + QTest::newRow("bad unary minus to string") + << QStringLiteral("unaryMinusToStringProperty.qml") + << Result { { Message { QStringLiteral( + "Cannot assign literal of type double to QString") } } }; + QTest::newRow("bad tranlsation binding (qsTr)") << QStringLiteral("bad_qsTr.qml") << Result {}; + QTest::newRow("bad string binding (QT_TR_NOOP)") + << QStringLiteral("bad_QT_TR_NOOP.qml") + << Result { { Message { + QStringLiteral("Cannot assign literal of type string to int") } } }; + QTest::newRow("BadScriptBindingOnGroup") + << QStringLiteral("badScriptBinding.group.qml") + << Result { { Message { + QStringLiteral("Binding assigned to \"bogusProperty\", but no " + "property \"bogusProperty\" exists in the current element."), + 3, 10 } } }; + QTest::newRow("BadScriptBindingOnAttachedType") + << QStringLiteral("badScriptBinding.attached.qml") + << Result { { Message { + QStringLiteral("Binding assigned to \"bogusProperty\", but no " + "property \"bogusProperty\" exists in the current element."), + 5, 12 } } }; + QTest::newRow("BadScriptBindingOnAttachedSignalHandler") + << QStringLiteral("badScriptBinding.attachedSignalHandler.qml") + << Result { { Message { + QStringLiteral("no matching signal found for handler \"onBogusSignal\""), 3, + 10 } } }; QTest::newRow("BadPropertyType") << QStringLiteral("badPropertyType.qml") - << QStringLiteral("No type found for property \"bad\". This may be due to a missing " - "import statement or incomplete qmltypes files.") - << QString(); + << Result { { Message { QStringLiteral( + "No type found for property \"bad\". This may be due to a missing " + "import statement or incomplete qmltypes files.") } } }; + QTest::newRow("Deprecation (Property, with reason)") + << QStringLiteral("deprecatedPropertyReason.qml") + << Result { { Message { + QStringLiteral("Property \"deprecated\" is deprecated (Reason: Test)") } } }; + QTest::newRow("Deprecation (Property, no reason)") + << QStringLiteral("deprecatedProperty.qml") + << Result { { Message { QStringLiteral("Property \"deprecated\" is deprecated") } } }; + QTest::newRow("Deprecation (Property binding, with reason)") + << QStringLiteral("deprecatedPropertyBindingReason.qml") + << Result { { Message { QStringLiteral( + "Binding on deprecated property \"deprecatedReason\" (Reason: Test)") } } }; + QTest::newRow("Deprecation (Property binding, no reason)") + << QStringLiteral("deprecatedPropertyBinding.qml") + << Result { { Message { + QStringLiteral("Binding on deprecated property \"deprecated\"") } } }; + QTest::newRow("Deprecation (Type, with reason)") + << QStringLiteral("deprecatedTypeReason.qml") + << Result { { Message { QStringLiteral( + "Type \"TypeDeprecatedReason\" is deprecated (Reason: Test)") } } }; + QTest::newRow("Deprecation (Type, no reason)") + << QStringLiteral("deprecatedType.qml") + << Result { { Message { QStringLiteral("Type \"TypeDeprecated\" is deprecated") } } }; + QTest::newRow("MissingDefaultProperty") + << QStringLiteral("defaultPropertyWithoutKeyword.qml") + << Result { { Message { + QStringLiteral("Cannot assign to non-existent default property") } } }; + QTest::newRow("MissingDefaultPropertyDefinedInTheSameType") + << QStringLiteral("defaultPropertyWithinTheSameType.qml") + << Result { { Message { + QStringLiteral("Cannot assign to non-existent default property") } } }; + QTest::newRow("DoubleAssignToDefaultProperty") + << QStringLiteral("defaultPropertyWithDoubleAssignment.qml") + << Result { { Message { QStringLiteral( + "Cannot assign multiple objects to a default non-list property") } } }; + QTest::newRow("DefaultPropertyWithWrongType(string)") + << QStringLiteral("defaultPropertyWithWrongType.qml") + << Result { { Message { QStringLiteral( + "Cannot assign to default property of incompatible type") } }, + { Message { QStringLiteral( + "Cannot assign to non-existent default property") } } }; + QTest::newRow("MultiDefaultPropertyWithWrongType") + << QStringLiteral("multiDefaultPropertyWithWrongType.qml") + << Result { { Message { QStringLiteral( + "Cannot assign to default property of incompatible type") } }, + { Message { QStringLiteral( + "Cannot assign to non-existent default property") } } }; + QTest::newRow("DefaultPropertyLookupInUnknownType") + << QStringLiteral("unknownParentDefaultPropertyCheck.qml") + << Result { { Message { QStringLiteral( + "Alien was not found. Did you add all import paths?") } } }; + QTest::newRow("InvalidImport") + << QStringLiteral("invalidImport.qml") + << Result { { Message { QStringLiteral( + "Failed to import FooBar. Are your import paths set up properly?") } } }; + QTest::newRow("Unused Import (simple)") + << QStringLiteral("unused_simple.qml") + << Result { { Message { QStringLiteral("Unused import"), 1, 1, QtInfoMsg } }, + {}, + {}, + Result::ExitsNormally }; + QTest::newRow("Unused Import (prefix)") + << QStringLiteral("unused_prefix.qml") + << Result { { Message { QStringLiteral("Unused import"), 1, 1, QtInfoMsg } }, + {}, + {}, + Result::ExitsNormally }; + QTest::newRow("TypePropertAccess") << QStringLiteral("typePropertyAccess.qml") << Result {}; + QTest::newRow("badAttachedProperty") + << QStringLiteral("badAttachedProperty.qml") + << Result { { Message { + QStringLiteral("Member \"progress\" not found on type \"TestType\"") } } }; + QTest::newRow("badAttachedPropertyNested") + << QStringLiteral("badAttachedPropertyNested.qml") + << Result { { Message { QStringLiteral( + "Member \"progress\" not found on type \"QObject\""), + 12, 41 } }, + { Message { QString("Member \"progress\" not found on type \"QObject\""), + 6, 37 } } }; + QTest::newRow("badAttachedPropertyTypeString") + << QStringLiteral("badAttachedPropertyTypeString.qml") + << Result { { Message { + QStringLiteral("Cannot assign literal of type string to int") } } }; + QTest::newRow("badAttachedPropertyTypeQtObject") + << QStringLiteral("badAttachedPropertyTypeQtObject.qml") + << Result { { Message { QStringLiteral( + "Property \"count\" of type \"int\" is assigned an incompatible type " + "\"QtObject\"") } } }; + // should succeed, but it does not: + QTest::newRow("attachedPropertyAccess") + << QStringLiteral("goodAttachedPropertyAccess.qml") << Result::clean(); + // should succeed, but it does not: + QTest::newRow("attachedPropertyNested") + << QStringLiteral("goodAttachedPropertyNested.qml") << Result::clean(); + QTest::newRow("deprecatedFunction") + << QStringLiteral("deprecatedFunction.qml") + << Result { { Message { QStringLiteral( + "Method \"deprecated(foobar)\" is deprecated (Reason: No particular " + "reason.)") } } }; + QTest::newRow("deprecatedFunctionInherited") + << QStringLiteral("deprecatedFunctionInherited.qml") + << Result { { Message { QStringLiteral( + "Method \"deprecatedInherited(c, d)\" is deprecated (Reason: This " + "deprecation should be visible!)") } } }; + + QTest::newRow("duplicated id") + << QStringLiteral("duplicateId.qml") + << Result { { Message { + QStringLiteral("Found a duplicated id. id root was first declared "), 0, 0, + QtCriticalMsg } } }; + + QTest::newRow("string as id") << QStringLiteral("stringAsId.qml") + << Result { { Message { QStringLiteral( + "ids do not need quotation marks") } } }; + QTest::newRow("stringIdUsedInWarning") + << QStringLiteral("stringIdUsedInWarning.qml") + << Result { { Message { + QStringLiteral("i is a member of a parent element"), + } }, + {}, + { Message { QStringLiteral("stringy.") } } }; + QTest::newRow("Invalid_id_expression") + << QStringLiteral("invalidId1.qml") + << Result { { Message { QStringLiteral("Failed to parse id") } } }; + QTest::newRow("Invalid_id_blockstatement") + << QStringLiteral("invalidId2.qml") + << Result { { Message { QStringLiteral("id must be followed by an identifier") } } }; + QTest::newRow("multilineString") + << QStringLiteral("multilineString.qml") + << Result { { Message { QStringLiteral("String contains unescaped line terminator " + "which is deprecated."), + 0, 0, QtInfoMsg } }, + {}, + { Message { "`Foo\nmultiline\\`\nstring`", 4, 32 }, + Message { "`another\\`\npart\nof it`", 6, 11 }, + Message { R"(` +quote: " \\" \\\\" +ticks: \` \` \\\` \\\` +singleTicks: ' \' \\' \\\' +expression: \${expr} \${expr} \\\${expr} \\\${expr}`)", + 10, 28 }, + Message { + R"(` +quote: " \" \\" \\\" +ticks: \` \` \\\` \\\` +singleTicks: ' \\' \\\\' +expression: \${expr} \${expr} \\\${expr} \\\${expr}`)", + 16, 27 } }, + { Result::ExitsNormally, Result::AutoFixable } }; + QTest::addRow("multifix") + << QStringLiteral("multifix.qml") + << Result { { + Message { QStringLiteral("Unqualified access"), 7, 19, QtWarningMsg}, + Message { QStringLiteral("Unqualified access"), 11, 19, QtWarningMsg}, + }, {}, { + Message { QStringLiteral("pragma ComponentBehavior: Bound\n"), 1, 1 } + }, { Result::AutoFixable }}; + QTest::newRow("unresolvedType") + << QStringLiteral("unresolvedType.qml") + << Result { { Message { QStringLiteral( + "UnresolvedType was not found. Did you add all import paths?") } }, + { Message { QStringLiteral("incompatible type") } } }; + QTest::newRow("invalidInterceptor") + << QStringLiteral("invalidInterceptor.qml") + << Result { { Message { QStringLiteral( + "On-binding for property \"angle\" has wrong type \"Item\"") } } }; + QTest::newRow("2Interceptors") + << QStringLiteral("2interceptors.qml") + << Result { { Message { QStringLiteral("Duplicate interceptor on property \"x\"") } } }; + QTest::newRow("ValueSource+2Interceptors") + << QStringLiteral("valueSourceBetween2interceptors.qml") + << Result { { Message { QStringLiteral("Duplicate interceptor on property \"x\"") } } }; + QTest::newRow("2ValueSources") << QStringLiteral("2valueSources.qml") + << Result { { Message { QStringLiteral( + "Duplicate value source on property \"x\"") } } }; + QTest::newRow("ValueSource+Value") + << QStringLiteral("valueSource_Value.qml") + << Result { { Message { QStringLiteral( + "Cannot combine value source and binding on property \"obj\"") } } }; + QTest::newRow("ValueSource+ListValue") + << QStringLiteral("valueSource_listValue.qml") + << Result { { Message { QStringLiteral( + "Cannot combine value source and binding on property \"objs\"") } } }; + QTest::newRow("NonExistentListProperty") + << QStringLiteral("nonExistentListProperty.qml") + << Result { { Message { QStringLiteral("Property \"objs\" does not exist") } } }; + QTest::newRow("QtQuick.Window 2.0") + << QStringLiteral("qtquickWindow20.qml") + << Result { { Message { QStringLiteral( + "Member \"window\" not found on type \"QQuickWindow\"") } } }; + QTest::newRow("unresolvedAttachedType") + << QStringLiteral("unresolvedAttachedType.qml") + << Result { { Message { QStringLiteral( + "unknown attached property scope UnresolvedAttachedType.") } }, + { Message { QStringLiteral("Property \"property\" does not exist") } } }; + QTest::newRow("nestedInlineComponents") + << QStringLiteral("nestedInlineComponents.qml") + << Result { { Message { + QStringLiteral("Nested inline components are not supported") } } }; + QTest::newRow("inlineComponentNoComponent") + << QStringLiteral("inlineComponentNoComponent.qml") + << Result { { Message { + QStringLiteral("Inline component declaration must be followed by a typename"), + 3, 2 } } }; + QTest::newRow("WithStatement") << QStringLiteral("WithStatement.qml") + << Result { { Message { QStringLiteral( + "with statements are strongly discouraged") } } }; + QTest::newRow("BadLiteralBinding") + << QStringLiteral("badLiteralBinding.qml") + << Result { { Message { + QStringLiteral("Cannot assign literal of type string to int") } } }; + QTest::newRow("BadLiteralBindingDate") + << QStringLiteral("badLiteralBindingDate.qml") + << Result { { Message { + QStringLiteral("Cannot assign binding of type QString to QDateTime") } } }; + QTest::newRow("BadModulePrefix") + << QStringLiteral("badModulePrefix.qml") + << Result { { Message { + QStringLiteral("Cannot access singleton as a property of an object") } } }; + QTest::newRow("BadModulePrefix2") + << QStringLiteral("badModulePrefix2.qml") + << Result { { Message { QStringLiteral( + "Cannot use a non-QObject type QRectF to access prefixed import") } } }; + QTest::newRow("AssignToReadOnlyProperty") + << QStringLiteral("assignToReadOnlyProperty.qml") + << Result { { Message { + QStringLiteral("Cannot assign to read-only property activeFocus") } } }; + QTest::newRow("AssignToReadOnlyProperty") + << QStringLiteral("assignToReadOnlyProperty2.qml") + << Result { { Message { + QStringLiteral("Cannot assign to read-only property activeFocus") } } }; + QTest::newRow("cachedDependency") + << QStringLiteral("cachedDependency.qml") + << Result { { Message { QStringLiteral("Unused import"), 1, 1, QtInfoMsg } }, + { Message { QStringLiteral( + "Cannot assign binding of type QQuickItem to QObject") } }, + {}, + Result::ExitsNormally }; + QTest::newRow("cycle in import") + << QStringLiteral("cycleHead.qml") + << Result { { Message { QStringLiteral( + "MenuItem is part of an inheritance cycle: MenuItem -> MenuItem") } } }; + QTest::newRow("badGeneralizedGroup1") + << QStringLiteral("badGeneralizedGroup1.qml") + << Result { { Message { QStringLiteral( + "Binding assigned to \"aaaa\", " + "but no property \"aaaa\" exists in the current element") } } }; + QTest::newRow("badGeneralizedGroup2") + << QStringLiteral("badGeneralizedGroup2.qml") + << Result { { Message { QStringLiteral("unknown grouped property scope aself") } } }; + QTest::newRow("missingQmltypes") + << QStringLiteral("missingQmltypes.qml") + << Result { { Message { QStringLiteral("QML types file does not exist") } } }; + QTest::newRow("enumInvalid") + << QStringLiteral("enumInvalid.qml") + << Result { { Message { + QStringLiteral("Member \"red\" not found on type \"QtObject\"") } } }; + QTest::newRow("inaccessibleId") + << QStringLiteral("inaccessibleId.qml") + << Result { { Message { + QStringLiteral("Member \"objectName\" not found on type \"int\"") } } }; + QTest::newRow("inaccessibleId2") + << QStringLiteral("inaccessibleId2.qml") + << Result { { Message { + QStringLiteral("Member \"objectName\" not found on type \"int\"") } } }; + QTest::newRow("unknownTypeCustomParser") + << QStringLiteral("unknownTypeCustomParser.qml") + << Result { { Message { QStringLiteral("TypeDoesNotExist was not found.") } } }; + QTest::newRow("nonNullStored") + << QStringLiteral("nonNullStored.qml") + << Result { { Message { QStringLiteral( + "Member \"objectName\" not found on type \"Foozle\"") } }, + { Message { QStringLiteral("Unqualified access") } } }; + QTest::newRow("cppPropertyChangeHandlers-wrong-parameters-size-bindable") + << QStringLiteral("badCppPropertyChangeHandlers1.qml") + << Result { { Message { QStringLiteral( + "Signal handler for \"onAChanged\" has more formal parameters than " + "the signal it handles") } } }; + QTest::newRow("cppPropertyChangeHandlers-wrong-parameters-size-notify") + << QStringLiteral("badCppPropertyChangeHandlers2.qml") + << Result { { Message { QStringLiteral( + "Signal handler for \"onBChanged\" has more formal parameters than " + "the signal it handles") } } }; + QTest::newRow("cppPropertyChangeHandlers-no-property") + << QStringLiteral("badCppPropertyChangeHandlers3.qml") + << Result { { Message { + QStringLiteral("no matching signal found for handler \"onXChanged\"") } } }; + QTest::newRow("cppPropertyChangeHandlers-not-a-signal") + << QStringLiteral("badCppPropertyChangeHandlers4.qml") + << Result { { Message { QStringLiteral( + "no matching signal found for handler \"onWannabeSignal\"") } } }; + QTest::newRow("didYouMean(binding)") + << QStringLiteral("didYouMeanBinding.qml") + << Result { + { Message { QStringLiteral( + "Binding assigned to \"witdh\", but no property \"witdh\" exists in " + "the current element.") } }, + {}, + { Message { QStringLiteral("width") } } + }; + QTest::newRow("didYouMean(unqualified)") + << QStringLiteral("didYouMeanUnqualified.qml") + << Result { { Message { QStringLiteral("Unqualified access") } }, + {}, + { Message { QStringLiteral("height") } } }; + QTest::newRow("didYouMean(unqualifiedCall)") + << QStringLiteral("didYouMeanUnqualifiedCall.qml") + << Result { { Message { QStringLiteral("Unqualified access") } }, + {}, + { Message { QStringLiteral("func") } } }; + QTest::newRow("didYouMean(property)") + << QStringLiteral("didYouMeanProperty.qml") + << Result { { Message { QStringLiteral( + "Member \"hoight\" not found on type \"Rectangle\"") }, + {}, + { Message { QStringLiteral("height") } } } }; + QTest::newRow("didYouMean(propertyCall)") + << QStringLiteral("didYouMeanPropertyCall.qml") + << Result { + { Message { QStringLiteral("Member \"lgg\" not found on type \"Console\"") }, + {}, + { Message { QStringLiteral("log") } } } + }; + QTest::newRow("didYouMean(component)") + << QStringLiteral("didYouMeanComponent.qml") + << Result { { Message { QStringLiteral( + "Itym was not found. Did you add all import paths?") }, + {}, + { Message { QStringLiteral("Item") } } } }; + QTest::newRow("didYouMean(enum)") + << QStringLiteral("didYouMeanEnum.qml") + << Result { { Message { QStringLiteral( + "Member \"Readx\" not found on type \"QQuickImage\"") }, + {}, + { Message { QStringLiteral("Ready") } } } }; + QTest::newRow("nullBinding") << QStringLiteral("nullBinding.qml") + << Result{ { Message{ QStringLiteral( + "Cannot assign literal of type null to qreal") } } }; + QTest::newRow("missingRequiredAlias") + << QStringLiteral("missingRequiredAlias.qml") + << Result { { Message { + QStringLiteral("Component is missing required property requiredAlias from " + "RequiredWithRootLevelAlias") } } }; + QTest::newRow("missingSingletonPragma") + << QStringLiteral("missingSingletonPragma.qml") + << Result { { Message { QStringLiteral( + "Type MissingPragma declared as singleton in qmldir but missing " + "pragma Singleton") } } }; + QTest::newRow("missingSingletonQmldir") + << QStringLiteral("missingSingletonQmldir.qml") + << Result { { Message { QStringLiteral( + "Type MissingQmldirSingleton not declared as singleton in qmldir but using " + "pragma Singleton") } } }; + QTest::newRow("jsVarDeclarationsWriteConst") + << QStringLiteral("jsVarDeclarationsWriteConst.qml") + << Result { { Message { + QStringLiteral("Cannot assign to read-only property constProp") } } }; + QTest::newRow("shadowedSignal") + << QStringLiteral("shadowedSignal.qml") + << Result { { Message { + QStringLiteral("Signal \"pressed\" is shadowed by a property.") } } }; + QTest::newRow("shadowedSignalWithId") + << QStringLiteral("shadowedSignalWithId.qml") + << Result { { Message { + QStringLiteral("Signal \"pressed\" is shadowed by a property") } } }; + QTest::newRow("shadowedSlot") << QStringLiteral("shadowedSlot.qml") + << Result { { Message { QStringLiteral( + "Slot \"move\" is shadowed by a property") } } }; + QTest::newRow("shadowedMethod") << QStringLiteral("shadowedMethod.qml") + << Result { { Message { QStringLiteral( + "Method \"foo\" is shadowed by a property.") } } }; + QTest::newRow("callVarProp") + << QStringLiteral("callVarProp.qml") + << Result { { Message { QStringLiteral( + "Property \"foo\" is a variant property. It may or may not be a " + "method. Use a regular function instead.") } } }; + QTest::newRow("callJSValue") + << QStringLiteral("callJSValueProp.qml") + << Result { { Message { QStringLiteral( + "Property \"gradient\" is a QJSValue property. It may or may not be " + "a method. Use a regular Q_INVOKABLE instead.") } } }; + QTest::newRow("assignNonExistingTypeToVarProp") + << QStringLiteral("assignNonExistingTypeToVarProp.qml") + << Result { { Message { QStringLiteral( + "NonExistingType was not found. Did you add all import paths?") } } }; + QTest::newRow("unboundComponents") + << QStringLiteral("unboundComponents.qml") + << Result { { + Message { QStringLiteral("Unqualified access"), 10, 25 }, + Message { QStringLiteral("Unqualified access"), 14, 33 } + } }; + QTest::newRow("badlyBoundComponents") + << QStringLiteral("badlyBoundComponents.qml") + << Result{ { Message{ QStringLiteral("Unqualified access"), 18, 36 } } }; + QTest::newRow("NotScopedEnumCpp") + << QStringLiteral("NotScopedEnumCpp.qml") + << Result{ { Message{ + QStringLiteral("You cannot access unscoped enum \"TheEnum\" from here."), 5, + 49 } } }; + + QTest::newRow("unresolvedArrayBinding") + << QStringLiteral("unresolvedArrayBinding.qml") + << Result{ { Message{ QStringLiteral(u"Declaring an object which is not an Qml object" + " as a list member.") } } }; + QTest::newRow("duplicatedPropertyName") + << QStringLiteral("duplicatedPropertyName.qml") + << Result{ { Message{ QStringLiteral("Duplicated property name \"cat\"."), 5, 5 } } }; + QTest::newRow("duplicatedSignalName") + << QStringLiteral("duplicatedPropertyName.qml") + << Result{ { Message{ QStringLiteral("Duplicated signal name \"clicked\"."), 8, 5 } } }; + QTest::newRow("missingComponentBehaviorBound") + << QStringLiteral("missingComponentBehaviorBound.qml") + << Result { + { Message{ QStringLiteral("Unqualified access"), 8, 31 } }, + {}, + { Message{ QStringLiteral("Set \"pragma ComponentBehavior: Bound\" in " + "order to use IDs from outer components " + "in nested components."), 0, 0, QtInfoMsg } }, + Result::AutoFixable + }; + QTest::newRow("IsNotAnEntryOfEnum") + << QStringLiteral("IsNotAnEntryOfEnum.qml") + << Result{ { + Message { + QStringLiteral("Member \"Mode\" not found on type \"Item\""), 12, + 29, QtWarningMsg }, + Message{ + QStringLiteral("\"Hour\" is not an entry of enum \"Mode\"."), 13, + 62, QtInfoMsg } + }, + {}, + { Message{ QStringLiteral("Hours") } } + }; + + QTest::newRow("StoreNameMethod") + << QStringLiteral("storeNameMethod.qml") + << Result { { Message { QStringLiteral("Cannot assign to method foo") } } }; + + QTest::newRow("CoerceToVoid") + << QStringLiteral("coercetovoid.qml") + << Result { { Message { + QStringLiteral("Function without return type annotation returns double") + } } }; + + QTest::newRow("lowerCaseQualifiedImport") + << QStringLiteral("lowerCaseQualifiedImport.qml") + << Result{ { + Message{ u"Import qualifier 'test' must start with a capital letter."_s }, + Message{ + u"Namespace 'test' of 'test.Rectangle' must start with an upper case letter."_s }, + } }; + QTest::newRow("lowerCaseQualifiedImport2") + << QStringLiteral("lowerCaseQualifiedImport2.qml") + << Result{ { + Message{ u"Import qualifier 'test' must start with a capital letter."_s }, + Message{ + u"Namespace 'test' of 'test.Item' must start with an upper case letter."_s }, + Message{ + u"Namespace 'test' of 'test.Rectangle' must start with an upper case letter."_s }, + Message{ + u"Namespace 'test' of 'test.color' must start with an upper case letter."_s }, + Message{ + u"Namespace 'test' of 'test.Grid' must start with an upper case letter."_s }, + } }; + QTest::newRow("notQmlRootMethods") + << QStringLiteral("notQmlRootMethods.qml") + << Result{ { + Message{ u"Member \"deleteLater\" not found on type \"QtObject\""_s }, + Message{ u"Member \"destroyed\" not found on type \"QtObject\""_s }, + } }; } void TestQmllint::dirtyQmlCode() { QFETCH(QString, filename); - QFETCH(QString, warningMessage); - QFETCH(QString, notContained); - if (warningMessage.contains(QLatin1String("%1"))) - warningMessage = warningMessage.arg(testFile(filename)); - - const QString output = runQmllint(filename, [&](QProcess &process) { - QVERIFY(process.waitForFinished()); - QCOMPARE(process.exitStatus(), QProcess::NormalExit); - QEXPECT_FAIL("anchors3", "We don't see that QQuickItem cannot be assigned to QQuickAnchorLine", Abort); - QEXPECT_FAIL("nanchors1", "Invalid grouped properties are not always detected", Abort); - QVERIFY(process.exitCode() != 0); - }); + QFETCH(Result, result); - QVERIFY(output.contains(warningMessage)); - if (!notContained.isEmpty()) - QVERIFY(!output.contains(notContained)); + QJsonArray warnings; + + QEXPECT_FAIL("attachedPropertyAccess", "We cannot discern between types and instances", Abort); + QEXPECT_FAIL("attachedPropertyNested", "We cannot discern between types and instances", Abort); + QEXPECT_FAIL("BadLiteralBindingDate", + "We're currently not able to verify any non-trivial QString conversion that " + "requires QQmlStringConverters", + Abort); + QEXPECT_FAIL("bad tranlsation binding (qsTr)", "We currently do not check translation binding", + Abort); + + callQmllint(filename, result.flags.testFlag(Result::ExitsNormally), &warnings, {}, {}, {}, + UseDefaultImports, nullptr, result.flags.testFlag(Result::Flag::AutoFixable)); + + checkResult( + warnings, result, + [] { + QEXPECT_FAIL("BadLiteralBindingDate", + "We're currently not able to verify any non-trivial QString " + "conversion that " + "requires QQmlStringConverters", + Abort); + }, + [] { + QEXPECT_FAIL("badAttachedPropertyNested", + "We cannot discern between types and instances", Abort); + }); } void TestQmllint::cleanQmlCode_data() @@ -385,7 +1228,7 @@ void TestQmllint::cleanQmlCode_data() QTest::newRow("enumFromQtQml") << QStringLiteral("enumFromQtQml.qml"); QTest::newRow("anchors1") << QStringLiteral("anchors1.qml"); QTest::newRow("anchors2") << QStringLiteral("anchors2.qml"); - QTest::newRow("optionalImport") << QStringLiteral("optionalImport.qml"); + QTest::newRow("defaultImport") << QStringLiteral("defaultImport.qml"); QTest::newRow("goodAliasObject") << QStringLiteral("goodAliasObject.qml"); QTest::newRow("jsmoduleimport") << QStringLiteral("jsmoduleimport.qml"); QTest::newRow("overridescript") << QStringLiteral("overridescript.qml"); @@ -398,40 +1241,288 @@ void TestQmllint::cleanQmlCode_data() QTest::newRow("externalEnumProperty") << QStringLiteral("externalEnumProperty.qml"); QTest::newRow("shapes") << QStringLiteral("shapes.qml"); QTest::newRow("var") << QStringLiteral("var.qml"); + QTest::newRow("defaultProperty") << QStringLiteral("defaultProperty.qml"); + QTest::newRow("defaultPropertyList") << QStringLiteral("defaultPropertyList.qml"); + QTest::newRow("defaultPropertyComponent") << QStringLiteral("defaultPropertyComponent.qml"); + QTest::newRow("defaultPropertyComponent2") << QStringLiteral("defaultPropertyComponent.2.qml"); + QTest::newRow("defaultPropertyListModel") << QStringLiteral("defaultPropertyListModel.qml"); + QTest::newRow("defaultPropertyVar") << QStringLiteral("defaultPropertyVar.qml"); + QTest::newRow("multiDefaultProperty") << QStringLiteral("multiDefaultPropertyOk.qml"); + QTest::newRow("propertyDelegate") << QStringLiteral("propertyDelegate.qml"); + QTest::newRow("duplicateQmldirImport") << QStringLiteral("qmldirImport/duplicate.qml"); + QTest::newRow("Used imports") << QStringLiteral("used.qml"); + QTest::newRow("Unused imports (multi)") << QStringLiteral("unused_multi.qml"); + QTest::newRow("Unused static module") << QStringLiteral("unused_static.qml"); + QTest::newRow("compositeSingleton") << QStringLiteral("compositesingleton.qml"); + QTest::newRow("stringLength") << QStringLiteral("stringLength.qml"); + QTest::newRow("stringLength2") << QStringLiteral("stringLength2.qml"); + QTest::newRow("stringLength3") << QStringLiteral("stringLength3.qml"); + QTest::newRow("attachedPropertyAssignments") + << QStringLiteral("attachedPropertyAssignments.qml"); + QTest::newRow("groupedPropertyAssignments") << QStringLiteral("groupedPropertyAssignments.qml"); + QTest::newRow("goodAttachedProperty") << QStringLiteral("goodAttachedProperty.qml"); + QTest::newRow("objectBindingOnVarProperty") << QStringLiteral("objectBoundToVar.qml"); + QTest::newRow("Unversioned change signal without arguments") << QStringLiteral("unversionChangedSignalSansArguments.qml"); + QTest::newRow("deprecatedFunctionOverride") << QStringLiteral("deprecatedFunctionOverride.qml"); + QTest::newRow("multilineStringEscaped") << QStringLiteral("multilineStringEscaped.qml"); + QTest::newRow("propertyOverride") << QStringLiteral("propertyOverride.qml"); + QTest::newRow("propertyBindingValue") << QStringLiteral("propertyBindingValue.qml"); + QTest::newRow("customParser") << QStringLiteral("customParser.qml"); + QTest::newRow("customParser.recursive") << QStringLiteral("customParser.recursive.qml"); + QTest::newRow("2Behavior") << QStringLiteral("2behavior.qml"); + QTest::newRow("interceptor") << QStringLiteral("interceptor.qml"); + QTest::newRow("valueSource") << QStringLiteral("valueSource.qml"); + QTest::newRow("interceptor+valueSource") << QStringLiteral("interceptor_valueSource.qml"); + QTest::newRow("groupedProperty (valueSource+interceptor)") + << QStringLiteral("groupedProperty_valueSource_interceptor.qml"); + QTest::newRow("QtQuick.Window 2.1") << QStringLiteral("qtquickWindow21.qml"); + QTest::newRow("attachedTypeIndirect") << QStringLiteral("attachedTypeIndirect.qml"); + QTest::newRow("objectArray") << QStringLiteral("objectArray.qml"); + QTest::newRow("aliasToList") << QStringLiteral("aliasToList.qml"); + QTest::newRow("QVariant") << QStringLiteral("qvariant.qml"); + QTest::newRow("Accessible") << QStringLiteral("accessible.qml"); + QTest::newRow("qjsroot") << QStringLiteral("qjsroot.qml"); + QTest::newRow("qmlRootMethods") << QStringLiteral("qmlRootMethods.qml"); + QTest::newRow("InlineComponent") << QStringLiteral("inlineComponent.qml"); + QTest::newRow("InlineComponentWithComponents") << QStringLiteral("inlineComponentWithComponents.qml"); + QTest::newRow("InlineComponentsChained") << QStringLiteral("inlineComponentsChained.qml"); + QTest::newRow("ignoreWarnings") << QStringLiteral("ignoreWarnings.qml"); + QTest::newRow("BindingBeforeDeclaration") << QStringLiteral("bindingBeforeDeclaration.qml"); + QTest::newRow("CustomParserUnqualifiedAccess") + << QStringLiteral("customParserUnqualifiedAccess.qml"); + QTest::newRow("ImportQMLModule") << QStringLiteral("importQMLModule.qml"); + QTest::newRow("ImportDirectoryQmldir") << QStringLiteral("Things/LintDirectly.qml"); + QTest::newRow("BindingsOnGroupAndAttachedProperties") + << QStringLiteral("goodBindingsOnGroupAndAttached.qml"); + QTest::newRow("QQmlEasingEnums::Type") << QStringLiteral("animationEasing.qml"); + QTest::newRow("ValidLiterals") << QStringLiteral("validLiterals.qml"); + QTest::newRow("GoodModulePrefix") << QStringLiteral("goodModulePrefix.qml"); + QTest::newRow("required property in Component") << QStringLiteral("requiredPropertyInComponent.qml"); + QTest::newRow("bytearray") << QStringLiteral("bytearray.qml"); + QTest::newRow("initReadonly") << QStringLiteral("initReadonly.qml"); + QTest::newRow("connectionNoParent") << QStringLiteral("connectionNoParent.qml"); // QTBUG-97600 + QTest::newRow("goodGeneralizedGroup") << QStringLiteral("goodGeneralizedGroup.qml"); + QTest::newRow("on binding in grouped property") << QStringLiteral("onBindingInGroupedProperty.qml"); + QTest::newRow("declared property of JS object") << QStringLiteral("bareQt.qml"); + QTest::newRow("ID overrides property") << QStringLiteral("accessibleId.qml"); + QTest::newRow("matchByName") << QStringLiteral("matchByName.qml"); + QTest::newRow("QObject.hasOwnProperty") << QStringLiteral("qobjectHasOwnProperty.qml"); + QTest::newRow("cppPropertyChangeHandlers") + << QStringLiteral("goodCppPropertyChangeHandlers.qml"); + QTest::newRow("unexportedCppBase") << QStringLiteral("unexportedCppBase.qml"); + QTest::newRow("requiredWithRootLevelAlias") << QStringLiteral("RequiredWithRootLevelAlias.qml"); + QTest::newRow("jsVarDeclarations") << QStringLiteral("jsVarDeclarations.qml"); + QTest::newRow("qmodelIndex") << QStringLiteral("qmodelIndex.qml"); + QTest::newRow("boundComponents") << QStringLiteral("boundComponents.qml"); + QTest::newRow("prefixedAttachedProperty") << QStringLiteral("prefixedAttachedProperty.qml"); + QTest::newRow("callLater") << QStringLiteral("callLater.qml"); + QTest::newRow("listPropertyMethods") << QStringLiteral("listPropertyMethods.qml"); + QTest::newRow("v4SequenceMethods") << QStringLiteral("v4SequenceMethods.qml"); + QTest::newRow("stringToByteArray") << QStringLiteral("stringToByteArray.qml"); + QTest::newRow("jsLibrary") << QStringLiteral("jsLibrary.qml"); + QTest::newRow("nullBindingFunction") << QStringLiteral("nullBindingFunction.qml"); + QTest::newRow("BindingTypeMismatchFunction") << QStringLiteral("bindingTypeMismatchFunction.qml"); + QTest::newRow("BindingTypeMismatch") << QStringLiteral("bindingTypeMismatch.qml"); + QTest::newRow("template literal (substitution)") << QStringLiteral("templateStringSubstitution.qml"); + QTest::newRow("enumsOfScrollBar") << QStringLiteral("enumsOfScrollBar.qml"); + QTest::newRow("optionalChainingCall") << QStringLiteral("optionalChainingCall.qml"); + QTest::newRow("EnumAccessCpp") << QStringLiteral("EnumAccessCpp.qml"); + QTest::newRow("qtquickdialog") << QStringLiteral("qtquickdialog.qml"); + QTest::newRow("callBase") << QStringLiteral("callBase.qml"); + QTest::newRow("propertyWithOn") << QStringLiteral("switcher.qml"); + QTest::newRow("constructorProperty") << QStringLiteral("constructorProperty.qml"); + QTest::newRow("onlyMajorVersion") << QStringLiteral("onlyMajorVersion.qml"); + QTest::newRow("attachedImportUse") << QStringLiteral("attachedImportUse.qml"); + QTest::newRow("VariantMapGetPropertyLookup") << QStringLiteral("variantMapLookup.qml"); + QTest::newRow("StringToDateTime") << QStringLiteral("stringToDateTime.qml"); + QTest::newRow("ScriptInTemplate") << QStringLiteral("scriptInTemplate.qml"); + QTest::newRow("AddressableValue") << QStringLiteral("addressableValue.qml"); + QTest::newRow("WriteListProperty") << QStringLiteral("writeListProperty.qml"); + QTest::newRow("dontConfuseMemberPrintWithGlobalPrint") << QStringLiteral("findMemberPrint.qml"); + QTest::newRow("groupedAttachedLayout") << QStringLiteral("groupedAttachedLayout.qml"); + QTest::newRow("QQmlScriptString") << QStringLiteral("scriptstring.qml"); + QTest::newRow("QEventPoint") << QStringLiteral("qEventPoint.qml"); + QTest::newRow("locale") << QStringLiteral("locale.qml"); + QTest::newRow("constInvokable") << QStringLiteral("useConstInvokable.qml"); + QTest::newRow("dontCheckJSTypes") << QStringLiteral("dontCheckJSTypes.qml"); } void TestQmllint::cleanQmlCode() { QFETCH(QString, filename); - const QString warnings = runQmllint(filename, true); - QEXPECT_FAIL("segFault", "This property exists and should not produce a warning", Abort); - QVERIFY2(warnings.isEmpty(), qPrintable(warnings)); + + QJsonArray warnings; + + runTest(filename, Result::clean()); +} + +void TestQmllint::compilerWarnings_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<Result>("result"); + QTest::addColumn<bool>("enableCompilerWarnings"); + + QTest::newRow("listIndices") << QStringLiteral("listIndices.qml") << Result::clean() << true; + QTest::newRow("lazyAndDirect") + << QStringLiteral("LazyAndDirect/Lazy.qml") << Result::clean() << true; + QTest::newRow("qQmlV4Function") << QStringLiteral("varargs.qml") << Result::clean() << true; + QTest::newRow("multiGrouped") << QStringLiteral("multiGrouped.qml") << Result::clean() << true; + + QTest::newRow("shadowable") + << QStringLiteral("shadowable.qml") + << Result { { Message {QStringLiteral( + "with type NotSoSimple (stored as QQuickItem) can be shadowed") } } } + << true; + QTest::newRow("tooFewParameters") + << QStringLiteral("tooFewParams.qml") + << Result { { Message { QStringLiteral("No matching override found") } } } << true; + QTest::newRow("javascriptVariableArgs") + << QStringLiteral("javascriptVariableArgs.qml") + << Result { { Message { + QStringLiteral("Function expects 0 arguments, but 2 were provided") } } } + << true; + QTest::newRow("unknownTypeInRegister") + << QStringLiteral("unknownTypeInRegister.qml") + << Result { { Message { + QStringLiteral("Functions without type annotations won't be compiled") } } } + << true; + QTest::newRow("pragmaStrict") + << QStringLiteral("pragmaStrict.qml") + << Result { { { QStringLiteral( + "Functions without type annotations won't be compiled") } } } + << true; + QTest::newRow("generalizedGroupHint") + << QStringLiteral("generalizedGroupHint.qml") + << Result { { { QStringLiteral( + "Cannot resolve property type for binding on myColor. " + "You may want use ID-based grouped properties here.") } } } + << true; + QTest::newRow("invalidIdLookup") + << QStringLiteral("invalidIdLookup.qml") + << Result { { { + QStringLiteral("Cannot retrieve a non-object type by ID: stateMachine") + } } } + << true; + QTest::newRow("returnTypeAnnotation-component") + << QStringLiteral("returnTypeAnnotation_component.qml") + << Result{ { { "Could not compile function comp: function without return type " + "annotation returns (component in" }, + { "returnTypeAnnotation_component.qml)::c with type Comp (stored as " + "QQuickItem). This may prevent proper compilation to Cpp." } } } + << true; + QTest::newRow("returnTypeAnnotation-enum") + << QStringLiteral("returnTypeAnnotation_enum.qml") + << Result{ { { "Could not compile function enumeration: function without return type " + "annotation returns QQuickText::HAlignment::AlignRight (stored as int). " + "This may prevent proper compilation to Cpp." } } } + << true; + QTest::newRow("returnTypeAnnotation-method") + << QStringLiteral("returnTypeAnnotation_method.qml") + << Result{ { { "Could not compile function method: function without return type " + "annotation returns (component in " }, // Don't check the build folder path + { "returnTypeAnnotation_method.qml)::f(...) (stored as QJSValue). This may " + "prevent proper compilation to Cpp." } } } + << true; + QTest::newRow("returnTypeAnnotation-property") + << QStringLiteral("returnTypeAnnotation_property.qml") + << Result{ { { "Could not compile function prop: function without return type " + "annotation returns (component in " }, // Don't check the build folder path + { "returnTypeAnnotation_property.qml)::i with type int. This may prevent " + "proper compilation to Cpp." } } } + << true; + QTest::newRow("returnTypeAnnotation-type") + << QStringLiteral("returnTypeAnnotation_type.qml") + << Result{ { { "Could not compile function type: function without return type " + "annotation returns double. This may prevent proper compilation to " + "Cpp." } } } + << true; +} + +void TestQmllint::compilerWarnings() +{ + QFETCH(QString, filename); + QFETCH(Result, result); + QFETCH(bool, enableCompilerWarnings); + + QJsonArray warnings; + + auto categories = QQmlJSLogger::defaultCategories(); + + auto category = std::find_if(categories.begin(), categories.end(), [](const QQmlJS::LoggerCategory& category) { + return category.id() == qmlCompiler; + }); + Q_ASSERT(category != categories.end()); + + if (enableCompilerWarnings) { + category->setLevel(QtWarningMsg); + category->setIgnored(false); + } + + runTest(filename, result, {}, {}, {}, UseDefaultImports, &categories); } QString TestQmllint::runQmllint(const QString &fileToLint, std::function<void(QProcess &)> handleResult, - const QStringList &extraArgs) + const QStringList &extraArgs, bool ignoreSettings, + bool addImportDirs, bool absolutePath, const Environment &env) { auto qmlImportDir = QLibraryInfo::path(QLibraryInfo::QmlImportsPath); QStringList args; - args << (QFileInfo(fileToLint).isAbsolute() ? fileToLint : testFile(fileToLint)) - << QStringLiteral("-I") << qmlImportDir - << QStringLiteral("-I") << dataDirectory(); + QString absoluteFilePath = + QFileInfo(fileToLint).isAbsolute() ? fileToLint : testFile(fileToLint); + + args << QFileInfo(absoluteFilePath).fileName(); + + if (addImportDirs) { + args << QStringLiteral("-I") << qmlImportDir + << QStringLiteral("-I") << dataDirectory(); + } + + if (ignoreSettings) + args << QStringLiteral("--ignore-settings"); + + if (absolutePath) + args << QStringLiteral("--absolute-path"); + args << extraArgs; args << QStringLiteral("--silent"); QString errors; auto verify = [&](bool isSilent) { QProcess process; + QProcessEnvironment processEnv = QProcessEnvironment::systemEnvironment(); + for (const auto &entry : env) + processEnv.insert(entry.first, entry.second); + + process.setProcessEnvironment(processEnv); + process.setWorkingDirectory(QFileInfo(absoluteFilePath).absolutePath()); process.start(m_qmllintPath, args); handleResult(process); errors = process.readAllStandardError(); - if (isSilent) - QVERIFY(errors.isEmpty()); + QStringList lines = errors.split(u'\n', Qt::SkipEmptyParts); + + auto end = std::remove_if(lines.begin(), lines.end(), [](const QString &line) { + return !line.startsWith("Warning: ") && !line.startsWith("Error: "); + }); + + std::sort(lines.begin(), end); + auto it = std::unique(lines.begin(), end); + if (it != end) { + qDebug() << "The warnings and errors were generated more than once:"; + do { + qDebug() << *it; + } while (++it != end); + QTest::qFail("Duplicate warnings and errors", __FILE__, __LINE__); + } + + if (isSilent) { + QTest::qVerify(errors.isEmpty(), "errors.isEmpty()", "Silent mode outputs messages", + __FILE__, __LINE__); + } if (QTest::currentTestFailed()) { - qDebug() << "Command:" << process.program() << args.join(u' '); + qDebug().noquote() << "Command:" << process.program() << args.join(u' '); qDebug() << "Exit status:" << process.exitStatus(); qDebug() << "Exit code:" << process.exitCode(); qDebug() << "stderr:" << errors; @@ -444,28 +1535,722 @@ QString TestQmllint::runQmllint(const QString &fileToLint, return errors; } -QString TestQmllint::runQmllint(const QString &fileToLint, bool shouldSucceed, const QStringList &extraArgs) +QString TestQmllint::runQmllint(const QString &fileToLint, bool shouldSucceed, + const QStringList &extraArgs, bool ignoreSettings, + bool addImportDirs, bool absolutePath, const Environment &env) { - return runQmllint(fileToLint, [&](QProcess &process) { - QVERIFY(process.waitForFinished()); - QCOMPARE(process.exitStatus(), QProcess::NormalExit); + return runQmllint( + fileToLint, + [&](QProcess &process) { + QVERIFY(process.waitForFinished()); + QCOMPARE(process.exitStatus(), QProcess::NormalExit); - QEXPECT_FAIL("segFault", "This property exists and should not produce a warning", Abort); - if (shouldSucceed) - QCOMPARE(process.exitCode(), 0); - else - QVERIFY(process.exitCode() != 0); - }, extraArgs); + if (shouldSucceed) + QCOMPARE(process.exitCode(), 0); + else + QVERIFY(process.exitCode() != 0); + }, + extraArgs, ignoreSettings, addImportDirs, absolutePath, env); +} + +void TestQmllint::callQmllint(const QString &fileToLint, bool shouldSucceed, QJsonArray *warnings, + QStringList importPaths, QStringList qmldirFiles, + QStringList resources, DefaultImportOption defaultImports, + QList<QQmlJS::LoggerCategory> *categories, bool autoFixable, + LintType type) +{ + QJsonArray jsonOutput; + + const QFileInfo info = QFileInfo(fileToLint); + const QString lintedFile = info.isAbsolute() ? fileToLint : testFile(fileToLint); + + QQmlJSLinter::LintResult lintResult; + + const QStringList resolvedImportPaths = defaultImports == UseDefaultImports + ? m_defaultImportPaths + importPaths + : importPaths; + if (type == LintFile) { + const QList<QQmlJS::LoggerCategory> resolvedCategories = + categories != nullptr ? *categories : QQmlJSLogger::defaultCategories(); + lintResult = m_linter.lintFile( + lintedFile, nullptr, true, &jsonOutput, resolvedImportPaths, qmldirFiles, + resources, resolvedCategories); + } else { + lintResult = + m_linter.lintModule(fileToLint, true, &jsonOutput, resolvedImportPaths, resources); + } + + bool success = lintResult == QQmlJSLinter::LintSuccess; + QEXPECT_FAIL("qtquickdialog", "Will fail until QTBUG-104091 is implemented", Abort); + QVERIFY2(success == shouldSucceed, QJsonDocument(jsonOutput).toJson()); + + if (warnings) { + QVERIFY2(jsonOutput.size() == 1, QJsonDocument(jsonOutput).toJson()); + *warnings = jsonOutput.at(0)[u"warnings"_s].toArray(); + } + + QCOMPARE(success, shouldSucceed); + + if (lintResult == QQmlJSLinter::LintSuccess || lintResult == QQmlJSLinter::HasWarnings) { + QString fixedCode; + QQmlJSLinter::FixResult fixResult = m_linter.applyFixes(&fixedCode, true); + + if (autoFixable) { + QCOMPARE(fixResult, QQmlJSLinter::FixSuccess); + // Check that the fixed version of the file actually passes qmllint now + QTemporaryDir dir; + QVERIFY(dir.isValid()); + QFile file(dir.filePath("Fixed.qml")); + QVERIFY2(file.open(QIODevice::WriteOnly), qPrintable(file.errorString())); + file.write(fixedCode.toUtf8()); + file.flush(); + file.close(); + + callQmllint(QFileInfo(file).absoluteFilePath(), true, nullptr, importPaths, qmldirFiles, + resources, defaultImports, categories, false); + + const QString fixedPath = testFile(info.baseName() + u".fixed.qml"_s); + + if (QFileInfo(fixedPath).exists()) { + QFile fixedFile(fixedPath); + QVERIFY(fixedFile.open(QFile::ReadOnly)); + QString fixedFileContents = QString::fromUtf8(fixedFile.readAll()); +#ifdef Q_OS_WIN + fixedCode = fixedCode.replace(u"\r\n"_s, u"\n"_s); + fixedFileContents = fixedFileContents.replace(u"\r\n"_s, u"\n"_s); +#endif + + QCOMPARE(fixedCode, fixedFileContents); + } + } else { + if (shouldSucceed) + QCOMPARE(fixResult, QQmlJSLinter::NothingToFix); + else + QVERIFY(fixResult == QQmlJSLinter::FixSuccess + || fixResult == QQmlJSLinter::NothingToFix); + } + } +} + +void TestQmllint::runTest(const QString &testFile, const Result &result, QStringList importDirs, + QStringList qmltypesFiles, QStringList resources, + DefaultImportOption defaultImports, + QList<QQmlJS::LoggerCategory> *categories) +{ + QJsonArray warnings; + callQmllint(testFile, result.flags.testFlag(Result::Flag::ExitsNormally), &warnings, importDirs, + qmltypesFiles, resources, defaultImports, categories, + result.flags.testFlag(Result::Flag::AutoFixable)); + checkResult(warnings, result); +} + +template<typename ExpectedMessageFailureHandler, typename BadMessageFailureHandler> +void TestQmllint::checkResult(const QJsonArray &warnings, const Result &result, + ExpectedMessageFailureHandler onExpectedMessageFailures, + BadMessageFailureHandler onBadMessageFailures) +{ + if (result.flags.testFlag(Result::Flag::NoMessages)) + QVERIFY2(warnings.isEmpty(), qPrintable(QJsonDocument(warnings).toJson())); + + for (const Message &msg : result.expectedMessages) { + // output.contains() expect fails: + onExpectedMessageFailures(); + + searchWarnings(warnings, msg.text, msg.severity, msg.line, msg.column); + } + + for (const Message &msg : result.badMessages) { + // !output.contains() expect fails: + onBadMessageFailures(); + + searchWarnings(warnings, msg.text, msg.severity, msg.line, msg.column, StringNotContained); + } + + for (const Message &replacement : result.expectedReplacements) { + searchWarnings(warnings, replacement.text, replacement.severity, replacement.line, + replacement.column, StringContained, DoReplacementSearch); + } +} + +void TestQmllint::searchWarnings(const QJsonArray &warnings, const QString &substring, + QtMsgType type, quint32 line, quint32 column, + ContainOption shouldContain, ReplacementOption searchReplacements) +{ + bool contains = false; + + auto typeStringToMsgType = [](const QString &type) -> QtMsgType { + if (type == u"debug") + return QtDebugMsg; + if (type == u"info") + return QtInfoMsg; + if (type == u"warning") + return QtWarningMsg; + if (type == u"critical") + return QtCriticalMsg; + if (type == u"fatal") + return QtFatalMsg; + + Q_UNREACHABLE(); + }; + + for (const QJsonValueConstRef warning : warnings) { + QString warningMessage = warning[u"message"].toString(); + quint32 warningLine = warning[u"line"].toInt(); + quint32 warningColumn = warning[u"column"].toInt(); + QtMsgType warningType = typeStringToMsgType(warning[u"type"].toString()); + + if (warningMessage.contains(substring)) { + if (warningType != type) { + continue; + } + if (line != 0 || column != 0) { + if (warningLine != line || warningColumn != column) { + continue; + } + } + + contains = true; + break; + } + + for (const QJsonValueConstRef fix : warning[u"suggestions"].toArray()) { + const QString fixMessage = fix[u"message"].toString(); + if (fixMessage.contains(substring)) { + contains = true; + break; + } + + if (searchReplacements == DoReplacementSearch) { + QString replacement = fix[u"replacement"].toString(); +#ifdef Q_OS_WIN + // Replacements can contain native line endings + // but we need them to be uniform in order for them to conform to our test data + replacement = replacement.replace(u"\r\n"_s, u"\n"_s); +#endif + + if (replacement.contains(substring)) { + quint32 fixLine = fix[u"line"].toInt(); + quint32 fixColumn = fix[u"column"].toInt(); + if (line != 0 || column != 0) { + if (fixLine != line || fixColumn != column) { + continue; + } + } + contains = true; + break; + } + } + } + } + + const auto toDescription = [](const QJsonArray &warnings, const QString &substring, + quint32 line, quint32 column, bool must = true) { + QString msg = QStringLiteral("qmllint output:\n%1\nIt %2 contain '%3'") + .arg(QString::fromUtf8( + QJsonDocument(warnings).toJson(QJsonDocument::Indented)), + must ? u"must" : u"must NOT", substring); + if (line != 0 || column != 0) + msg += u" (%1:%2)"_s.arg(line).arg(column); + + return msg; + }; + + if (shouldContain == StringContained) { + if (!contains) + qWarning().noquote() << toDescription(warnings, substring, line, column); + QVERIFY(contains); + } else { + if (contains) + qWarning().noquote() << toDescription(warnings, substring, line, column, false); + QVERIFY(!contains); + } } void TestQmllint::requiredProperty() { - QVERIFY(runQmllint("requiredProperty.qml", true).isEmpty()); + runTest("requiredProperty.qml", Result::clean()); + + runTest("requiredMissingProperty.qml", + Result { { Message { QStringLiteral( + "Property \"foo\" was marked as required but does not exist.") } } }); + + runTest("requiredPropertyBindings.qml", Result::clean()); + runTest("requiredPropertyBindingsNow.qml", + Result { { Message { QStringLiteral("Component is missing required property " + "required_now_string from Base") }, + Message { QStringLiteral("Component is missing required property " + "required_defined_here_string from here") } } }); + runTest("requiredPropertyBindingsLater.qml", + Result { { Message { QStringLiteral("Component is missing required property " + "required_later_string from " + "Base") }, + Message { QStringLiteral("Property marked as required in Derived") }, + Message { QStringLiteral("Component is missing required property " + "required_even_later_string " + "from Base (marked as required by here)") } } }); +} + +void TestQmllint::settingsFile() +{ + QVERIFY(runQmllint("settings/unqualifiedSilent/unqualified.qml", true, QStringList(), false) + .isEmpty()); + QVERIFY(runQmllint("settings/unusedImportWarning/unused.qml", false, QStringList(), false) + .contains(QStringLiteral("Warning: %1:2:1: Unused import") + .arg(testFile("settings/unusedImportWarning/unused.qml")))); + QVERIFY(runQmllint("settings/bare/bare.qml", false, {}, false, false) + .contains(QStringLiteral("Failed to find the following builtins: " + "builtins.qmltypes, jsroot.qmltypes"))); + QVERIFY(runQmllint("settings/qmltypes/qmltypes.qml", false, QStringList(), false) + .contains(QStringLiteral("not a qmldir file. Assuming qmltypes."))); + QVERIFY(runQmllint("settings/qmlimports/qmlimports.qml", true, QStringList(), false).isEmpty()); +} + +void TestQmllint::additionalImplicitImport() +{ + // We're polluting the resource file system here, so let's clean up afterwards. + const auto guard = qScopeGuard([this]() {m_linter.clearCache(); }); + runTest("additionalImplicitImport.qml", Result::clean(), {}, {}, + { testFile("implicitImportResource.qrc") }); +} + +void TestQmllint::qrcUrlImport() +{ + const auto guard = qScopeGuard([this]() { m_linter.clearCache(); }); + + QJsonArray warnings; + callQmllint(testFile("untitled/main.qml"), true, &warnings, {}, {}, + { testFile("untitled/qrcUrlImport.qrc") }); + checkResult(warnings, Result::clean()); +} + +void TestQmllint::incorrectImportFromHost_data() +{ + QTest::addColumn<QString>("filename"); + QTest::addColumn<Result>("result"); + + QTest::newRow("NonexistentFile") + << QStringLiteral("importNonexistentFile.qml") + << Result{ { Message{ + QStringLiteral("File or directory you are trying to import does not exist"), + 1, 1 } } }; +#ifndef Q_OS_WIN + // there is no /dev/null device on Win + QTest::newRow("NullDevice") + << QStringLiteral("importNullDevice.qml") + << Result{ { Message{ QStringLiteral("is neither a file nor a directory. Are sure the " + "import path is correct?"), + 1, 1 } } }; +#endif +} + +void TestQmllint::incorrectImportFromHost() +{ + QFETCH(QString, filename); + QFETCH(Result, result); - const QString errors = runQmllint("requiredMissingProperty.qml", true); - QVERIFY(errors.contains(QStringLiteral("Property \"foo\" was marked as required but does not exist."))); + runTest(filename, result); } +void TestQmllint::attachedPropertyReuse() +{ + auto categories = QQmlJSLogger::defaultCategories(); + auto category = std::find_if(categories.begin(), categories.end(), [](const QQmlJS::LoggerCategory& category) { + return category.id() == qmlAttachedPropertyReuse; + }); + Q_ASSERT(category != categories.end()); + + category->setLevel(QtWarningMsg); + category->setIgnored(false); + runTest("attachedPropNotReused.qml", + Result { { Message { QStringLiteral("Using attached type QQuickKeyNavigationAttached " + "already initialized in a parent " + "scope") } } }, + {}, {}, {}, UseDefaultImports, &categories); + + runTest("attachedPropEnum.qml", Result::clean(), {}, {}, {}, UseDefaultImports, &categories); + runTest("MyStyle/ToolBar.qml", Result { + { + Message { + "Using attached type MyStyle already initialized in a parent scope"_L1, + 10, + 16 + } + }, + {}, + { + Message { + "Reference it by id instead"_L1, + 10, + 16 + } + }, + Result::AutoFixable + }); +} + +void TestQmllint::missingBuiltinsNoCrash() +{ + // We cannot use the normal linter here since the other tests might have cached the builtins + // alread + QQmlJSLinter linter(m_defaultImportPaths); + + QJsonArray jsonOutput; + QJsonArray warnings; + + bool success = linter.lintFile(testFile("missingBuiltinsNoCrash.qml"), nullptr, true, + &jsonOutput, {}, {}, {}, {}) + == QQmlJSLinter::LintSuccess; + QVERIFY2(!success, QJsonDocument(jsonOutput).toJson()); + + QVERIFY2(jsonOutput.size() == 1, QJsonDocument(jsonOutput).toJson()); + warnings = jsonOutput.at(0)[u"warnings"_s].toArray(); + + checkResult(warnings, + Result { { Message { QStringLiteral("Failed to find the following builtins: " + "builtins.qmltypes, jsroot.qmltypes") } } }); +} + +void TestQmllint::absolutePath() +{ + QString absPathOutput = runQmllint("memberNotFound.qml", false, {}, true, true, true); + QString relPathOutput = runQmllint("memberNotFound.qml", false, {}, true, true, false); + const QString absolutePath = QFileInfo(testFile("memberNotFound.qml")).absoluteFilePath(); + + QVERIFY(absPathOutput.contains(absolutePath)); + QVERIFY(!relPathOutput.contains(absolutePath)); +} + +void TestQmllint::importMultipartUri() +{ + runTest("here.qml", Result::clean(), {}, { testFile("Elsewhere/qmldir") }); +} + +void TestQmllint::lintModule_data() +{ + QTest::addColumn<QString>("module"); + QTest::addColumn<QStringList>("importPaths"); + QTest::addColumn<QStringList>("resources"); + QTest::addColumn<Result>("result"); + + QTest::addRow("Things") + << u"Things"_s + << QStringList() + << QStringList() + << Result { + { Message { + u"Type \"QPalette\" not found. Used in SomethingEntirelyStrange.palette"_s, + }, + Message { + u"Type \"CustomPalette\" is not fully resolved. Used in SomethingEntirelyStrange.palette2"_s } } + }; + QTest::addRow("missingQmltypes") + << u"Fake5Compat.GraphicalEffects.private"_s + << QStringList() + << QStringList() + << Result { { Message { u"QML types file does not exist"_s } } }; + + QTest::addRow("moduleWithQrc") + << u"moduleWithQrc"_s + << QStringList({ testFile("hidden") }) + << QStringList({ + testFile("hidden/qmake_moduleWithQrc.qrc"), + testFile("hidden/moduleWithQrc_raw_qml_0.qrc") + }) + << Result::clean(); +} + +void TestQmllint::lintModule() +{ + QFETCH(QString, module); + QFETCH(QStringList, importPaths); + QFETCH(QStringList, resources); + QFETCH(Result, result); + + QJsonArray warnings; + callQmllint(module, result.flags & Result::ExitsNormally, &warnings, importPaths, {}, resources, + UseDefaultImports, nullptr, false, LintModule); + checkResult(warnings, result); +} + +void TestQmllint::testLineEndings() +{ + { + const auto textWithLF = QString::fromUtf16(u"import QtQuick 2.0\nimport QtTest 2.0 // qmllint disable unused-imports\n" + "import QtTest 2.0 // qmllint disable\n\nItem {\n @Deprecated {}\n property string deprecated\n\n " + "property string a: root.a // qmllint disable unqualifi77777777777777777777777777777777777777777777777777777" + "777777777777777777777777777777777777ed\n property string b: root.a // qmllint di000000000000000000000000" + "000000000000000000inyyyyyyyyg c: root.a\n property string d: root.a\n // qmllint enable unqualified\n\n " + "//qmllint d 4isable\n property string e: root.a\n Component.onCompleted: {\n console.log" + "(deprecated);\n }\n // qmllint enable\n\n}\n"); + + const auto lintResult = m_linter.lintFile( {}, &textWithLF, true, nullptr, {}, {}, {}, {}); + + QCOMPARE(lintResult, QQmlJSLinter::LintResult::HasWarnings); + } + { + const auto textWithCRLF = QString::fromUtf16(u"import QtQuick 2.0\nimport QtTest 2.0 // qmllint disable unused-imports\n" + "import QtTest 2.0 // qmllint disable\n\nItem {\n @Deprecated {}\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r" + "\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\r\n property string deprecated\n\n property string a: root.a " + "// qmllint disable unqualifi77777777777777777777777777777777777777777777777777777777777777777777777777777777777777777ed\n " + "property string b: root.a // qmllint di000000000000000000000000000000000000000000inyyyyyyyyg c: root.a\n property string d: " + "root.a\n // qmllint enable unqualified\n\n //qmllint d 4isable\n property string e: root.a\n Component.onCompleted: " + "{\n console.log(deprecated);\n }\n // qmllint enable\n\n}\n"); + + const auto lintResult = m_linter.lintFile( {}, &textWithCRLF, true, nullptr, {}, {}, {}, {}); + + QCOMPARE(lintResult, QQmlJSLinter::LintResult::HasWarnings); + } +} + +void TestQmllint::valueTypesFromString() +{ + runTest("valueTypesFromString.qml", + Result{ { + Message{ + u"Binding is not supported: Type QSizeF should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s }, + Message{ + u"Binding is not supported: Type QRectF should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s }, + Message{ + u"Binding is not supported: Type QPointF should be constructed using QML_STRUCTURED_VALUE's construction mechanism, instead of a string."_s }, + }, + { /*bad messages */ }, + { + Message{ u"({ width: 30, height: 50 })"_s }, + Message{ u"({ x: 10, y: 20, width: 30, height: 50 })"_s }, + Message{ u"({ x: 30, y: 50 })"_s }, + } }); +} + +#if QT_CONFIG(library) +void TestQmllint::testPlugin() +{ + bool pluginFound = false; + for (const QQmlJSLinter::Plugin &plugin : m_linter.plugins()) { + if (plugin.name() == "testPlugin") { + pluginFound = true; + QCOMPARE(plugin.author(), u"Qt"_s); + QCOMPARE(plugin.description(), u"A test plugin for tst_qmllint"_s); + QCOMPARE(plugin.version(), u"1.0"_s); + break; + } + } + QVERIFY(pluginFound); + + runTest("elementpass_pluginTest.qml", Result { { Message { u"ElementTest OK"_s, 4, 5 } } }); + runTest("propertypass_pluginTest.qml", + Result { + { // Specific binding for specific property + Message { + u"Saw binding on Text property text with value NULL (and type 3) in scope Text"_s }, + + // Property on any type + Message { u"Saw read on Text property x in scope Text"_s }, + Message { + u"Saw binding on Text property x with value NULL (and type 2) in scope Text"_s }, + Message { u"Saw read on Text property x in scope Item"_s }, + Message { u"Saw write on Text property x with value int in scope Item"_s }, + Message { + u"Saw binding on Item property x with value NULL (and type 2) in scope Item"_s }, + // ListModel + Message { + u"Saw binding on ListView property model with value ListModel (and type 8) in scope ListView"_s }, + Message { + u"Saw binding on ListView property height with value NULL (and type 2) in scope ListView"_s } } }); + runTest("controlsWithQuick_pluginTest.qml", + Result { { Message { u"QtQuick.Controls, QtQuick and QtQuick.Window present"_s } } }); + runTest("controlsWithoutQuick_pluginTest.qml", + Result { { Message { u"QtQuick.Controls and NO QtQuick present"_s } } }); + // Verify that none of the passes do anything when they're not supposed to + runTest("nothing_pluginTest.qml", Result::clean()); + + QVERIFY(runQmllint("settings/plugin/elemenpass_pluginSettingTest.qml", true, QStringList(), false) + .isEmpty()); +} + +// TODO: Eventually tests for (real) plugins need to be moved into a separate file +void TestQmllint::quickPlugin() +{ + const auto &plugins = m_linter.plugins(); + + const bool pluginFound = + std::find_if(plugins.cbegin(), plugins.cend(), + [](const auto &plugin) { return plugin.name() == "Quick"; }) + != plugins.cend(); + QVERIFY(pluginFound); + + runTest("pluginQuick_anchors.qml", + Result{ { Message{ + u"Cannot specify left, right, and horizontalCenter anchors at the same time."_s }, + Message { + u"Cannot specify top, bottom, and verticalCenter anchors at the same time."_s }, + Message{ + u"Baseline anchor cannot be used in conjunction with top, bottom, or verticalCenter anchors."_s }, + Message { u"Cannot assign literal of type null to QQuickAnchorLine"_s, 5, + 35 }, + Message { u"Cannot assign literal of type null to QQuickAnchorLine"_s, 6, + 33 } } }); + runTest("pluginQuick_anchorsUndefined.qml", Result::clean()); + runTest("pluginQuick_layoutChildren.qml", + Result { + { Message { + u"Detected anchors on an item that is managed by a layout. This is undefined behavior; use Layout.alignment instead."_s }, + Message { + u"Detected x on an item that is managed by a layout. This is undefined behavior; use Layout.leftMargin or Layout.rightMargin instead."_s }, + Message { + u"Detected y on an item that is managed by a layout. This is undefined behavior; use Layout.topMargin or Layout.bottomMargin instead."_s }, + Message { + u"Detected height on an item that is managed by a layout. This is undefined behavior; use implictHeight or Layout.preferredHeight instead."_s }, + Message { + u"Detected width on an item that is managed by a layout. This is undefined behavior; use implicitWidth or Layout.preferredWidth instead."_s }, + Message { + u"Cannot specify anchors for items inside Grid. Grid will not function."_s }, + Message { + u"Cannot specify x for items inside Grid. Grid will not function."_s }, + Message { + u"Cannot specify y for items inside Grid. Grid will not function."_s }, + Message { + u"Cannot specify anchors for items inside Flow. Flow will not function."_s }, + Message { + u"Cannot specify x for items inside Flow. Flow will not function."_s }, + Message { + u"Cannot specify y for items inside Flow. Flow will not function."_s } } }); + runTest("pluginQuick_attached.qml", + Result { + { Message { u"ToolTip must be attached to an Item"_s }, + Message { u"SplitView attached property only works with Items"_s }, + Message { u"ScrollIndicator must be attached to a Flickable"_s }, + Message { u"ScrollBar must be attached to a Flickable or ScrollView"_s }, + Message { u"Accessible must be attached to an Item"_s }, + Message { u"EnterKey attached property only works with Items"_s }, + Message { + u"LayoutDirection attached property only works with Items and Windows"_s }, + Message { u"Layout must be attached to Item elements"_s }, + Message { u"StackView attached property only works with Items"_s }, + Message { u"TextArea must be attached to a Flickable"_s }, + Message { u"StackLayout must be attached to an Item"_s }, + Message { + u"Tumbler: attached properties of Tumbler must be accessed through a delegate item"_s }, + Message { + u"Attached properties of SwipeDelegate must be accessed through an Item"_s }, + Message { u"SwipeView must be attached to an Item"_s } } }); + + runTest("pluginQuick_swipeDelegate.qml", + Result { { + Message { + u"SwipeDelegate: Cannot use horizontal anchors with contentItem; unable to layout the item."_s, + 6, 43 }, + Message { + u"SwipeDelegate: Cannot use horizontal anchors with background; unable to layout the item."_s, + 7, 43 }, + Message { u"SwipeDelegate: Cannot set both behind and left/right properties"_s, + 9, 9 }, + Message { + u"SwipeDelegate: Cannot use horizontal anchors with contentItem; unable to layout the item."_s, + 13, 47 }, + Message { + u"SwipeDelegate: Cannot use horizontal anchors with background; unable to layout the item."_s, + 14, 42 }, + Message { u"SwipeDelegate: Cannot set both behind and left/right properties"_s, + 16, 9 }, + } }); + + runTest("pluginQuick_varProp.qml", + Result { + { Message { + u"Unexpected type for property \"contentItem\" expected QQuickPathView, QQuickListView got QQuickItem"_s }, + Message { + u"Unexpected type for property \"columnWidthProvider\" expected function got null"_s }, + Message { + u"Unexpected type for property \"textFromValue\" expected function got null"_s }, + Message { + u"Unexpected type for property \"valueFromText\" expected function got int"_s }, + Message { + u"Unexpected type for property \"rowHeightProvider\" expected function got int"_s } } }); + runTest("pluginQuick_varPropClean.qml", Result::clean()); + runTest("pluginQuick_attachedClean.qml", Result::clean()); + runTest("pluginQuick_attachedIgnore.qml", Result::clean()); + runTest("pluginQuick_noCrashOnUneresolved.qml", Result {}); // we don't care about the specific warnings + + runTest("pluginQuick_propertyChangesParsed.qml", + Result { { + Message { + u"Property \"myColor\" is custom-parsed in PropertyChanges. " + "You should phrase this binding as \"foo.myColor: Qt.rgba(0.5, ...\""_s, + 12, 30 + }, + Message { + u"You should remove any bindings on the \"target\" property and avoid " + "custom-parsed bindings in PropertyChanges."_s, + 11, 29 + }, + Message { + u"Unknown property \"notThere\" in PropertyChanges."_s, + 13, 31 + } + } }); + runTest("pluginQuick_propertyChangesInvalidTarget.qml", Result {}); // we don't care about the specific warnings +} + +void TestQmllint::environment_data() +{ + QTest::addColumn<QString>("file"); + QTest::addColumn<bool>("shouldSucceed"); + QTest::addColumn<QStringList>("extraArgs"); + QTest::addColumn<Environment>("env"); + QTest::addColumn<QString>("expectedWarning"); + + const QString fileThatNeedsImportPath = testFile(u"NeedImportPath.qml"_s); + const QString importPath = testFile(u"ImportPath"_s); + const QString invalidImportPath = testFile(u"ImportPathThatDoesNotExist"_s); + const QString noWarningExpected; + + QTest::addRow("missing-import-dir") + << fileThatNeedsImportPath << false << QStringList{} + << Environment{ { u"QML_IMPORT_PATH"_s, importPath } } << noWarningExpected; + + QTest::addRow("import-dir-via-arg") + << fileThatNeedsImportPath << true << QStringList{ u"-I"_s, importPath } + << Environment{ { u"QML_IMPORT_PATH"_s, invalidImportPath } } << noWarningExpected; + + QTest::addRow("import-dir-via-env") + << fileThatNeedsImportPath << true << QStringList{ u"-E"_s } + << Environment{ { u"QML_IMPORT_PATH"_s, importPath } } + << u"Using import directories passed from environment variable \"QML_IMPORT_PATH\": \"%1\"."_s + .arg(importPath); + + QTest::addRow("import-dir-via-env2") + << fileThatNeedsImportPath << true << QStringList{ u"-E"_s } + << Environment{ { u"QML2_IMPORT_PATH"_s, importPath } } + << u"Using import directories passed from the deprecated environment variable \"QML2_IMPORT_PATH\": \"%1\"."_s + .arg(importPath); +} + +void TestQmllint::environment() +{ + QFETCH(QString, file); + QFETCH(bool, shouldSucceed); + QFETCH(QStringList, extraArgs); + QFETCH(Environment, env); + QFETCH(QString, expectedWarning); + + const QString output = runQmllint(file, shouldSucceed, extraArgs, false, true, false, env); + if (!expectedWarning.isEmpty()) { + QVERIFY(output.contains(expectedWarning)); + } +} + +#endif + +void TestQmllint::ignoreSettingsNotCommandLineOptions() +{ + const QString importPath = testFile(u"ImportPath"_s); + // makes sure that ignore settings only ignores settings and not command line options like + // "-I". + const QString output = runQmllint(testFile(u"NeedImportPath.qml"_s), true, + QStringList{ u"-I"_s, importPath }, true); + // should not complain about not finding the module that is in importPath + QCOMPARE(output, QString()); +} -QTEST_MAIN(TestQmllint) +QTEST_GUILESS_MAIN(TestQmllint) #include "tst_qmllint.moc" |