qmllint: Properly handle JavaScript functions with variable arguments
Previously calling a JavaScript function with variable arguments could cause the linting process to error out because of a lack of matching function arguments. This is now handled by defaulting to a JavaScript method if no matching function signature can be found. Fixes: QTBUG-98299 Change-Id: I748a60839106243a12bffd8d715b48cbc53d7f57 Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
parent
3bb8ef28a7
commit
d8e73b588a
File diff suppressed because it is too large
Load Diff
|
@ -46,4 +46,5 @@ Member {
|
|||
property bool isConstructor: false
|
||||
property bool isList: false
|
||||
property bool isPointer: false
|
||||
property bool isJavaScriptFunction: false
|
||||
}
|
||||
|
|
|
@ -1228,6 +1228,7 @@ void QQmlJSImportVisitor::visitFunctionExpressionHelper(QQmlJS::AST::FunctionExp
|
|||
if (!name.isEmpty()) {
|
||||
QQmlJSMetaMethod method(name);
|
||||
method.setMethodType(QQmlJSMetaMethod::Method);
|
||||
method.setIsJavaScriptFunction(true);
|
||||
|
||||
if (!m_pendingMethodAnnotations.isEmpty()) {
|
||||
method.setAnnotations(m_pendingMethodAnnotations);
|
||||
|
|
|
@ -187,6 +187,12 @@ public:
|
|||
bool isConstructor() const { return m_isConstructor; }
|
||||
void setIsConstructor(bool isConstructor) { m_isConstructor = isConstructor; }
|
||||
|
||||
bool isJavaScriptFunction() const { return m_isJavaScriptFunction; }
|
||||
void setIsJavaScriptFunction(bool isJavaScriptFunction)
|
||||
{
|
||||
m_isJavaScriptFunction = isJavaScriptFunction;
|
||||
}
|
||||
|
||||
bool isValid() const { return !m_name.isEmpty(); }
|
||||
|
||||
const QVector<QQmlJSAnnotation>& annotations() const { return m_annotations; }
|
||||
|
@ -247,6 +253,7 @@ private:
|
|||
Access m_methodAccess = Private;
|
||||
int m_revision = 0;
|
||||
bool m_isConstructor = false;
|
||||
bool m_isJavaScriptFunction = false;
|
||||
};
|
||||
|
||||
class QQmlJSMetaProperty
|
||||
|
|
|
@ -312,6 +312,8 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bo
|
|||
metaMethod.setRevision(readIntBinding(script));
|
||||
} else if (name == QLatin1String("isConstructor")) {
|
||||
metaMethod.setIsConstructor(true);
|
||||
} else if (name == QLatin1String("isJavaScriptFunction")) {
|
||||
metaMethod.setIsJavaScriptFunction(true);
|
||||
} else if (name == QLatin1String("isList")) {
|
||||
// TODO: Theoretically this can happen. QQmlJSMetaMethod should store it.
|
||||
} else if (name == QLatin1String("isPointer")) {
|
||||
|
@ -320,8 +322,9 @@ void QQmlJSTypeDescriptionReader::readSignalOrMethod(UiObjectDefinition *ast, bo
|
|||
// description of the type being referenced has access semantics after all.
|
||||
} else {
|
||||
addWarning(script->firstSourceLocation(),
|
||||
tr("Expected only name, type, revision, isPointer, isList, and "
|
||||
"isConstructor in script bindings."));
|
||||
tr("Expected only name, type, revision, isPointer, isList, "
|
||||
"isConstructor, and "
|
||||
"isJavaScriptFunction in script bindings."));
|
||||
}
|
||||
} else {
|
||||
addWarning(member->firstSourceLocation(),
|
||||
|
|
|
@ -793,6 +793,7 @@ void QQmlJSTypePropagator::generate_CallProperty(int nameIndex, int base, int ar
|
|||
QQmlJSMetaMethod QQmlJSTypePropagator::bestMatchForCall(const QList<QQmlJSMetaMethod> &methods,
|
||||
int argc, int argv, QStringList *errors)
|
||||
{
|
||||
QQmlJSMetaMethod javascriptFunction;
|
||||
for (const auto &method : methods) {
|
||||
const auto argumentTypes = method.parameterTypes();
|
||||
if (argumentTypes.size() == 1
|
||||
|
@ -802,6 +803,10 @@ QQmlJSMetaMethod QQmlJSTypePropagator::bestMatchForCall(const QList<QQmlJSMetaMe
|
|||
continue;
|
||||
}
|
||||
|
||||
// If we encounter a JavaScript function, use this as a fallback if no other method matches
|
||||
if (method.isJavaScriptFunction())
|
||||
javascriptFunction = method;
|
||||
|
||||
if (argc != argumentTypes.size()) {
|
||||
errors->append(u"Function expects %1 arguments, but %2 were provided"_qs
|
||||
.arg(argumentTypes.size())
|
||||
|
@ -835,7 +840,7 @@ QQmlJSMetaMethod QQmlJSTypePropagator::bestMatchForCall(const QList<QQmlJSMetaMe
|
|||
if (matches)
|
||||
return method;
|
||||
}
|
||||
return QQmlJSMetaMethod();
|
||||
return javascriptFunction;
|
||||
}
|
||||
|
||||
void QQmlJSTypePropagator::propagateCall(const QList<QQmlJSMetaMethod> &methods, int argc, int argv)
|
||||
|
|
|
@ -262,6 +262,9 @@ void QmlTypesCreator::writeMethods(const QJsonArray &methods, const QString &typ
|
|||
const auto isConstructor = obj.find(QLatin1String("isConstructor"));
|
||||
if (isConstructor != obj.constEnd() && isConstructor->toBool())
|
||||
m_qml.writeScriptBinding(QLatin1String("isConstructor"), QLatin1String("true"));
|
||||
const auto isJavaScriptFunction = obj.find(QLatin1String("isJavaScriptFunction"));
|
||||
if (isJavaScriptFunction != obj.constEnd() && isJavaScriptFunction->toBool())
|
||||
m_qml.writeScriptBinding(QLatin1String("isJavaScriptFunction"), QLatin1String("true"));
|
||||
for (const QJsonValue argument : arguments) {
|
||||
const QJsonObject obj = argument.toObject();
|
||||
m_qml.writeStartObject(QLatin1String("Parameter"));
|
||||
|
|
|
@ -0,0 +1,9 @@
|
|||
import QtQml
|
||||
|
||||
QtObject {
|
||||
function varArgs() {}
|
||||
Component.onCompleted: {
|
||||
console.log("It works!");
|
||||
varArgs("This works", 2);
|
||||
}
|
||||
}
|
|
@ -89,6 +89,7 @@ private Q_SLOTS:
|
|||
void missingBuiltinsNoCrash();
|
||||
void absolutePath();
|
||||
void multiGrouped();
|
||||
void javascriptVariableArgs();
|
||||
|
||||
private:
|
||||
QString runQmllint(const QString &fileToLint, std::function<void(QProcess &)> handleResult,
|
||||
|
@ -1169,5 +1170,10 @@ void TestQmllint::multiGrouped()
|
|||
QVERIFY(runQmllint("multiGrouped.qml", true, {"--compiler=warning"}).isEmpty());
|
||||
}
|
||||
|
||||
void TestQmllint::javascriptVariableArgs()
|
||||
{
|
||||
QVERIFY(runQmllint("javascriptVariableArgs.qml", true, { "--compiler", "warning" }).isEmpty());
|
||||
}
|
||||
|
||||
QTEST_MAIN(TestQmllint)
|
||||
#include "tst_qmllint.moc"
|
||||
|
|
|
@ -250,6 +250,7 @@ static QString buildClass(const QJSManagedValue &value, QJsonArray *classes,
|
|||
|
||||
methodObject.insert(QStringLiteral("access"), QStringLiteral("public"));
|
||||
methodObject.insert(QStringLiteral("name"), info.name);
|
||||
methodObject.insert(QStringLiteral("isJavaScriptFunction"), true);
|
||||
|
||||
const int formalParams = propFunction->getLength();
|
||||
if (propFunction->isConstructor()) {
|
||||
|
|
Loading…
Reference in New Issue