diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2023-02-16 11:28:33 +0100 |
---|---|---|
committer | Ulf Hermann <ulf.hermann@qt.io> | 2023-02-22 11:00:19 +0100 |
commit | bdb2bb561054ad7e95ced2f4b79533d13000172b (patch) | |
tree | 8cf445d89c335bd13ca21720c87aa5bc69271ece /src | |
parent | 763dad999dc5bf6109158283c9dc6b396a4e75f6 (diff) |
QML: Allow pragmas with multiple values
This will be needed in follow-up changes.
Task-number: QTBUG-94807
Change-Id: I6243ea31290251c30dd0aceaae878568bc1c0525
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/qml/compiler/qqmlirbuilder.cpp | 123 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen.cpp | 5 | ||||
-rw-r--r-- | src/qml/compiler/qv4codegen_p.h | 1 | ||||
-rw-r--r-- | src/qml/parser/qqmljs.g | 27 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast.cpp | 9 | ||||
-rw-r--r-- | src/qml/parser/qqmljsast_p.h | 47 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastfwd_p.h | 1 | ||||
-rw-r--r-- | src/qml/parser/qqmljsastvisitor_p.h | 4 | ||||
-rw-r--r-- | src/qmlcompiler/qqmljsimportvisitor.cpp | 77 | ||||
-rw-r--r-- | src/qmldom/qqmldomastdumper.cpp | 8 | ||||
-rw-r--r-- | src/qmldom/qqmldomcomments.cpp | 3 | ||||
-rw-r--r-- | src/qmldom/qqmldomreformatter.cpp | 10 |
12 files changed, 233 insertions, 82 deletions
diff --git a/src/qml/compiler/qqmlirbuilder.cpp b/src/qml/compiler/qqmlirbuilder.cpp index 6b2f795daf..e85c0fe310 100644 --- a/src/qml/compiler/qqmlirbuilder.cpp +++ b/src/qml/compiler/qqmlirbuilder.cpp @@ -767,10 +767,10 @@ struct PragmaParser pragma->type = type(); - if (!assign(pragma, node->value)) { + if (QQmlJS::AST::UiPragmaValueList *bad = assign(pragma, node->values)) { builder->recordError( node->pragmaToken, QCoreApplication::translate( - "QQmlParser", "Unknown %1 '%2' in pragma").arg(name(), node->value)); + "QQmlParser", "Unknown %1 '%2' in pragma").arg(name(), bad->value)); return false; } @@ -795,63 +795,90 @@ private: Q_UNREACHABLE_RETURN(Pragma::PragmaType(-1)); } - static bool assign(Pragma *pragma, QStringView value) + template<typename F> + static QQmlJS::AST::UiPragmaValueList *iterateValues( + QQmlJS::AST::UiPragmaValueList *input, F &&process) + { + for (QQmlJS::AST::UiPragmaValueList *i = input; i; i = i->next) { + if (!process(i->value)) + return i; + } + return nullptr; + } + + static QQmlJS::AST::UiPragmaValueList *assign( + Pragma *pragma, QQmlJS::AST::UiPragmaValueList *values) { // We could use QMetaEnum here to make the code more compact, // but it's probably more expensive. if constexpr (std::is_same_v<Argument, Pragma::ComponentBehaviorValue>) { - if (value == "Unbound"_L1) { - pragma->componentBehavior = Pragma::Unbound; - return true; - } - if (value == "Bound"_L1) { - pragma->componentBehavior = Pragma::Bound; - return true; - } + return iterateValues(values, [pragma](QStringView value) { + if (value == "Unbound"_L1) { + pragma->componentBehavior = Pragma::Unbound; + return true; + } + if (value == "Bound"_L1) { + pragma->componentBehavior = Pragma::Bound; + return true; + } + return false; + }); } else if constexpr (std::is_same_v<Argument, Pragma::ListPropertyAssignBehaviorValue>) { - if (value == "Append"_L1) { - pragma->listPropertyAssignBehavior = Pragma::Append; - return true; - } - if (value == "Replace"_L1) { - pragma->listPropertyAssignBehavior = Pragma::Replace; - return true; - } - if (value == "ReplaceIfNotDefault"_L1) { - pragma->listPropertyAssignBehavior = Pragma::ReplaceIfNotDefault; - return true; - } + return iterateValues(values, [pragma](QStringView value) { + if (value == "Append"_L1) { + pragma->listPropertyAssignBehavior = Pragma::Append; + return true; + } + if (value == "Replace"_L1) { + pragma->listPropertyAssignBehavior = Pragma::Replace; + return true; + } + if (value == "ReplaceIfNotDefault"_L1) { + pragma->listPropertyAssignBehavior = Pragma::ReplaceIfNotDefault; + return true; + } + return false; + }); } else if constexpr (std::is_same_v<Argument, Pragma::FunctionSignatureBehaviorValue>) { - if (value == "Ignored"_L1) { - pragma->functionSignatureBehavior = Pragma::Ignored; - return true; - } - if (value == "Enforced"_L1) { - pragma->functionSignatureBehavior = Pragma::Enforced; - return true; - } + return iterateValues(values, [pragma](QStringView value) { + if (value == "Ignored"_L1) { + pragma->functionSignatureBehavior = Pragma::Ignored; + return true; + } + if (value == "Enforced"_L1) { + pragma->functionSignatureBehavior = Pragma::Enforced; + return true; + } + return false; + }); } else if constexpr (std::is_same_v<Argument, Pragma::NativeMethodBehaviorValue>) { - if (value == "AcceptThisObject"_L1) { - pragma->nativeMethodBehavior = Pragma::AcceptThisObject; - return true; - } - if (value == "RejectThisObject"_L1) { - pragma->nativeMethodBehavior = Pragma::RejectThisObject; - return true; - } + return iterateValues(values, [pragma](QStringView value) { + if (value == "AcceptThisObject"_L1) { + pragma->nativeMethodBehavior = Pragma::AcceptThisObject; + return true; + } + if (value == "RejectThisObject"_L1) { + pragma->nativeMethodBehavior = Pragma::RejectThisObject; + return true; + } + return false; + }); } else if constexpr (std::is_same_v<Argument, Pragma::ValueTypeBehaviorValue>) { - if (value == "Reference"_L1) { - pragma->valueTypeBehavior = Pragma::Reference; - return true; - } - if (value == "Copy"_L1) { - pragma->valueTypeBehavior = Pragma::Copy; - return true; - } + return iterateValues(values, [pragma](QStringView value) { + if (value == "Reference"_L1) { + pragma->valueTypeBehavior = Pragma::Reference; + return true; + } + if (value == "Copy"_L1) { + pragma->valueTypeBehavior = Pragma::Copy; + return true; + } + return false; + }); } - return false; + Q_UNREACHABLE_RETURN(nullptr); } static bool isUnique(IRBuilder *builder) diff --git a/src/qml/compiler/qv4codegen.cpp b/src/qml/compiler/qv4codegen.cpp index 5df9b3fa4c..3b0dac0766 100644 --- a/src/qml/compiler/qv4codegen.cpp +++ b/src/qml/compiler/qv4codegen.cpp @@ -905,6 +905,11 @@ bool Codegen::visit(UiHeaderItemList *) Q_UNREACHABLE_RETURN(false); } +bool Codegen::visit(UiPragmaValueList *) +{ + Q_UNREACHABLE_RETURN(false); +} + bool Codegen::visit(UiPragma *) { Q_UNREACHABLE_RETURN(false); diff --git a/src/qml/compiler/qv4codegen_p.h b/src/qml/compiler/qv4codegen_p.h index fddbcc7d31..e1f17dc89b 100644 --- a/src/qml/compiler/qv4codegen_p.h +++ b/src/qml/compiler/qv4codegen_p.h @@ -595,6 +595,7 @@ protected: bool visit(QQmlJS::AST::UiArrayMemberList *ast) override; bool visit(QQmlJS::AST::UiImport *ast) override; bool visit(QQmlJS::AST::UiHeaderItemList *ast) override; + bool visit(QQmlJS::AST::UiPragmaValueList *ast) override; bool visit(QQmlJS::AST::UiPragma *ast) override; bool visit(QQmlJS::AST::UiObjectInitializer *ast) override; bool visit(QQmlJS::AST::UiObjectMemberList *ast) override; diff --git a/src/qml/parser/qqmljs.g b/src/qml/parser/qqmljs.g index 394edf0fed..13c54d387b 100644 --- a/src/qml/parser/qqmljs.g +++ b/src/qml/parser/qqmljs.g @@ -217,6 +217,7 @@ public: AST::UiProgram *UiProgram; AST::UiHeaderItemList *UiHeaderItemList; + AST::UiPragmaValueList *UiPragmaValueList; AST::UiPragma *UiPragma; AST::UiImport *UiImport; AST::UiParameterList *UiParameterList; @@ -717,10 +718,31 @@ UiHeaderItemList: UiHeaderItemList UiImport; ./ PragmaId: JsIdentifier; +PragmaValue: JsIdentifier; Semicolon: T_AUTOMATIC_SEMICOLON; Semicolon: T_SEMICOLON; +UiPragmaValueList: PragmaValue; +/. + case $rule_number: { + AST::UiPragmaValueList *list + = new (pool) AST::UiPragmaValueList(stringRef(1)); + list->location = loc(1); + sym(1).Node = list; + } break; +./ + +UiPragmaValueList: UiPragmaValueList T_COMMA PragmaValue; +/. + case $rule_number: { + AST::UiPragmaValueList *list + = new (pool) AST::UiPragmaValueList(sym(1).UiPragmaValueList, stringRef(3)); + list->location = loc(3); + sym(1).Node = list; + } break; +./ + UiPragma: T_PRAGMA PragmaId Semicolon; /. case $rule_number: { @@ -731,10 +753,11 @@ UiPragma: T_PRAGMA PragmaId Semicolon; } break; ./ -UiPragma: T_PRAGMA PragmaId T_COLON JsIdentifier Semicolon; +UiPragma: T_PRAGMA PragmaId T_COLON UiPragmaValueList Semicolon; /. case $rule_number: { - AST::UiPragma *pragma = new (pool) AST::UiPragma(stringRef(2), stringRef(4)); + AST::UiPragma *pragma = new (pool) AST::UiPragma( + stringRef(2), sym(4).UiPragmaValueList->finish()); pragma->pragmaToken = loc(1); pragma->semicolonToken = loc(5); sym(1).Node = pragma; diff --git a/src/qml/parser/qqmljsast.cpp b/src/qml/parser/qqmljsast.cpp index 5408f29900..e3ed876473 100644 --- a/src/qml/parser/qqmljsast.cpp +++ b/src/qml/parser/qqmljsast.cpp @@ -1336,6 +1336,15 @@ void UiImport::accept0(BaseVisitor *visitor) visitor->endVisit(this); } +void UiPragmaValueList::accept0(BaseVisitor *visitor) +{ + if (visitor->visit(this)) { + } + + visitor->endVisit(this); +} + + void UiPragma::accept0(BaseVisitor *visitor) { if (visitor->visit(this)) { diff --git a/src/qml/parser/qqmljsast_p.h b/src/qml/parser/qqmljsast_p.h index 77af38aaca..e7052f324e 100644 --- a/src/qml/parser/qqmljsast_p.h +++ b/src/qml/parser/qqmljsast_p.h @@ -222,6 +222,7 @@ public: Kind_UiObjectInitializer, Kind_UiObjectMemberList, Kind_UiArrayMemberList, + Kind_UiPragmaValueList, Kind_UiPragma, Kind_UiProgram, Kind_UiParameterList, @@ -3074,13 +3075,53 @@ public: UiObjectMember *member; }; +class QML_PARSER_EXPORT UiPragmaValueList: public Node +{ +public: + QQMLJS_DECLARE_AST_NODE(UiPragmaValueList) + + UiPragmaValueList(QStringView value) + : value(value) + , next(this) + { + kind = K; + } + + UiPragmaValueList(UiPragmaValueList *previous, QStringView value) + : value(value) + { + kind = K; + next = previous->next; + previous->next = this; + } + + void accept0(BaseVisitor *visitor) override; + + SourceLocation firstSourceLocation() const override + { return location; } + + SourceLocation lastSourceLocation() const override + { return lastListElement(this)->location; } + + UiPragmaValueList *finish() + { + UiPragmaValueList *head = next; + next = nullptr; + return head; + } + + QStringView value; + UiPragmaValueList *next; + SourceLocation location; +}; + class QML_PARSER_EXPORT UiPragma: public Node { public: QQMLJS_DECLARE_AST_NODE(UiPragma) - UiPragma(QStringView name, QStringView value = {}) - : name(name), value(value) + UiPragma(QStringView name, UiPragmaValueList *values = nullptr) + : name(name), values(values) { kind = K; } void accept0(BaseVisitor *visitor) override; @@ -3093,7 +3134,7 @@ public: // attributes QStringView name; - QStringView value; + UiPragmaValueList *values; SourceLocation pragmaToken; SourceLocation semicolonToken; }; diff --git a/src/qml/parser/qqmljsastfwd_p.h b/src/qml/parser/qqmljsastfwd_p.h index e06da8b4c1..ab807386c2 100644 --- a/src/qml/parser/qqmljsastfwd_p.h +++ b/src/qml/parser/qqmljsastfwd_p.h @@ -128,6 +128,7 @@ class TypeAnnotation; // ui elements class UiProgram; +class UiPragmaValueList; class UiPragma; class UiImport; class UiPublicMember; diff --git a/src/qml/parser/qqmljsastvisitor_p.h b/src/qml/parser/qqmljsastvisitor_p.h index 450cfaad40..b4ee47ef0d 100644 --- a/src/qml/parser/qqmljsastvisitor_p.h +++ b/src/qml/parser/qqmljsastvisitor_p.h @@ -60,6 +60,7 @@ public: // Ui virtual bool visit(UiProgram *) = 0; virtual bool visit(UiHeaderItemList *) = 0; + virtual bool visit(UiPragmaValueList *) = 0; virtual bool visit(UiPragma *) = 0; virtual bool visit(UiImport *) = 0; virtual bool visit(UiPublicMember *) = 0; @@ -84,6 +85,7 @@ public: virtual void endVisit(UiProgram *) = 0; virtual void endVisit(UiImport *) = 0; virtual void endVisit(UiHeaderItemList *) = 0; + virtual void endVisit(UiPragmaValueList *) = 0; virtual void endVisit(UiPragma *) = 0; virtual void endVisit(UiPublicMember *) = 0; virtual void endVisit(UiSourceElement *) = 0; @@ -404,6 +406,7 @@ public: // Ui bool visit(UiProgram *) override { return true; } bool visit(UiHeaderItemList *) override { return true; } + bool visit(UiPragmaValueList *) override { return true; } bool visit(UiPragma *) override { return true; } bool visit(UiImport *) override { return true; } bool visit(UiPublicMember *) override { return true; } @@ -428,6 +431,7 @@ public: void endVisit(UiProgram *) override {} void endVisit(UiImport *) override {} void endVisit(UiHeaderItemList *) override {} + void endVisit(UiPragmaValueList *) override {} void endVisit(UiPragma *) override {} void endVisit(UiPublicMember *) override {} void endVisit(UiSourceElement *) override {} diff --git a/src/qmlcompiler/qqmljsimportvisitor.cpp b/src/qmlcompiler/qqmljsimportvisitor.cpp index 380520595a..2f0e4f3321 100644 --- a/src/qmlcompiler/qqmljsimportvisitor.cpp +++ b/src/qmlcompiler/qqmljsimportvisitor.cpp @@ -2233,6 +2233,21 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiImport *import) return true; } +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) +template<typename F> +void handlePragmaValues(QQmlJS::AST::UiPragma *pragma, F &&assign) +{ + for (const QQmlJS::AST::UiPragmaValueList *v = pragma->values; v; v = v->next) + assign(v->value); +} +#else +template<typename F> +void handlePragmaValues(QQmlJS::AST::UiPragma *pragma, F &&assign) +{ + assign(pragma->value); +} +#endif + bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiPragma *pragma) { if (pragma->name == u"Strict"_s) { @@ -2248,37 +2263,41 @@ bool QQmlJSImportVisitor::visit(QQmlJS::AST::UiPragma *pragma) } else if (pragma->name == u"Singleton") { m_rootIsSingleton = true; } else if (pragma->name == u"ComponentBehavior") { - if (pragma->value == u"Bound") { - m_scopesById.setComponentsAreBound(true); - } else if (pragma->value == u"Unbound") { - m_scopesById.setComponentsAreBound(false); - } else { - m_logger->log( - u"Unkonwn argument \"%s\" to pragma ComponentBehavior"_s.arg(pragma->value), - qmlSyntax, pragma->firstSourceLocation()); - } + handlePragmaValues(pragma, [this, pragma](QStringView value) { + if (value == u"Bound") { + m_scopesById.setComponentsAreBound(true); + } else if (value == u"Unbound") { + m_scopesById.setComponentsAreBound(false); + } else { + m_logger->log( + u"Unkonwn argument \"%s\" to pragma ComponentBehavior"_s.arg(value), + qmlSyntax, pragma->firstSourceLocation()); + } + }); } else if (pragma->name == u"FunctionSignatureBehavior") { - if (pragma->value == u"Enforced") { - m_scopesById.setSignaturesAreEnforced(true); - } else if (pragma->value == u"Ignored") { - m_scopesById.setSignaturesAreEnforced(false); - } else { - m_logger->log( - u"Unkonwn argument \"%s\" to pragma FunctionSignatureBehavior"_s - .arg(pragma->value), - qmlSyntax, pragma->firstSourceLocation()); - } + handlePragmaValues(pragma, [this, pragma](QStringView value) { + if (value == u"Enforced") { + m_scopesById.setSignaturesAreEnforced(true); + } else if (value == u"Ignored") { + m_scopesById.setSignaturesAreEnforced(false); + } else { + m_logger->log( + u"Unkonwn argument \"%s\" to pragma FunctionSignatureBehavior"_s.arg(value), + qmlSyntax, pragma->firstSourceLocation()); + } + }); } else if (pragma->name == u"ValueTypeBehavior") { - if (pragma->value == u"Copy") { - m_scopesById.setValueTypesAreCopied(true); - } else if (pragma->value == u"Reference") { - m_scopesById.setValueTypesAreCopied(false); - } else { - m_logger->log( - u"Unkonwn argument \"%s\" to pragma ValueTypeBehavior"_s - .arg(pragma->value), - qmlSyntax, pragma->firstSourceLocation()); - } + handlePragmaValues(pragma, [this, pragma](QStringView value) { + if (value == u"Copy") { + m_scopesById.setValueTypesAreCopied(true); + } else if (value == u"Reference") { + m_scopesById.setValueTypesAreCopied(false); + } else { + m_logger->log( + u"Unkonwn argument \"%s\" to pragma ValueTypeBehavior"_s.arg(value), + qmlSyntax, pragma->firstSourceLocation()); + } + }); } return true; diff --git a/src/qmldom/qqmldomastdumper.cpp b/src/qmldom/qqmldomastdumper.cpp index ffb776cf2d..9ae88a6dc9 100644 --- a/src/qmldom/qqmldomastdumper.cpp +++ b/src/qmldom/qqmldomastdumper.cpp @@ -132,6 +132,14 @@ public: bool visit(UiHeaderItemList *) override { start(u"UiHeaderItemList"); return true; } void endVisit(AST::UiHeaderItemList *) override { stop(u"UiHeaderItemList"); } +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) + bool visit(UiPragmaValueList *el) override { + start(QLatin1String("UiPragmaValueList value=%1").arg(el->value)); + return true; + } + void endVisit(AST::UiPragmaValueList *) override { stop(u"UiPragmaValueList"); } +#endif + bool visit(UiPragma *el) override { start(QLatin1String("UiPragma name=%1 pragmaToken=%2%3") .arg(quotedString(el->name), loc(el->pragmaToken), diff --git a/src/qmldom/qqmldomcomments.cpp b/src/qmldom/qqmldomcomments.cpp index 3eee7adb28..559f7c0d73 100644 --- a/src/qmldom/qqmldomcomments.cpp +++ b/src/qmldom/qqmldomcomments.cpp @@ -331,6 +331,9 @@ QSet<int> VisitAll::uiKinds() AST::Node::Kind_UiArrayBinding, AST::Node::Kind_UiImport, AST::Node::Kind_UiObjectBinding, AST::Node::Kind_UiObjectDefinition, AST::Node::Kind_UiInlineComponent, AST::Node::Kind_UiObjectInitializer, +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) + AST::Node::Kind_UiPragmaValueList, +#endif AST::Node::Kind_UiPragma, AST::Node::Kind_UiProgram, AST::Node::Kind_UiPublicMember, AST::Node::Kind_UiQualifiedId, AST::Node::Kind_UiScriptBinding, AST::Node::Kind_UiSourceElement, diff --git a/src/qmldom/qqmldomreformatter.cpp b/src/qmldom/qqmldomreformatter.cpp index 9114f39c3e..c41b51b147 100644 --- a/src/qmldom/qqmldomreformatter.cpp +++ b/src/qmldom/qqmldomreformatter.cpp @@ -92,7 +92,14 @@ protected: } } +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) // we are not supposed to handle the ui + bool visit(UiPragmaValueList *) override + { + Q_ASSERT(false); + return false; + } +#endif bool visit(UiPragma *) override { Q_ASSERT(false); @@ -1059,6 +1066,9 @@ protected: void endVisit(UiProgram *) override { } void endVisit(UiImport *) override { } void endVisit(UiHeaderItemList *) override { } +#if QT_VERSION >= QT_VERSION_CHECK(6, 6, 0) + void endVisit(UiPragmaValueList *) override { } +#endif void endVisit(UiPragma *) override { } void endVisit(UiPublicMember *) override { } void endVisit(UiSourceElement *) override { } |