diff --git a/src/libs/qmljs/parser/qmljs.g b/src/libs/qmljs/parser/qmljs.g index 54aaf3b010c..6fd265ebc19 100644 --- a/src/libs/qmljs/parser/qmljs.g +++ b/src/libs/qmljs/parser/qmljs.g @@ -4019,14 +4019,16 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead AssignmentExpress /. case $rule_number: { AST::ReturnStatement *ret = new (pool) AST::ReturnStatement(sym(4).Expression); - ret->returnToken = sym(4).Node->firstSourceLocation(); - ret->semicolonToken = sym(4).Node->lastSourceLocation(); + const auto zeroLength = [](SourceLocation l){ l.length = 0; return l; }; + ret->returnToken = zeroLength(sym(4).Node->firstSourceLocation()); + ret->semicolonToken = zeroLength(sym(4).Node->lastSourceLocation()); AST::StatementList *statements = (new (pool) AST::StatementList(ret))->finish(); - AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, statements); + AST::FunctionExpression *f = new (pool) + AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, statements); f->isArrowFunction = true; f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1); - f->lbraceToken = sym(4).Node->firstSourceLocation(); - f->rbraceToken = sym(4).Node->lastSourceLocation(); + f->lbraceToken = zeroLength(sym(4).Node->firstSourceLocation()); + f->rbraceToken = zeroLength(sym(4).Node->lastSourceLocation()); sym(1).Node = f; } break; ./ @@ -4039,7 +4041,7 @@ ArrowFunction_In: ArrowParameters T_ARROW ConciseBodyLookahead T_FORCE_BLOCK Fun AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, sym(6).StatementList); f->isArrowFunction = true; f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1); - f->lbraceToken = loc(6); + f->lbraceToken = loc(5); f->rbraceToken = loc(7); sym(1).Node = f; } break; diff --git a/src/libs/qmljs/parser/qmljsparser.cpp b/src/libs/qmljs/parser/qmljsparser.cpp index 57b03b6cfbf..ec6087f6435 100644 --- a/src/libs/qmljs/parser/qmljsparser.cpp +++ b/src/libs/qmljs/parser/qmljsparser.cpp @@ -3001,15 +3001,16 @@ case 241: { case 528: { AST::ReturnStatement *ret = new (pool) AST::ReturnStatement(sym(4).Expression); - ret->returnToken = sym(4).Node->firstSourceLocation(); - ret->semicolonToken = sym(4).Node->lastSourceLocation(); + const auto zeroLength = [](SourceLocation l){ l.length = 0; return l; }; + ret->returnToken = zeroLength(sym(4).Node->firstSourceLocation()); + ret->semicolonToken = zeroLength(sym(4).Node->lastSourceLocation()); AST::StatementList *statements = (new (pool) AST::StatementList(ret))->finish(); AST::FunctionExpression *f = new (pool) AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, statements); f->isArrowFunction = true; f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1); - f->lbraceToken = sym(4).Node->firstSourceLocation(); - f->rbraceToken = sym(4).Node->lastSourceLocation(); + f->lbraceToken = zeroLength(sym(4).Node->firstSourceLocation()); + f->rbraceToken = zeroLength(sym(4).Node->lastSourceLocation()); sym(1).Node = f; } break; @@ -3022,7 +3023,7 @@ case 241: { AST::FunctionExpression(QStringView(), sym(1).FormalParameterList, sym(6).StatementList); f->isArrowFunction = true; f->functionToken = sym(1).Node ? sym(1).Node->firstSourceLocation() : loc(1); - f->lbraceToken = loc(6); + f->lbraceToken = loc(5); f->rbraceToken = loc(7); sym(1).Node = f; } break; diff --git a/src/libs/qmljs/qmljsreformatter.cpp b/src/libs/qmljs/qmljsreformatter.cpp index b723f9ff7bd..52b5afc0b1d 100644 --- a/src/libs/qmljs/qmljsreformatter.cpp +++ b/src/libs/qmljs/qmljsreformatter.cpp @@ -1097,7 +1097,8 @@ protected: { out(ast->returnToken); if (ast->expression) { - out(" "); + if (ast->returnToken.isValid()) + out(" "); accept(ast->expression); } return false; @@ -1218,17 +1219,32 @@ protected: bool visit(FunctionExpression *ast) override { - out("function ", ast->functionToken); - if (!ast->name.isNull()) - out(ast->identifierToken); + if (!ast->isArrowFunction) { + out("function ", ast->functionToken); + if (!ast->name.isNull()) + out(ast->identifierToken); + } out(ast->lparenToken); + if (ast->isArrowFunction && ast->formals && ast->formals->next) + out("("); accept(ast->formals); + if (ast->isArrowFunction && ast->formals && ast->formals->next) + out(")"); out(ast->rparenToken); + if (ast->isArrowFunction && !ast->formals) + out("()"); out(" "); + if (ast->isArrowFunction) + out("=> "); out(ast->lbraceToken); if (ast->body) { - lnAcceptIndented(ast->body); - newLine(); + if (ast->body->next || ast->lbraceToken.isValid()) { + lnAcceptIndented(ast->body); + newLine(); + } else { + // print a single statement in one line. E.g. x => x * 2 + accept(ast->body); + } } out(ast->rbraceToken); return false; diff --git a/tests/auto/qml/reformatter/jssyntax.js b/tests/auto/qml/reformatter/jssyntax.js index d651cd7822c..c59e73e77e2 100644 --- a/tests/auto/qml/reformatter/jssyntax.js +++ b/tests/auto/qml/reformatter/jssyntax.js @@ -12,6 +12,15 @@ function foo(a, b) { var foo = function (a, b) {} +const func1 = x => x * 2 +const func2 = x => { + return x * 7 +} +const func3 = (x, y) => x + y +const func4 = (x, y) => { + return x + y +} + while (true) { for (var a = 1; a < 5; ++a) { switch (a) {