diff options
author | Ulf Hermann <ulf.hermann@qt.io> | 2019-10-21 09:27:57 +0200 |
---|---|---|
committer | Fabian Kosmale <fabian.kosmale@qt.io> | 2019-11-18 14:01:44 +0100 |
commit | 41bbf7e376d0e374dc7c4e2a5ed4157a1b880b4a (patch) | |
tree | 36e009e5850fe7fbd980faa249d7fc9702c48cbf /tests/auto/qml/qqmlparser | |
parent | 355fd4bf5cd0a83b52b37c2a905cee867f9af4d6 (diff) |
QML: Consider the semicolon as part of expression statements
When asked for lastSourceLocation() we should always return the
semicolon token. In order for that to work, the semicolon token needs to
be valid in all cases. In the case of object literals as expressions for
properties we neither accepted nor synthesized a semicolon as delimiter.
Add an optional semicolon that we can then also use as end of the
expression statement.
Furthermore, this triggered a silent rule conflict for ImportSpecifier, which
for some reason did not arise before:
IdentifierReference could resolve to both ImpordBinding and IdentifierName,
causing ambiguity in the grammar, and ultimately caused parse failues
when parsing an import statement.
This is now resolved by explicitly telling the parser to prefer
shifting.
Initial-patch-by: Ulf Hermann <ulf.hermann@qt.io>
Change-Id: Iaec29c452b577312248a17cb48f005f4fc0bd8c4
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Reviewed-by: Ulf Hermann <ulf.hermann@qt.io>
Diffstat (limited to 'tests/auto/qml/qqmlparser')
-rw-r--r-- | tests/auto/qml/qqmlparser/tst_qqmlparser.cpp | 41 |
1 files changed, 41 insertions, 0 deletions
diff --git a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp index 9d8818d01e..4ba6a709df 100644 --- a/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp +++ b/tests/auto/qml/qqmlparser/tst_qqmlparser.cpp @@ -62,6 +62,7 @@ private slots: void typeAnnotations(); void disallowedTypeAnnotations_data(); void disallowedTypeAnnotations(); + void semicolonPartOfExpressionStatement(); private: QStringList excludedDirs; @@ -141,6 +142,30 @@ struct TypeAnnotationObserver: public AST::Visitor } }; +struct ExpressionStatementObserver: public AST::Visitor +{ + int expressionsSeen = 0; + bool endsWithSemicolon = true; + + void operator()(AST::Node *node) + { + AST::Node::accept(node, this); + } + + virtual bool visit(AST::ExpressionStatement *statement) + { + ++expressionsSeen; + endsWithSemicolon = endsWithSemicolon + && (statement->lastSourceLocation().end() == statement->semicolonToken.end()); + return true; + } + + void throwRecursionDepthError() final + { + QFAIL("Maximum statement or expression depth exceeded"); + } +}; + } tst_qqmlparser::tst_qqmlparser() @@ -438,6 +463,22 @@ void tst_qqmlparser::disallowedTypeAnnotations() QVERIFY2(parser.errorMessage().startsWith("Type annotations are not permitted "), qPrintable(parser.errorMessage())); } +void tst_qqmlparser::semicolonPartOfExpressionStatement() +{ + QQmlJS::Engine engine; + QQmlJS::Lexer lexer(&engine); + lexer.setCode(QLatin1String("A { property int x: 1+1; property int y: 2+2 \n" + "tt: {'a': 5, 'b': 6}; ff: {'c': 'rrr'}}"), 1); + QQmlJS::Parser parser(&engine); + QVERIFY(parser.parse()); + + check::ExpressionStatementObserver observer; + observer(parser.rootNode()); + + QCOMPARE(observer.expressionsSeen, 4); + QVERIFY(observer.endsWithSemicolon); +} + QTEST_MAIN(tst_qqmlparser) #include "tst_qqmlparser.moc" |