aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMaximilian Goldstein <max.goldstein@qt.io>2021-12-14 13:23:32 +0100
committerMaximilian Goldstein <max.goldstein@qt.io>2021-12-17 12:43:14 +0100
commit687609f2f3a98ade4b8e074615c3d1db1228fce0 (patch)
tree4d5ed39c9ea5087cb4868315e826ea9869c32dee
parentb9dba49d57338df0335912f9c6db627404af149d (diff)
Move QObject and QQmlComponent into builtins
Previously we had two versions of QObject and QQmlComponent: a hand-written version in bultins and one that is generated from QtQml. We now move the QtQml version into builtins in order to allow for representing the JavaScript extensions that are present in these types. We also add some logic so that unused types will still react properly despite the fact that those components are no longer in QtQml. This is done by introducing the concept of static modules. These are modules that have side effects beyond simply provinding components. This applies both to when some components are in builtins instead of QtQml or when the global object is modified in some way (i.e. by adding an image provider). This is a tooling-only concept and does not affect how these modules are handled at runtime. Fixes: QTBUG-99025 Change-Id: Ifacaa836e4d2eef0521494f5a41363e053c90007 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
-rw-r--r--src/imports/builtins/builtins.qmltypes101
-rw-r--r--src/labs/sharedimage/CMakeLists.txt1
-rw-r--r--src/qml/CMakeLists.txt1
-rw-r--r--src/qml/Qt6QmlBuildInternals.cmake2
-rw-r--r--src/qml/Qt6QmlMacros.cmake17
-rw-r--r--src/qml/qml/qqmlcomponent.h1
-rw-r--r--src/qml/qml/qqmlengine_p.h2
-rw-r--r--src/qml/qmldirparser/qqmldirparser.cpp10
-rw-r--r--src/qml/qmldirparser/qqmldirparser_p.h4
-rw-r--r--src/qmlcompiler/qqmljsimporter.cpp32
-rw-r--r--src/qmlcompiler/qqmljsimporter_p.h16
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor.cpp18
-rw-r--r--src/qmlcompiler/qqmljsimportvisitor_p.h2
-rw-r--r--src/qmltyperegistrar/qmltypesclassdescription.cpp5
-rw-r--r--src/qmltyperegistrar/qmltypesclassdescription.h2
-rw-r--r--src/qmltyperegistrar/qmltypescreator.cpp83
-rw-r--r--tests/auto/qml/qmllint/data/qobjectHasOwnProperty.qml7
-rw-r--r--tests/auto/qml/qmllint/data/unused_static.qml4
-rw-r--r--tests/auto/qml/qmllint/tst_qmllint.cpp2
19 files changed, 202 insertions, 108 deletions
diff --git a/src/imports/builtins/builtins.qmltypes b/src/imports/builtins/builtins.qmltypes
index 23defaa55b..0bc89d8c9c 100644
--- a/src/imports/builtins/builtins.qmltypes
+++ b/src/imports/builtins/builtins.qmltypes
@@ -23,61 +23,118 @@ Module {
}
Component {
+ file: "private/qqmlengine_p.h"
name: "QObject"
+ extension: "Object"
accessSemantics: "reference"
exports: ["QML/QtObject 1.0"]
exportMetaObjectRevisions: [256]
-
- Method {
- name: "toString"
+ Property {
+ name: "objectName"
type: "QString"
+ bindable: "bindableObjectName"
+ read: "objectName"
+ write: "setObjectName"
+ notify: "objectNameChanged"
+ index: 0
+ }
+ Signal {
+ name: "objectNameChanged"
+ Parameter { name: "objectName"; type: "QString" }
}
-
Method {
- name: "destroy"
+ name: "_q_reregisterTimers"
+ Parameter { type: "void"; isPointer: true }
}
-
+ Method { name: "toString"; type: "string" }
+ Method { name: "destroy" }
Method {
name: "destroy"
-
- Parameter {
- name: "delay"
- type: "int"
- }
+ Parameter { name: "delay"; type: "int" }
}
}
Component {
+ file: "qqmlcomponent.h"
name: "QQmlComponent"
accessSemantics: "reference"
prototype: "QObject"
exports: ["QML/Component 1.0"]
exportMetaObjectRevisions: [256]
-
+ attachedType: "QQmlComponentAttached"
+ Enum {
+ name: "CompilationMode"
+ values: ["PreferSynchronous", "Asynchronous"]
+ }
Enum {
name: "Status"
values: ["Null", "Ready", "Loading", "Error"]
}
-
+ Property {
+ name: "progress"
+ type: "double"
+ read: "progress"
+ notify: "progressChanged"
+ index: 0
+ isReadonly: true
+ }
Property {
name: "status"
type: "Status"
+ read: "status"
+ notify: "statusChanged"
+ index: 1
isReadonly: true
}
-
+ Property { name: "url"; type: "QUrl"; read: "url"; index: 2; isReadonly: true }
Signal {
name: "statusChanged"
-
- Parameter {
- type: "QQmlComponent::Status"
- }
-
+ Parameter { type: "QQmlComponent::Status" }
+ }
+ Signal {
+ name: "progressChanged"
+ Parameter { type: "double" }
}
-
Method {
- name: "errorString"
- type: "QString"
+ name: "loadUrl"
+ Parameter { name: "url"; type: "QUrl" }
+ }
+ Method {
+ name: "loadUrl"
+ Parameter { name: "url"; type: "QUrl" }
+ Parameter { name: "mode"; type: "CompilationMode" }
+ }
+ Method {
+ name: "setData"
+ Parameter { type: "QByteArray" }
+ Parameter { name: "baseUrl"; type: "QUrl" }
}
+ Method { name: "errorString"; type: "QString" }
+ Method { name: "createObject"; isJavaScriptFunction: true }
+ Method {
+ name: "createObject"
+ type: "QObject"
+ isPointer: true
+ Parameter { name: "parent"; type: "QObject"; isPointer: true }
+ Parameter { name: "properties"; type: "QVariantMap" }
+ }
+ Method {
+ name: "createObject"
+ type: "QObject"
+ isPointer: true
+ Parameter { name: "parent"; type: "QObject"; isPointer: true }
+ }
+ Method { name: "createObject"; type: "QObject"; isPointer: true }
+ Method { name: "incubateObject"; isJavaScriptFunction: true }
+ }
+
+ Component {
+ file: "private/qqmlcomponentattached_p.h"
+ name: "QQmlComponentAttached"
+ accessSemantics: "reference"
+ prototype: "QObject"
+ Signal { name: "completed" }
+ Signal { name: "destruction" }
}
Component {
diff --git a/src/labs/sharedimage/CMakeLists.txt b/src/labs/sharedimage/CMakeLists.txt
index 0dec607ac2..5acfb3dddf 100644
--- a/src/labs/sharedimage/CMakeLists.txt
+++ b/src/labs/sharedimage/CMakeLists.txt
@@ -1,6 +1,7 @@
qt_internal_add_qml_module(LabsSharedImage
URI "Qt.labs.sharedimage"
VERSION "${PROJECT_VERSION}"
+ __QT_INTERNAL_STATIC_MODULE
PLUGIN_TARGET sharedimageplugin
NO_PLUGIN_OPTIONAL
NO_GENERATE_PLUGIN_SOURCE
diff --git a/src/qml/CMakeLists.txt b/src/qml/CMakeLists.txt
index 046e29fdcd..3c08c6f9c5 100644
--- a/src/qml/CMakeLists.txt
+++ b/src/qml/CMakeLists.txt
@@ -32,6 +32,7 @@ qt_internal_add_qml_module(Qml
URI "QtQml"
VERSION "${PROJECT_VERSION}"
DESIGNER_SUPPORTED
+ __QT_INTERNAL_SYSTEM_MODULE
PLUGIN_TARGET qmlplugin
CLASS_NAME QtQmlPlugin
IMPORTS ${module_dynamic_qml_imports}
diff --git a/src/qml/Qt6QmlBuildInternals.cmake b/src/qml/Qt6QmlBuildInternals.cmake
index 4b6a144b0e..13cc64cad7 100644
--- a/src/qml/Qt6QmlBuildInternals.cmake
+++ b/src/qml/Qt6QmlBuildInternals.cmake
@@ -18,6 +18,8 @@ macro(qt_internal_get_internal_add_qml_module_keywords
NO_GENERATE_QMLDIR
NO_LINT
NO_CACHEGEN
+ __QT_INTERNAL_STATIC_MODULE
+ __QT_INTERNAL_SYSTEM_MODULE
)
set(${single_args}
URI
diff --git a/src/qml/Qt6QmlMacros.cmake b/src/qml/Qt6QmlMacros.cmake
index e2bef207d3..d3e9ac0e03 100644
--- a/src/qml/Qt6QmlMacros.cmake
+++ b/src/qml/Qt6QmlMacros.cmake
@@ -32,6 +32,11 @@ function(qt6_add_qml_module target)
# Used only by _qt_internal_qml_type_registration()
# TODO: Remove this once qt6_extract_metatypes does not install by default.
__QT_INTERNAL_INSTALL_METATYPES_JSON
+
+ # Used to mark modules as having static side effects (i.e. if they install an image provider)
+ __QT_INTERNAL_STATIC_MODULE
+ # Used to mark modules as being a system module that provides all builtins
+ __QT_INTERNAL_SYSTEM_MODULE
)
set(args_single
@@ -453,6 +458,8 @@ function(qt6_add_qml_module target)
_qt_qml_module_installed_plugin_target "${arg_INSTALLED_PLUGIN_TARGET}"
QT_QML_MODULE_DESIGNER_SUPPORTED "${arg_DESIGNER_SUPPORTED}"
+ QT_QML_MODULE_IS_STATIC "${arg___QT_INTERNAL_STATIC_MODULE}"
+ QT_QML_MODULE_IS_SYSTEM "${arg___QT_INTERNAL_SYSTEM_MODULE}"
QT_QML_MODULE_OUTPUT_DIRECTORY "${arg_OUTPUT_DIRECTORY}"
QT_QML_MODULE_RESOURCE_PREFIX "${qt_qml_module_resource_prefix}"
QT_QML_MODULE_PAST_MAJOR_VERSIONS "${arg_PAST_MAJOR_VERSIONS}"
@@ -954,6 +961,16 @@ function(_qt_internal_target_generate_qmldir target)
string(APPEND content "designersupported\n")
endif()
+ get_target_property(static_module ${target} QT_QML_MODULE_IS_STATIC)
+ if (static_module)
+ string(APPEND content "static\n")
+ endif()
+
+ get_target_property(system_module ${target} QT_QML_MODULE_IS_SYSTEM)
+ if (system_module)
+ string(APPEND content "system\n")
+ endif()
+
_qt_internal_qmldir_item(typeinfo QT_QML_MODULE_TYPEINFO)
_qt_internal_qmldir_item_list(import QT_QML_MODULE_IMPORTS)
diff --git a/src/qml/qml/qqmlcomponent.h b/src/qml/qml/qqmlcomponent.h
index d60c2cdc9f..e70dae5de8 100644
--- a/src/qml/qml/qqmlcomponent.h
+++ b/src/qml/qml/qqmlcomponent.h
@@ -73,6 +73,7 @@ class Q_QML_EXPORT QQmlComponent : public QObject
QML_NAMED_ELEMENT(Component)
QML_ADDED_IN_VERSION(2, 0)
QML_ATTACHED(QQmlComponentAttached)
+ Q_CLASSINFO("QML.OmitFromQmlTypes", "true")
public:
enum CompilationMode { PreferSynchronous, Asynchronous };
diff --git a/src/qml/qml/qqmlengine_p.h b/src/qml/qml/qqmlengine_p.h
index 630d32736b..58bc61dcf0 100644
--- a/src/qml/qml/qqmlengine_p.h
+++ b/src/qml/qml/qqmlengine_p.h
@@ -96,7 +96,7 @@ struct QObjectForeign {
QML_FOREIGN(QObject)
QML_NAMED_ELEMENT(QtObject)
QML_ADDED_IN_VERSION(2, 0)
- Q_CLASSINFO("QML.Root", "QML")
+ Q_CLASSINFO("QML.OmitFromQmlTypes", "true")
};
// This needs to be declared here so that the pool for it can live in QQmlEnginePrivate.
diff --git a/src/qml/qmldirparser/qqmldirparser.cpp b/src/qml/qmldirparser/qqmldirparser.cpp
index 183fa918d2..bb9036582e 100644
--- a/src/qml/qmldirparser/qqmldirparser.cpp
+++ b/src/qml/qmldirparser/qqmldirparser.cpp
@@ -296,6 +296,16 @@ bool QQmlDirParser::parse(const QString &source)
reportError(lineNumber, 0, QStringLiteral("designersupported does not expect any argument"));
else
_designerSupported = true;
+ } else if (sections[0] == QLatin1String("static")) {
+ if (sectionCount != 1)
+ reportError(lineNumber, 0, QStringLiteral("static does not expect any argument"));
+ else
+ _isStaticModule = true;
+ } else if (sections[0] == QLatin1String("system")) {
+ if (sectionCount != 1)
+ reportError(lineNumber, 0, QStringLiteral("system does not expect any argument"));
+ else
+ _isSystemModule = true;
} else if (sections[0] == QLatin1String("import")
|| sections[0] == QLatin1String("depends")) {
if (!readImport(sections, sectionCount, Import::Default))
diff --git a/src/qml/qmldirparser/qqmldirparser_p.h b/src/qml/qmldirparser/qqmldirparser_p.h
index fe371e6b4f..51d4d75323 100644
--- a/src/qml/qmldirparser/qqmldirparser_p.h
+++ b/src/qml/qmldirparser/qqmldirparser_p.h
@@ -157,6 +157,8 @@ public:
QList<Script> scripts() const { return _scripts; }
QList<Plugin> plugins() const { return _plugins; }
bool designerSupported() const { return _designerSupported; }
+ bool isStaticModule() const { return _isStaticModule; }
+ bool isSystemModule() const { return _isSystemModule; }
QStringList typeInfos() const { return _typeInfos; }
QStringList classNames() const { return _classNames; }
@@ -177,6 +179,8 @@ private:
QList<Script> _scripts;
QList<Plugin> _plugins;
bool _designerSupported = false;
+ bool _isStaticModule = false;
+ bool _isSystemModule = false;
QStringList _typeInfos;
QStringList _classNames;
QString _linkTarget;
diff --git a/src/qmlcompiler/qqmljsimporter.cpp b/src/qmlcompiler/qqmljsimporter.cpp
index e14fa7a52d..757830448e 100644
--- a/src/qmlcompiler/qqmljsimporter.cpp
+++ b/src/qmlcompiler/qqmljsimporter.cpp
@@ -146,6 +146,9 @@ QQmlJSImporter::Import QQmlJSImporter::readQmldir(const QString &path)
{
Import result;
auto reader = createQmldirParserForFile(path + SlashQmldir);
+ result.name = reader.typeNamespace();
+ result.isStaticModule = reader.isStaticModule();
+ result.isSystemModule = reader.isSystemModule();
result.imports.append(reader.imports());
result.dependencies.append(reader.dependencies());
@@ -354,6 +357,14 @@ void QQmlJSImporter::processImport(const QQmlJSScope::Import &importDescription,
if (!importDescription.prefix().isEmpty())
types->qmlNames.insert(importDescription.prefix(), {}); // Empty type means "this is the prefix"
+ if (!importDescription.isDependency()) {
+ if (import.isStaticModule)
+ types->staticModules << import.name;
+
+ if (import.isSystemModule)
+ types->hasSystemModule = true;
+ }
+
for (auto it = import.scripts.begin(); it != import.scripts.end(); ++it) {
types->cppNames.insert(prefixedName(anonPrefix, internalName(it->scope)), it->scope);
// You cannot have a script without an export
@@ -520,10 +531,13 @@ void QQmlJSImporter::importQmldirs(const QStringList &qmldirFiles)
}
}
-QQmlJSImporter::ImportedTypes QQmlJSImporter::importModule(
- const QString &module, const QString &prefix, QTypeRevision version)
+QQmlJSImporter::ImportedTypes QQmlJSImporter::importModule(const QString &module,
+ const QString &prefix,
+ QTypeRevision version,
+ QStringList *staticModuleList)
{
- AvailableTypes result(builtinImportHelper().cppNames);
+ const AvailableTypes builtins = builtinImportHelper();
+ AvailableTypes result(builtins.cppNames);
if (!importHelper(module, &result, prefix, version)) {
m_warnings.append({
QStringLiteral("Failed to import %1. Are your include paths set up properly?").arg(module),
@@ -531,6 +545,16 @@ QQmlJSImporter::ImportedTypes QQmlJSImporter::importModule(
QQmlJS::SourceLocation()
});
}
+
+ // If we imported a system module add all builtin QML types
+ if (result.hasSystemModule) {
+ for (const QString &name : builtins.qmlNames.keys())
+ result.qmlNames.insert(prefixedName(prefix, name), builtins.qmlNames[name]);
+ }
+
+ if (staticModuleList)
+ *staticModuleList << result.staticModules;
+
return result.qmlNames;
}
@@ -558,6 +582,8 @@ bool QQmlJSImporter::importHelper(const QString &module, AvailableTypes *types,
const auto &cacheEntry = m_cachedImportTypes[cacheKey];
types->cppNames.insert(cacheEntry->cppNames);
+ types->staticModules << cacheEntry->staticModules;
+ types->hasSystemModule = cacheEntry->hasSystemModule;
// No need to import qml names for dependencies
if (!isDependency)
diff --git a/src/qmlcompiler/qqmljsimporter_p.h b/src/qmlcompiler/qqmljsimporter_p.h
index fdadcf6c3b..4cc22f4cfe 100644
--- a/src/qmlcompiler/qqmljsimporter_p.h
+++ b/src/qmlcompiler/qqmljsimporter_p.h
@@ -65,9 +65,9 @@ public:
QQmlJSScope::Ptr importFile(const QString &file);
ImportedTypes importDirectory(const QString &directory, const QString &prefix = QString());
- ImportedTypes importModule(
- const QString &module, const QString &prefix = QString(),
- QTypeRevision version = QTypeRevision());
+ ImportedTypes importModule(const QString &module, const QString &prefix = QString(),
+ QTypeRevision version = QTypeRevision(),
+ QStringList *staticModuleList = nullptr);
ImportedTypes builtinInternalNames();
@@ -97,9 +97,19 @@ private:
// Names the importing component sees, including any prefixes
QHash<QString, QQmlJSScope::ConstPtr> qmlNames;
+
+ // Static modules included here
+ QStringList staticModules;
+
+ // Whether a system module has been imported
+ bool hasSystemModule = false;
};
struct Import {
+ QString name;
+ bool isStaticModule;
+ bool isSystemModule;
+
QHash<QString, QQmlJSExportedScope> objects;
QHash<QString, QQmlJSExportedScope> scripts;
QList<QQmlDirParser::Import> imports;
diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp
index 6d7fe4807c..4efc722d5e 100644
--- a/src/qmlcompiler/qqmljsimportvisitor.cpp
+++ b/src/qmlcompiler/qqmljsimportvisitor.cpp
@@ -398,6 +398,9 @@ void QQmlJSImportVisitor::endVisit(UiProgram *)
break;
}
+ for (const QQmlJS::SourceLocation &import : m_importStaticModuleLocationMap.values())
+ unusedImports.remove(import);
+
for (const auto &import : unusedImports) {
m_logger->logInfo(QString::fromLatin1("Unused import at %1:%2:%3")
.arg(m_logger->fileName())
@@ -1715,13 +1718,26 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import)
}
path.chop(1);
+ QStringList staticModulesProvided;
+
const auto imported = m_importer->importModule(
- path, prefix, import->version ? import->version->version : QTypeRevision());
+ path, prefix, import->version ? import->version->version : QTypeRevision(),
+ &staticModulesProvided);
m_rootScopeImports.insert(imported);
for (const QString &key : imported.keys())
addImportLocation(key);
+ if (prefix.isEmpty()) {
+ for (const QString &staticModule : staticModulesProvided) {
+ // Always prefer a direct import of static module to it being imported as a dependency
+ if (path != staticModule && m_importStaticModuleLocationMap.contains(staticModule))
+ continue;
+
+ m_importStaticModuleLocationMap[staticModule] = import->firstSourceLocation();
+ }
+ }
+
processImportWarnings(QStringLiteral("module \"%1\"").arg(path), import->firstSourceLocation());
return true;
}
diff --git a/src/qmlcompiler/qqmljsimportvisitor_p.h b/src/qmlcompiler/qqmljsimportvisitor_p.h
index c5175fac2a..5a5256a98c 100644
--- a/src/qmlcompiler/qqmljsimportvisitor_p.h
+++ b/src/qmlcompiler/qqmljsimportvisitor_p.h
@@ -167,6 +167,8 @@ protected:
// Maps all qmlNames to the source location of their import
QMultiHash<QString, QQmlJS::SourceLocation> m_importTypeLocationMap;
+ // Maps all static modules to the source location of their import
+ QMultiHash<QString, QQmlJS::SourceLocation> m_importStaticModuleLocationMap;
// Contains all import source locations (could be extracted from above but that is expensive)
QSet<QQmlJS::SourceLocation> m_importLocations;
// A set of all types that have been used during type resolution
diff --git a/src/qmltyperegistrar/qmltypesclassdescription.cpp b/src/qmltyperegistrar/qmltypesclassdescription.cpp
index 369b42fbd9..fb01a48013 100644
--- a/src/qmltyperegistrar/qmltypesclassdescription.cpp
+++ b/src/qmltyperegistrar/qmltypesclassdescription.cpp
@@ -180,8 +180,9 @@ void QmlTypesClassDescription::collect(
isSingleton = true;
} else if (name == QLatin1String("QML.Foreign")) {
foreignTypeName = value;
- } else if (name == QLatin1String("QML.Root")) {
- isRootClass = true;
+ } else if (name == QLatin1String("QML.OmitFromQmlTypes")) {
+ if (value == QLatin1String("true"))
+ omitFromQmlTypes = true;
} else if (name == QLatin1String("QML.HasCustomParser")) {
if (value == QLatin1String("true"))
hasCustomParser = true;
diff --git a/src/qmltyperegistrar/qmltypesclassdescription.h b/src/qmltyperegistrar/qmltypesclassdescription.h
index 10470a1644..000ff2b0da 100644
--- a/src/qmltyperegistrar/qmltypesclassdescription.h
+++ b/src/qmltyperegistrar/qmltypesclassdescription.h
@@ -53,8 +53,8 @@ struct QmlTypesClassDescription
QTypeRevision removedInRevision;
bool isCreatable = true;
bool isSingleton = false;
- bool isRootClass = false;
bool hasCustomParser = false;
+ bool omitFromQmlTypes = false;
QStringList implementsInterfaces;
QStringList deferredNames;
QStringList immediateNames;
diff --git a/src/qmltyperegistrar/qmltypescreator.cpp b/src/qmltyperegistrar/qmltypescreator.cpp
index d7eef3421c..bf74fa9ca2 100644
--- a/src/qmltyperegistrar/qmltypescreator.cpp
+++ b/src/qmltyperegistrar/qmltypescreator.cpp
@@ -336,89 +336,26 @@ static QJsonArray members(const QJsonObject *classDef,
void QmlTypesCreator::writeComponents()
{
- const QLatin1String nameKey("name");
const QLatin1String signalsKey("signals");
const QLatin1String enumsKey("enums");
const QLatin1String propertiesKey("properties");
const QLatin1String slotsKey("slots");
const QLatin1String methodsKey("methods");
- const QLatin1String accessKey("access");
- const QLatin1String typeKey("type");
- const QLatin1String returnTypeKey("returnType");
- const QLatin1String argumentsKey("arguments");
-
- const QLatin1String destroyedName("destroyed");
- const QLatin1String deleteLaterName("deleteLater");
- const QLatin1String toStringName("toString");
- const QLatin1String destroyName("destroy");
- const QLatin1String delayName("delay");
const QLatin1String signalElement("Signal");
const QLatin1String componentElement("Component");
const QLatin1String methodElement("Method");
- const QLatin1String publicAccess("public");
- const QLatin1String intType("int");
- const QLatin1String stringType("string");
-
- auto writeRootClass = [&](const QJsonObject *classDef) {
- // Hide destroyed() signals
- QJsonArray componentSignals = members(classDef, signalsKey, m_version);
- for (auto it = componentSignals.begin(); it != componentSignals.end();) {
- if (it->toObject().value(nameKey).toString() == destroyedName)
- it = componentSignals.erase(it);
- else
- ++it;
- }
- writeMethods(componentSignals, signalElement);
-
- // Hide deleteLater() methods
- QJsonArray componentMethods = members(classDef, methodsKey, m_version);
- const QJsonArray componentSlots = members(classDef, slotsKey, m_version);
- for (const QJsonValue componentSlot : componentSlots)
- componentMethods.append(componentSlot);
- for (auto it = componentMethods.begin(); it != componentMethods.end();) {
- if (it->toObject().value(nameKey).toString() == deleteLaterName)
- it = componentMethods.erase(it);
- else
- ++it;
- }
-
- // Add toString()
- QJsonObject toStringMethod;
- toStringMethod.insert(nameKey, toStringName);
- toStringMethod.insert(accessKey, publicAccess);
- toStringMethod.insert(returnTypeKey, stringType);
- componentMethods.append(toStringMethod);
-
- // Add destroy()
- QJsonObject destroyMethod;
- destroyMethod.insert(nameKey, destroyName);
- destroyMethod.insert(accessKey, publicAccess);
- componentMethods.append(destroyMethod);
-
- // Add destroy(int)
- QJsonObject destroyMethodWithArgument;
- destroyMethodWithArgument.insert(nameKey, destroyName);
- destroyMethodWithArgument.insert(accessKey, publicAccess);
- QJsonObject delayArgument;
- delayArgument.insert(nameKey, delayName);
- delayArgument.insert(typeKey, intType);
- QJsonArray destroyArguments;
- destroyArguments.append(delayArgument);
- destroyMethodWithArgument.insert(argumentsKey, destroyArguments);
- componentMethods.append(destroyMethodWithArgument);
-
- writeMethods(componentMethods, methodElement);
- };
-
for (const QJsonObject &component : m_ownTypes) {
- m_qml.writeStartObject(componentElement);
-
QmlTypesClassDescription collector;
collector.collect(&component, m_ownTypes, m_foreignTypes,
QmlTypesClassDescription::TopLevel, m_version);
+ if (collector.omitFromQmlTypes)
+ continue;
+
+ m_qml.writeStartObject(componentElement);
+
writeClassProperties(collector);
if (const QJsonObject *classDef = collector.resolvedClass) {
@@ -426,13 +363,9 @@ void QmlTypesCreator::writeComponents()
writeProperties(members(classDef, propertiesKey, m_version));
- if (collector.isRootClass) {
- writeRootClass(classDef);
- } else {
- writeMethods(members(classDef, signalsKey, m_version), signalElement);
- writeMethods(members(classDef, slotsKey, m_version), methodElement);
- writeMethods(members(classDef, methodsKey, m_version), methodElement);
- }
+ writeMethods(members(classDef, signalsKey, m_version), signalElement);
+ writeMethods(members(classDef, slotsKey, m_version), methodElement);
+ writeMethods(members(classDef, methodsKey, m_version), methodElement);
}
m_qml.writeEndObject();
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/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/tst_qmllint.cpp b/tests/auto/qml/qmllint/tst_qmllint.cpp
index 0e166b81f3..8963f3a5f1 100644
--- a/tests/auto/qml/qmllint/tst_qmllint.cpp
+++ b/tests/auto/qml/qmllint/tst_qmllint.cpp
@@ -895,6 +895,7 @@ void TestQmllint::cleanQmlCode_data()
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");
@@ -947,6 +948,7 @@ void TestQmllint::cleanQmlCode_data()
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");
}
void TestQmllint::cleanQmlCode()