Qml: Add script element for return statements

Implement and test the DOM representation of a JS return statement.

Task-number: QTBUG-100084
Task-number: QTBUG-111415
Change-Id: I2c11c0b9be3c93cf5be2bd9db5575335d4be19c1
Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
This commit is contained in:
Sami Shalayel 2023-03-07 15:49:30 +01:00
parent 7d8ac7c2d3
commit eba8eb2305
9 changed files with 98 additions and 1 deletions

View File

@ -91,6 +91,7 @@ class VariableDeclaration;
class VariableDeclarationEntry;
// TODO: add new script classes here, as qqmldomitem_p.h cannot include qqmldomscriptelements_p.h
// without creating circular dependencies
class ReturnStatement;
} // end namespace ScriptElements

View File

@ -1256,6 +1256,30 @@ void QQmlDomAstCreator::endVisit(AST::IfStatement *ifStatement)
pushScriptElement(current);
}
bool QQmlDomAstCreator::visit(AST::ReturnStatement *)
{
if (!m_enableScriptExpressions)
return false;
return true;
}
void QQmlDomAstCreator::endVisit(AST::ReturnStatement *returnStatement)
{
if (!m_enableScriptExpressions)
return;
auto current = makeScriptElement<ScriptElements::ReturnStatement>(returnStatement);
if (returnStatement->expression) {
Q_SCRIPTELEMENT_EXIT_IF(scriptNodeStack.isEmpty());
current->setExpression(currentScriptNodeEl().takeVariant());
removeCurrentScriptNode({});
}
pushScriptElement(current);
}
static const DomEnvironment *environmentFrom(MutableDomItem &qmlFile)
{
auto top = qmlFile.top();

View File

@ -303,6 +303,9 @@ public:
bool visit(AST::Block *block) override;
void endVisit(AST::Block *) override;
bool visit(AST::ReturnStatement *block) override;
void endVisit(AST::ReturnStatement *) override;
bool visit(AST::ForStatement *forStatement) override;
void endVisit(AST::ForStatement *forStatement) override;

View File

@ -200,6 +200,7 @@ enum class DomType {
ScriptFunctionDeclaration,
ScriptVariableDeclaration,
ScriptVariableDeclarationEntry,
ScriptReturnStatement,
ScriptElementStop, // marker to check if a DomType is a scriptelement or not
};

View File

@ -730,7 +730,8 @@ public:
VariantOfPointer<ScriptElements::BlockStatement, ScriptElements::IdentifierExpression,
ScriptElements::ForStatement, ScriptElements::BinaryExpression,
ScriptElements::VariableDeclarationEntry, ScriptElements::Literal,
ScriptElements::IfStatement, ScriptElements::VariableDeclaration>;
ScriptElements::IfStatement,
ScriptElements::VariableDeclaration, ScriptElements::ReturnStatement>;
template<typename T>
static ScriptElementVariant fromElement(T element)

View File

@ -278,3 +278,22 @@ void VariableDeclaration::createFileLocations(FileLocations::Tree base)
BaseT::createFileLocations(base);
m_declarations.createFileLocations(base);
}
bool ReturnStatement::iterateDirectSubpaths(DomItem &self, DirectVisitor visitor)
{
bool cont = true;
cont &= wrap(self, visitor, Fields::expression, m_expression);
return cont;
}
void ReturnStatement::updatePathFromOwner(Path p)
{
BaseT::updatePathFromOwner(p);
m_expression.base()->updatePathFromOwner(p.field(Fields::expression));
}
void ReturnStatement::createFileLocations(FileLocations::Tree base)
{
BaseT::createFileLocations(base);
m_expression.base()->createFileLocations(base);
}

View File

@ -241,6 +241,24 @@ private:
ScriptElementVariant m_alternative;
};
class ReturnStatement : public ScriptElementBase<DomType::ScriptReturnStatement>
{
public:
using BaseT::BaseT;
~ReturnStatement() override{};
// minimal required overload for this to be wrapped as DomItem:
bool iterateDirectSubpaths(DomItem &self, DirectVisitor visitor) override;
void updatePathFromOwner(Path p) override;
void createFileLocations(FileLocations::Tree base) override;
ScriptElementVariant expression() const { return m_expression; }
void setExpression(ScriptElementVariant expression) { m_expression = expression; }
private:
ScriptElementVariant m_expression;
};
class BinaryExpression : public ScriptElementBase<DomType::ScriptBinaryExpression>
{
public:

View File

@ -36,7 +36,13 @@ Item {
} else {
i = 456
}
}
function returningFunction() {
if (i)
return 123;
else
return 1 + 2;
}
function testForNull() {

View File

@ -1246,6 +1246,30 @@ private slots:
}
}
}
{
DomItem block =
rootQmlObject.path(".methods[\"returningFunction\"][0].body.scriptElement");
QCOMPARE(block.internalKind(), DomType::ScriptBlockStatement);
QCOMPARE(block.field(Fields::statements).indexes(), 1);
DomItem conditional = block.field(Fields::statements).index(0);
DomItem consequence = conditional.field(Fields::consequence);
QCOMPARE(consequence.internalKind(), DomType::ScriptReturnStatement);
{
DomItem returnValue = consequence.field(Fields::expression);
QCOMPARE(returnValue.internalKind(), DomType::ScriptLiteral);
QCOMPARE(returnValue.field(Fields::value).value().toDouble(), 123);
}
DomItem alternative = conditional.field(Fields::alternative);
QCOMPARE(alternative.internalKind(), DomType::ScriptReturnStatement);
{
DomItem returnValue = alternative.field(Fields::expression);
QCOMPARE(returnValue.internalKind(), DomType::ScriptBinaryExpression);
QCOMPARE(returnValue.field(Fields::left).field(Fields::value).value().toDouble(),
1);
QCOMPARE(returnValue.field(Fields::right).field(Fields::value).value().toDouble(),
2);
}
}
}
private: