qmltc: Don't re-check headers for their suffix

qmltyperegistrar already does that and warns about suspicious headers.
Allowing only ".h" is overly restrictive.

Since qmltc uses the .h suffix also to mark scopes it has pre-processed,
we need to drop the preprocessing and determine the path names on the
fly when writing the includes.

Pick-to: 6.8
Fixes: QTBUG-125959
Change-Id: If68431ca92fd6625ca77beb6b00a460c43c987e5
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Ulf Hermann 2024-07-02 08:45:00 +02:00
parent 265ae27a3c
commit 0f15921006
7 changed files with 52 additions and 22 deletions

View File

@ -24,6 +24,7 @@ set(cpp_sources
cpptypes/typewithsignal.h
cpptypes/custominitialization.h
cpptypes/typewithrequiredproperties.h
cpptypes/hpp.hpp
)
set(qml_sources
@ -137,6 +138,8 @@ set(qml_sources
badFile.qml
requiredProperties.qml
hpp.qml
)
set(js_sources

View File

@ -0,0 +1,15 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
#ifndef HPP_HPP
#define HPP_HPP
#include <QtQml/qqml.h>
class Hpp : public QObject
{
Q_OBJECT
QML_ELEMENT
};
#endif // HPP_HPP

View File

@ -0,0 +1,8 @@
// Copyright (C) 2024 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
import QmltcTests 1.0
Hpp {
objectName: "hpp"
}

View File

@ -92,6 +92,8 @@
#include "signalconnections.h"
#include "requiredproperties.h"
#include "hpp.h"
// Qt:
#include <QtCore/qstring.h>
#include <QtCore/qbytearray.h>
@ -3396,4 +3398,11 @@ void tst_qmltc::signalConnections()
QCOMPARE(createdByQmltc.objectName(), QLatin1String("second"));
}
void tst_qmltc::hpp()
{
QQmlEngine e;
PREPEND_NAMESPACE(hpp) createdByQmltc(&e);
QCOMPARE(createdByQmltc.objectName(), QLatin1String("hpp"));
}
QTEST_MAIN(tst_qmltc)

View File

@ -105,4 +105,6 @@ private slots:
#endif
void urlToString();
void signalConnections();
void hpp();
};

View File

@ -89,7 +89,7 @@ void QmltcVisitor::findCppIncludes()
return false;
};
const auto addCppInclude = [this](const QQmlJSScope::ConstPtr &type) {
if (QString includeFile = type->filePath(); includeFile.endsWith(u".h"))
if (QString includeFile = filePath(type); !includeFile.isEmpty())
m_cppIncludes.insert(std::move(includeFile));
};
@ -151,8 +151,8 @@ void QmltcVisitor::findCppIncludes()
for (const QQmlJSMetaProperty &p : properties) {
findInType(p.type());
if (p.isPrivate() && t->filePath().endsWith(u".h")) {
const QString ownersInclude = t->filePath();
if (p.isPrivate()) {
const QString ownersInclude = filePath(t);
QString privateInclude = constructPrivateInclude(ownersInclude);
if (!privateInclude.isEmpty())
m_cppIncludes.insert(std::move(privateInclude));
@ -174,7 +174,7 @@ void QmltcVisitor::findCppIncludes()
}
// remove own include
m_cppIncludes.remove(m_exportedRootScope->filePath());
m_cppIncludes.remove(filePath(m_exportedRootScope));
}
static void addCleanQmlTypeName(QStringList *names, const QQmlJSScope::ConstPtr &scope)
@ -191,16 +191,9 @@ static void addCleanQmlTypeName(QStringList *names, const QQmlJSScope::ConstPtr
bool QmltcVisitor::visit(QQmlJS::AST::UiObjectDefinition *object)
{
const bool processingRoot = !rootScopeIsValid();
if (!QQmlJSImportVisitor::visit(object))
return false;
if (processingRoot || m_currentScope->isInlineComponent()) {
Q_ASSERT(rootScopeIsValid());
setRootFilePath();
}
// we're not interested in non-QML scopes
if (m_currentScope->scopeType() != QQmlSA::ScopeType::QMLScope)
return true;
@ -831,14 +824,14 @@ void QmltcVisitor::checkNamesAndTypes(const QQmlJSScope::ConstPtr &type)
}
/*! \internal
* Sets the file paths for the document and the inline components roots.
* Returns the file path for the C++ header of \a scope or the header created
* by qmltc for it and its inline components.
*/
void QmltcVisitor::setRootFilePath()
QString QmltcVisitor::filePath(const QQmlJSScope::ConstPtr &scope) const
{
const QString filePath = m_currentScope->filePath();
if (filePath.endsWith(u".h")) // assume the correct path is set
return;
Q_ASSERT(filePath.endsWith(u".qml"_s));
const QString filePath = scope->filePath();
if (!filePath.endsWith(u".qml")) // assume the correct path is set
return scope->filePath();
const QString correctedFilePath = sourceDirectoryPath(filePath);
const QStringList paths = m_importer->resourceFileMapper()->resourcePaths(
@ -850,13 +843,13 @@ void QmltcVisitor::setRootFilePath()
qCDebug(lcQmltcCompiler,
"Failed to find a header file name for path %s. Paths checked:\n%s",
correctedFilePath.toUtf8().constData(), matchedPaths.toUtf8().constData());
return;
return QString();
}
// NB: get the file name to avoid prefixes
m_currentScope->setFilePath(QFileInfo(*firstHeader).fileName());
return QFileInfo(*firstHeader).fileName();
}
QString QmltcVisitor::sourceDirectoryPath(const QString &path)
QString QmltcVisitor::sourceDirectoryPath(const QString &path) const
{
auto result = QQmlJSUtils::sourceDirectoryPath(m_importer, path);
if (const QString *srcDirPath = std::get_if<QString>(&result))

View File

@ -23,9 +23,9 @@ class QmltcVisitor : public QQmlJSImportVisitor
&qmlIrOrderedBindings);
void setupAliases();
void checkNamesAndTypes(const QQmlJSScope::ConstPtr &type);
void setRootFilePath();
QString filePath(const QQmlJSScope::ConstPtr &scope) const;
QString sourceDirectoryPath(const QString &path);
QString sourceDirectoryPath(const QString &path) const;
using InlineComponentOrDocumentRootName = QQmlJSScope::InlineComponentOrDocumentRootName;