aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFriedemann Kleint <Friedemann.Kleint@qt.io>2020-11-06 09:20:29 +0100
committerFriedemann Kleint <Friedemann.Kleint@qt.io>2020-11-09 15:49:19 +0000
commit3428efa5f69d321bcacdd106b0e724ab99bb63ed (patch)
tree2b53a24f83cefd95e2861e8594a0d37010dfe020
parentc2a9236fe970fc34fbb90757d4e8b562760cbc15 (diff)
shiboken6: Add a new parser for AddedFunction parameters
Observe' <' (templates), '{' (initializer lists), '[' (array dimensions) and '(' (initialization, function pointers) when splitting the parameter lists of added functions. Add a test. Change-Id: I8cdc135a2daceab5587c4b5545ed38f0a022b5f8 Reviewed-by: Christian Tismer <tismer@stackless.com>
-rw-r--r--sources/shiboken6/ApiExtractor/modifications.cpp110
-rw-r--r--sources/shiboken6/ApiExtractor/modifications_p.h67
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp42
-rw-r--r--sources/shiboken6/ApiExtractor/tests/testaddfunction.h2
4 files changed, 220 insertions, 1 deletions
diff --git a/sources/shiboken6/ApiExtractor/modifications.cpp b/sources/shiboken6/ApiExtractor/modifications.cpp
index 54b30f041..a370a2e03 100644
--- a/sources/shiboken6/ApiExtractor/modifications.cpp
+++ b/sources/shiboken6/ApiExtractor/modifications.cpp
@@ -27,6 +27,7 @@
****************************************************************************/
#include "modifications.h"
+#include "modifications_p.h"
#include "typedatabase.h"
#include "typesystem.h"
@@ -174,6 +175,115 @@ bool FunctionModification::setSignature(const QString &s, QString *errorMessage)
return true;
}
+// Helpers to split a parameter list of <add-function>, <declare-function>
+// (@ denoting names), like
+// "void foo(QList<X,Y> &@list@ = QList<X,Y>{1,2}, int @b@=5, ...)"
+namespace AddedFunctionParser {
+
+bool Argument::equals(const Argument &rhs) const
+{
+ return type == rhs.type && name == rhs.name && defaultValue == rhs.defaultValue;
+}
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const Argument &a)
+{
+ QDebugStateSaver saver(d);
+ d.noquote();
+ d.nospace();
+ d << "Argument(type=\"" << a.type << '"';
+ if (!a.name.isEmpty())
+ d << ", name=\"" << a.name << '"';
+ if (!a.defaultValue.isEmpty())
+ d << ", defaultValue=\"" << a.defaultValue << '"';
+ d << ')';
+ return d;
+}
+#endif // QT_NO_DEBUG_STREAM
+
+// Helper for finding the end of a function parameter, observing
+// nested template parameters or lists.
+static int parameterTokenEnd(int startPos, QStringView paramString)
+{
+ const int end = paramString.size();
+ int nestingLevel = 0;
+ for (int p = startPos; p < end; ++p) {
+ switch (paramString.at(p).toLatin1()) {
+ case ',':
+ if (nestingLevel == 0)
+ return p;
+ break;
+ case '<': // templates
+ case '{': // initializer lists of default values
+ case '(': // initialization, function pointers
+ case '[': // array dimensions
+ ++nestingLevel;
+ break;
+ case '>':
+ case '}':
+ case ')':
+ case ']':
+ --nestingLevel;
+ break;
+ }
+ }
+ return end;
+}
+
+// Split a function parameter list into string tokens containing one
+// parameters (including default value, etc).
+static QList<QStringView> splitParameterTokens(QStringView paramString)
+{
+ QList<QStringView> result;
+ int startPos = 0;
+ for ( ; startPos < paramString.size(); ) {
+ int end = parameterTokenEnd(startPos, paramString);
+ result.append(paramString.mid(startPos, end - startPos).trimmed());
+ startPos = end + 1;
+ }
+ return result;
+}
+
+// Split a function parameter list
+Arguments splitParameters(QStringView paramString, QString *errorMessage)
+{
+ Arguments result;
+ const QList<QStringView> tokens = splitParameterTokens(paramString);
+
+ for (const auto &t : tokens) {
+ Argument argument;
+ // Check defaultValue, "int @b@=5"
+ const int equalPos = t.lastIndexOf(QLatin1Char('='));
+ if (equalPos != -1) {
+ const int defaultValuePos = equalPos + 1;
+ argument.defaultValue =
+ t.mid(defaultValuePos, t.size() - defaultValuePos).trimmed().toString();
+ }
+ QString typeString = (equalPos != -1 ? t.left(equalPos) : t).trimmed().toString();
+ // Check @name@
+ const int atPos = typeString.indexOf(QLatin1Char('@'));
+ if (atPos != -1) {
+ const int namePos = atPos + 1;
+ const int nameEndPos = typeString.indexOf(QLatin1Char('@'), namePos);
+ if (nameEndPos == -1) {
+ if (errorMessage != nullptr) {
+ *errorMessage = QLatin1String("Mismatched @ in \"")
+ + paramString.toString() + QLatin1Char('"');
+ }
+ return {};
+ }
+ argument.name = typeString.mid(namePos, nameEndPos - namePos).trimmed();
+ typeString.remove(atPos, nameEndPos - atPos + 1);
+ }
+ argument.type = typeString.trimmed();
+ result.append(argument);
+ }
+
+ return result;
+}
+
+} // namespace AddedFunctionParser
+
// ---------------------- AddedFunction
static AddedFunction::TypeInfo parseType(const QString& signature,
diff --git a/sources/shiboken6/ApiExtractor/modifications_p.h b/sources/shiboken6/ApiExtractor/modifications_p.h
new file mode 100644
index 000000000..c8f18308e
--- /dev/null
+++ b/sources/shiboken6/ApiExtractor/modifications_p.h
@@ -0,0 +1,67 @@
+/****************************************************************************
+**
+** Copyright (C) 2020 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt for Python.
+**
+** $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$
+**
+****************************************************************************/
+
+#ifndef MODIFICATIONS_P_H
+#define MODIFICATIONS_P_H
+
+#include <QtCore/QList>
+#include <QtCore/QString>
+#include <QtCore/QStringView>
+
+QT_BEGIN_NAMESPACE
+class QDebug;
+QT_END_NAMESPACE
+
+// Helpers to split a parameter list of <add-function>, <declare-function>
+// in a separate header for testing purposes
+
+namespace AddedFunctionParser {
+
+struct Argument
+{
+ bool equals(const Argument &rhs) const;
+
+ QString type;
+ QString name;
+ QString defaultValue;
+};
+
+using Arguments = QList<Argument>;
+
+inline bool operator==(const Argument &a1, const Argument &a2) { return a1.equals(a2); }
+inline bool operator!=(const Argument &a1, const Argument &a2) { return !a1.equals(a2); }
+
+#ifndef QT_NO_DEBUG_STREAM
+QDebug operator<<(QDebug d, const Argument &a);
+#endif
+
+Arguments splitParameters(QStringView paramString, QString *errorMessage = nullptr);
+
+} // namespace AddedFunctionParser
+
+#endif // MODIFICATIONS_P_H
diff --git a/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp b/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp
index bacdd4906..ca10cbfc6 100644
--- a/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp
+++ b/sources/shiboken6/ApiExtractor/tests/testaddfunction.cpp
@@ -31,6 +31,7 @@
#include "testutil.h"
#include <abstractmetafunction.h>
#include <abstractmetalang.h>
+#include <modifications_p.h>
#include <typesystem.h>
void TestAddFunction::testParsingFuncNameAndConstness()
@@ -464,5 +465,44 @@ void TestAddFunction::testAddFunctionWithTemplateArg()
QCOMPARE(arg.type().instantiations().count(), 1);
}
-QTEST_APPLESS_MAIN(TestAddFunction)
+// Test splitting of <add-function> parameter lists.
+
+Q_DECLARE_METATYPE(AddedFunctionParser::Argument)
+
+using Arguments = AddedFunctionParser::Arguments;
+
+void TestAddFunction::testAddFunctionTypeParser_data()
+{
+ QTest::addColumn<QString>("parameterList");
+ QTest::addColumn<Arguments>("expected");
+
+ QTest::newRow("empty")
+ << QString() << Arguments{};
+
+ QTest::newRow("1-arg")
+ << QString::fromLatin1("int @a@=42")
+ << Arguments{{QLatin1String("int"), QLatin1String("a"), QLatin1String("42")}};
+
+ QTest::newRow("2-args")
+ << QString::fromLatin1("double @d@, int @a@=42")
+ << Arguments{{QLatin1String("double"), QLatin1String("d"), {}},
+ {QLatin1String("int"), QLatin1String("a"), QLatin1String("42")}};
+
+ QTest::newRow("template-var_args")
+ << QString::fromLatin1("const QList<X,Y> &@list@ = QList<X,Y>{1,2}, int @b@=5, ...")
+ << Arguments{{QLatin1String("const QList<X,Y> &"), QLatin1String("list"), QLatin1String("QList<X,Y>{1,2}")},
+ {QLatin1String("int"), QLatin1String("b"), QLatin1String("5")},
+ {QLatin1String("..."), {}, {}}};
+}
+void TestAddFunction::testAddFunctionTypeParser()
+{
+
+ QFETCH(QString, parameterList);
+ QFETCH(Arguments, expected);
+
+ const auto actual = AddedFunctionParser::splitParameters(parameterList);
+ QCOMPARE(actual, expected);
+}
+
+QTEST_APPLESS_MAIN(TestAddFunction)
diff --git a/sources/shiboken6/ApiExtractor/tests/testaddfunction.h b/sources/shiboken6/ApiExtractor/tests/testaddfunction.h
index d95f0ecfe..195633030 100644
--- a/sources/shiboken6/ApiExtractor/tests/testaddfunction.h
+++ b/sources/shiboken6/ApiExtractor/tests/testaddfunction.h
@@ -49,6 +49,8 @@ private slots:
void testModifyAddedFunction();
void testAddFunctionOnTypedef();
void testAddFunctionWithTemplateArg();
+ void testAddFunctionTypeParser_data();
+ void testAddFunctionTypeParser();
};
#endif