aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorSami Shalayel <sami.shalayel@qt.io>2024-02-14 16:25:58 +0100
committerSami Shalayel <sami.shalayel@qt.io>2024-02-19 10:37:07 +0100
commitdb7267cd61a5ae094686726ee222e11fef08e977 (patch)
tree4a90077761ce138f8104477e052bf4ee967a10ae /tools
parent7cc3d8af146878c051baebe1342a84384d299583 (diff)
qmltc: warn about QML defined types from other modules
Add a warning for QML defined types imported from other modules in qmltcvisitor to avoid qmltc generating invalid C++ code. This requires populating the moduleName member of qqmljsscope where it was ignored: * for qmldir files imported via command line options * for inline components * for the file to be compiled The module name of the QML file to be compiled is passed from CMake to qmltc via a newly introduced command line argument, and is simulated in the tst_qmltc_qprocess tests. Pick-to: 6.5 6.6 6.7 Fixes: QTBUG-121592 Change-Id: I965d759a028546c648ccf6c9aa469b84538be446 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/qmltc/main.cpp13
-rw-r--r--tools/qmltc/qmltcvisitor.cpp34
-rw-r--r--tools/qmltc/qmltcvisitor.h2
3 files changed, 42 insertions, 7 deletions
diff --git a/tools/qmltc/main.cpp b/tools/qmltc/main.cpp
index 7c3bf3bacd..e88cae6bd7 100644
--- a/tools/qmltc/main.cpp
+++ b/tools/qmltc/main.cpp
@@ -99,6 +99,13 @@ int main(int argc, char **argv)
QCoreApplication::translate("main", "namespace")
};
parser.addOption(namespaceOption);
+ QCommandLineOption moduleOption{
+ u"module"_s,
+ QCoreApplication::translate("main",
+ "Name of the QML module that this QML code belongs to."),
+ QCoreApplication::translate("main", "module")
+ };
+ parser.addOption(moduleOption);
QCommandLineOption exportOption{ u"export"_s,
QCoreApplication::translate(
"main", "Export macro used in the generated C++ code"),
@@ -262,7 +269,11 @@ int main(int argc, char **argv)
logger.setCode(sourceCode);
setupLogger(logger);
- QmltcVisitor visitor(QQmlJSScope::create(), &importer, &logger,
+ auto currentScope = QQmlJSScope::create();
+ if (parser.isSet(moduleOption))
+ currentScope->setModuleName(parser.value(moduleOption));
+
+ QmltcVisitor visitor(currentScope, &importer, &logger,
QQmlJSImportVisitor::implicitImportDirectory(url, &mapper), qmldirFiles);
visitor.setMode(QmltcVisitor::Compile);
QmltcTypeResolver typeResolver { &importer };
diff --git a/tools/qmltc/qmltcvisitor.cpp b/tools/qmltc/qmltcvisitor.cpp
index 88ec451891..95cb280c4d 100644
--- a/tools/qmltc/qmltcvisitor.cpp
+++ b/tools/qmltc/qmltcvisitor.cpp
@@ -338,7 +338,7 @@ void QmltcVisitor::endVisit(QQmlJS::AST::UiProgram *program)
for (const QList<QQmlJSScope::ConstPtr> &qmlTypes : m_pureQmlTypes)
for (const QQmlJSScope::ConstPtr &type : qmlTypes)
- checkForNamingCollisionsWithCpp(type);
+ checkNamesAndTypes(type);
}
QQmlJSScope::ConstPtr fetchType(const QQmlJSMetaPropertyBinding &binding)
@@ -655,7 +655,7 @@ void QmltcVisitor::setupAliases()
}
}
-void QmltcVisitor::checkForNamingCollisionsWithCpp(const QQmlJSScope::ConstPtr &type)
+void QmltcVisitor::checkNamesAndTypes(const QQmlJSScope::ConstPtr &type)
{
static const QString cppKeywords[] = {
u"alignas"_s,
@@ -772,6 +772,23 @@ void QmltcVisitor::checkForNamingCollisionsWithCpp(const QQmlJSScope::ConstPtr &
qmlCompiler, type->sourceLocation());
};
+ const auto validateType = [&type, this](const QQmlJSScope::ConstPtr &typeToCheck,
+ QStringView name, QStringView errorPrefix) {
+ if (type->moduleName().isEmpty() || typeToCheck.isNull())
+ return;
+
+ if (typeToCheck->isComposite() && typeToCheck->moduleName() != type->moduleName()) {
+ m_logger->log(
+ QStringLiteral(
+ "Can't compile the %1 type \"%2\" to C++ because it "
+ "lives in \"%3\" instead of the current file's \"%4\" QML module.")
+ .arg(errorPrefix, name, typeToCheck->moduleName(), type->moduleName()),
+ qmlCompiler, type->sourceLocation());
+ }
+ };
+
+ validateType(type->baseType(), type->baseTypeName(), u"QML base");
+
const auto enums = type->ownEnumerations();
for (auto it = enums.cbegin(); it != enums.cend(); ++it) {
const QQmlJSMetaEnum e = it.value();
@@ -786,16 +803,23 @@ void QmltcVisitor::checkForNamingCollisionsWithCpp(const QQmlJSScope::ConstPtr &
for (auto it = properties.cbegin(); it != properties.cend(); ++it) {
const QQmlJSMetaProperty &p = it.value();
validate(p.propertyName(), u"Property");
+
+ if (!p.isAlias() && !p.typeName().isEmpty())
+ validateType(p.type(), p.typeName(), u"QML property");
}
const auto methods = type->ownMethods();
for (auto it = methods.cbegin(); it != methods.cend(); ++it) {
const QQmlJSMetaMethod &m = it.value();
validate(m.methodName(), u"Method");
+ if (!m.returnTypeName().isEmpty())
+ validateType(m.returnType(), m.returnTypeName(), u"QML method return");
- const auto parameterNames = m.parameterNames();
- for (const auto &name : parameterNames)
- validate(name, u"Method '%1' parameter"_s.arg(m.methodName()));
+ for (const auto &parameter : m.parameters()) {
+ validate(parameter.name(), u"Method '%1' parameter"_s.arg(m.methodName()));
+ if (!parameter.typeName().isEmpty())
+ validateType(parameter.type(), parameter.typeName(), u"QML parameter");
+ }
}
// TODO: one could also test signal handlers' parameters but we do not store
diff --git a/tools/qmltc/qmltcvisitor.h b/tools/qmltc/qmltcvisitor.h
index c7d2990848..111df0e885 100644
--- a/tools/qmltc/qmltcvisitor.h
+++ b/tools/qmltc/qmltcvisitor.h
@@ -22,7 +22,7 @@ class QmltcVisitor : public QQmlJSImportVisitor
void postVisitResolve(const QHash<QQmlJSScope::ConstPtr, QList<QQmlJSMetaPropertyBinding>>
&qmlIrOrderedBindings);
void setupAliases();
- void checkForNamingCollisionsWithCpp(const QQmlJSScope::ConstPtr &type);
+ void checkNamesAndTypes(const QQmlJSScope::ConstPtr &type);
void setRootFilePath();
QString sourceDirectoryPath(const QString &path);