aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAndrei Golubev <andrei.golubev@qt.io>2022-01-27 16:29:39 +0100
committerQt Cherry-pick Bot <cherrypick_bot@qt-project.org>2022-01-31 20:45:29 +0000
commit3342e25c616588779ab80b37b5d91d983b5f9595 (patch)
treedf42994ee342f7b644f2101cfea3767b5bde60fb
parent9a975279977d0252e1d4031e02eb432ed55f41b4 (diff)
Improve the structure of the output generated by qmltc
Make an effort to separate user-visible APIs from internal code relevant to qmltc In the process of doing it, make tst_qmltc_examples::helloWorld() test less brittle by using QMap instead of QHash when dumping C++ member functions of the type. QHash does not guarantee that the keys are ordered while QMap does (via operator "<") Change-Id: I1495e1755d3fd77950acb3820ad2b9c5e3cdee33 Reviewed-by: Ulf Hermann <ulf.hermann@qt.io> (cherry picked from commit 0ad51325c7432c8a8da38580d26721455252e64f) Reviewed-by: Qt Cherry-pick Bot <cherrypick_bot@qt-project.org>
-rw-r--r--src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp2
-rw-r--r--tools/qmltc/prototype/codegenerator.cpp12
-rw-r--r--tools/qmltc/prototype/codegeneratorwriter.cpp101
-rw-r--r--tools/qmltc/prototype/qmlcompiler.h1
4 files changed, 81 insertions, 35 deletions
diff --git a/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
index ca1d438d2c..ddbf3baaaa 100644
--- a/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
+++ b/src/qml/doc/snippets/qmltc/special/HelloWorld.qml.cpp
@@ -67,6 +67,7 @@ class HelloWorld : public QObject
Q_OBJECT
QML_ELEMENT
Q_PROPERTY(QString hello WRITE setHello READ hello BINDABLE bindableHello)
+
public:
HelloWorld(QQmlEngine * engine, QObject * parent = nullptr);
@@ -74,7 +75,6 @@ public:
void setHello(const QString& hello_);
QString hello();
QBindable<QString> bindableHello();
-
Q_INVOKABLE void printHello(QString prefix, QString suffix);
signals:
diff --git a/tools/qmltc/prototype/codegenerator.cpp b/tools/qmltc/prototype/codegenerator.cpp
index f60c8b71f9..ff71db989b 100644
--- a/tools/qmltc/prototype/codegenerator.cpp
+++ b/tools/qmltc/prototype/codegenerator.cpp
@@ -880,6 +880,7 @@ void CodeGenerator::compileProperty(QQmlJSAotObject &current, const QQmlJSMetaPr
u""_qs);
setter.body << variableName + u".setValue(" + name + u"_);";
setter.body << u"emit " + compilationData.notify + u"();";
+ setter.userVisible = true;
current.functions.emplaceBack(setter);
mocPieces << u"WRITE"_qs << setter.name;
}
@@ -888,6 +889,7 @@ void CodeGenerator::compileProperty(QQmlJSAotObject &current, const QQmlJSMetaPr
getter.returnType = underlyingType;
getter.name = compilationData.read;
getter.body << u"return " + variableName + u".value();";
+ getter.userVisible = true;
current.functions.emplaceBack(getter);
mocPieces << u"READ"_qs << getter.name;
@@ -898,6 +900,7 @@ void CodeGenerator::compileProperty(QQmlJSAotObject &current, const QQmlJSMetaPr
bindable.name = compilationData.bindable;
bindable.body << u"return QBindable<" + underlyingType + u">(std::addressof(" + variableName
+ u"));";
+ bindable.userVisible = true;
current.functions.emplaceBack(bindable);
mocPieces << u"BINDABLE"_qs << bindable.name;
}
@@ -1050,6 +1053,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject &current, const QQmlJSMetaPrope
getter.body += prologue;
getter.body << u"return " + info.readLine + u";";
// getter.body += writeSpecificEpilogue;
+ getter.userVisible = true;
current.functions.emplaceBack(getter);
mocLines << u"READ"_qs << getter.name;
} // else always an error?
@@ -1082,6 +1086,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject &current, const QQmlJSMetaPrope
setter.body << info.writeLine + u";";
}
setter.body += writeSpecificEpilogue;
+ setter.userVisible = true;
current.functions.emplaceBack(setter);
mocLines << u"WRITE"_qs << setter.name;
}
@@ -1093,6 +1098,7 @@ void CodeGenerator::compileAlias(QQmlJSAotObject &current, const QQmlJSMetaPrope
bindable.name = compilationData.bindable;
bindable.body += prologue;
bindable.body << u"return " + info.bindableLine + u";";
+ bindable.userVisible = true;
current.functions.emplaceBack(bindable);
mocLines << u"BINDABLE"_qs << bindable.name;
}
@@ -1154,8 +1160,12 @@ void CodeGenerator::compileMethod(QQmlJSAotObject &current, const QQmlJSMetaMeth
compiled.body = std::move(code);
compiled.type = methodType;
compiled.access = m.access();
- if (methodType != QQmlJSMetaMethod::Signal)
+ if (methodType != QQmlJSMetaMethod::Signal) {
compiled.declPreambles << u"Q_INVOKABLE"_qs; // TODO: do we need this for signals as well?
+ compiled.userVisible = m.access() == QQmlJSMetaMethod::Public;
+ } else {
+ compiled.userVisible = !m.isImplicitQmlPropertyChangeSignal();
+ }
current.functions.emplaceBack(compiled);
}
diff --git a/tools/qmltc/prototype/codegeneratorwriter.cpp b/tools/qmltc/prototype/codegeneratorwriter.cpp
index 13b8adb301..d43a94084e 100644
--- a/tools/qmltc/prototype/codegeneratorwriter.cpp
+++ b/tools/qmltc/prototype/codegeneratorwriter.cpp
@@ -32,6 +32,7 @@
#include <QtCore/qfileinfo.h>
#include <utility>
+#include <functional>
static constexpr char16_t newLine[] =
#ifdef Q_OS_WIN32
@@ -176,6 +177,25 @@ static QString classString(const QQmlJSAotObject &compiled)
return str;
}
+template<typename Predicate>
+static void dumpFunctions(GeneratedCodeUtils &code, const QList<QQmlJSAotMethod> &functions,
+ Predicate pred)
+{
+ // functions are _ordered_ by access and kind. ordering is important to
+ // provide consistent output
+ QMap<QString, QList<const QQmlJSAotMethod *>> orderedFunctions;
+ for (const auto &function : functions) {
+ if (pred(function))
+ orderedFunctions[getFunctionCategory(function)].append(std::addressof(function));
+ }
+
+ for (auto it = orderedFunctions.cbegin(); it != orderedFunctions.cend(); ++it) {
+ code.appendToHeader(it.key() + u":", -1);
+ for (const QQmlJSAotMethod *function : qAsConst(it.value()))
+ CodeGeneratorWriter::write(code, *function);
+ }
+}
+
void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotObject &compiled)
{
code.appendToHeader(u""); // just new line
@@ -196,37 +216,61 @@ void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotObject
GeneratedCodeUtils::HeaderIndentationScope headerIndentScope(code);
Q_UNUSED(headerIndentScope);
- // generate ctor
- if (compiled.ignoreInit) { // TODO: this branch should be eliminated
- // NB: here the ctor should be public
- code.appendToHeader(getFunctionCategory(compiled.baselineCtor) + u":", -1);
- CodeGeneratorWriter::write(code, compiled.baselineCtor);
- } else {
- Q_ASSERT(compiled.baselineCtor.access == compiled.init.access);
- code.appendToHeader(getFunctionCategory(compiled.init) + u":", -1);
- CodeGeneratorWriter::write(code, compiled.baselineCtor);
- CodeGeneratorWriter::write(code, compiled.init);
+ // first, write user-visible code, then everything else. someone might
+ // want to look at the generated code, so let's make an effort when
+ // writing it down
+
+ code.appendToHeader(u"// -----------------");
+ code.appendToHeader(u"// External C++ API:");
+ code.appendToHeader(u"public:", -1);
+
+ // NB: when non-document root, the externalCtor won't be public - but we
+ // really don't care about the output format of such types
+ if (!compiled.ignoreInit && compiled.externalCtor.access == QQmlJSMetaMethod::Public) {
+ // TODO: ignoreInit must be eliminated
- // NB: when non-document root, this ctor won't be public
- code.appendToHeader(getFunctionCategory(compiled.externalCtor) + u":", -1);
CodeGeneratorWriter::write(code, compiled.externalCtor);
- code.appendToHeader(u"protected:", -1);
- CodeGeneratorWriter::write(code, compiled.endInit);
- CodeGeneratorWriter::write(code, compiled.completeComponent);
- CodeGeneratorWriter::write(code, compiled.finalizeComponent);
- CodeGeneratorWriter::write(code, compiled.handleOnCompleted);
- code.appendToHeader(u"public:", -1);
}
-
// generate dtor
if (compiled.dtor)
CodeGeneratorWriter::write(code, *compiled.dtor);
// generate enums
- code.appendToHeader(u"// BEGIN(enumerations)");
for (const auto &enumeration : qAsConst(compiled.enums))
CodeGeneratorWriter::write(code, enumeration);
- code.appendToHeader(u"// END(enumerations)");
+
+ // generate (visible) functions
+ const auto isUserVisibleFunction = [](const QQmlJSAotMethod &function) {
+ return function.userVisible;
+ };
+ dumpFunctions(code, compiled.functions, isUserVisibleFunction);
+
+ code.appendToHeader(u"// -----------------");
+ code.appendToHeader(u""); // blank line
+ code.appendToHeader(u"// Internal functionality (do NOT use it!):");
+
+ // below are the hidden parts of the class
+
+ // generate (rest of the) ctors
+ if (compiled.ignoreInit) { // TODO: this branch should be eliminated
+ Q_ASSERT(compiled.baselineCtor.access == QQmlJSMetaMethod::Public);
+ code.appendToHeader(u"public:", -1);
+ CodeGeneratorWriter::write(code, compiled.baselineCtor);
+ } else {
+ code.appendToHeader(u"protected:", -1);
+ if (compiled.externalCtor.access != QQmlJSMetaMethod::Public) {
+ Q_ASSERT(compiled.externalCtor.access == QQmlJSMetaMethod::Protected);
+ CodeGeneratorWriter::write(code, compiled.externalCtor);
+ }
+ CodeGeneratorWriter::write(code, compiled.baselineCtor);
+ CodeGeneratorWriter::write(code, compiled.init);
+ CodeGeneratorWriter::write(code, compiled.endInit);
+ CodeGeneratorWriter::write(code, compiled.completeComponent);
+ CodeGeneratorWriter::write(code, compiled.finalizeComponent);
+ CodeGeneratorWriter::write(code, compiled.handleOnCompleted);
+
+ // code.appendToHeader(u"public:", -1);
+ }
// generate child types
code.appendToHeader(u"// BEGIN(children)");
@@ -235,18 +279,9 @@ void CodeGeneratorWriter::write(GeneratedCodeUtils &code, const QQmlJSAotObject
code.appendToHeader(u"// END(children)");
// generate functions
- code.appendToHeader(u"// BEGIN(functions)");
- // functions are special as they are grouped by access and kind
- QHash<QString, QList<const QQmlJSAotMethod *>> functionsByCategory;
- for (const auto &function : qAsConst(compiled.functions))
- functionsByCategory[getFunctionCategory(function)].append(std::addressof(function));
-
- for (auto it = functionsByCategory.cbegin(); it != functionsByCategory.cend(); ++it) {
- code.appendToHeader(it.key() + u":", -1);
- for (const QQmlJSAotMethod *function : qAsConst(it.value()))
- CodeGeneratorWriter::write(code, *function);
- }
- code.appendToHeader(u"// END(functions)");
+ code.appendToHeader(u"// BEGIN(hidden_functions)");
+ dumpFunctions(code, compiled.functions, std::not_fn(isUserVisibleFunction));
+ code.appendToHeader(u"// END(hidden_functions)");
if (!compiled.variables.isEmpty() || !compiled.properties.isEmpty()) {
code.appendToHeader(u""); // blank line
diff --git a/tools/qmltc/prototype/qmlcompiler.h b/tools/qmltc/prototype/qmlcompiler.h
index 4ac515957f..3c770612cc 100644
--- a/tools/qmltc/prototype/qmlcompiler.h
+++ b/tools/qmltc/prototype/qmlcompiler.h
@@ -122,6 +122,7 @@ struct QQmlJSAotMethodBase
struct QQmlJSAotMethod : QQmlJSAotMethodBase
{
QQmlJSMetaMethod::Type type = QQmlJSMetaMethod::Method; // Qt function type
+ bool userVisible = false; // tells if a function is prioritized during the output generation
};
// Represents C++ special member function