aboutsummaryrefslogtreecommitdiffstats
path: root/tools
diff options
context:
space:
mode:
authorFawzi Mohamed <fawzi.mohamed@qt.io>2021-04-19 16:43:21 +0200
committerFawzi Mohamed <fawzi.mohamed@qt.io>2021-06-05 00:08:00 +0200
commitdc5d14c3963e25a3664ed116856e7f604e43b7af (patch)
tree98370c3477b2bf07947a20cb71303de2cca4e6e4 /tools
parentde3d65009adf3c7ce0be6da77ee74b0a2610c9c5 (diff)
qmlformat: use QmlDom
Replace qmlformat with the formatter using qml dom Change-Id: Ie90814260f2d3b9e589ce04381d5ad1880c5b519 Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org> Reviewed-by: Fabian Kosmale <fabian.kosmale@qt.io>
Diffstat (limited to 'tools')
-rw-r--r--tools/qmlformat/CMakeLists.txt7
-rw-r--r--tools/qmlformat/commentastvisitor.cpp288
-rw-r--r--tools/qmlformat/commentastvisitor.h141
-rw-r--r--tools/qmlformat/dumpastvisitor.cpp1434
-rw-r--r--tools/qmlformat/dumpastvisitor.h158
-rw-r--r--tools/qmlformat/qmlformat.cpp (renamed from tools/qmlformat/main.cpp)218
-rw-r--r--tools/qmlformat/restructureastvisitor.cpp196
-rw-r--r--tools/qmlformat/restructureastvisitor.h45
8 files changed, 104 insertions, 2383 deletions
diff --git a/tools/qmlformat/CMakeLists.txt b/tools/qmlformat/CMakeLists.txt
index e492a3ec56..eeabe1c368 100644
--- a/tools/qmlformat/CMakeLists.txt
+++ b/tools/qmlformat/CMakeLists.txt
@@ -9,12 +9,11 @@ qt_internal_add_tool(${target_name}
TARGET_DESCRIPTION "QML Formatter"
TOOLS_TARGET Qml # special case
SOURCES
- commentastvisitor.cpp commentastvisitor.h
- dumpastvisitor.cpp dumpastvisitor.h
- main.cpp
- restructureastvisitor.cpp restructureastvisitor.h
+ qmlformat.cpp
PUBLIC_LIBRARIES
+ Qt::Core
Qt::QmlDevToolsPrivate
+ Qt::QmlDomPrivate
)
#### Keys ignored in scope 1:.:.:qmlformat.pro:<TRUE>:
diff --git a/tools/qmlformat/commentastvisitor.cpp b/tools/qmlformat/commentastvisitor.cpp
deleted file mode 100644
index f07f770b33..0000000000
--- a/tools/qmlformat/commentastvisitor.cpp
+++ /dev/null
@@ -1,288 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "commentastvisitor.h"
-
-using namespace QQmlJS;
-using namespace QQmlJS::AST;
-
-CommentAstVisitor::CommentAstVisitor(QQmlJS::Engine *engine, Node *rootNode) : m_engine(engine)
-{
- rootNode->accept(this);
-
- // Look for complete orphans that have not been attached to *any* node
- QVector<Comment> completeOrphans;
-
- for (const auto &comment : m_engine->comments()) {
- if (isCommentAttached(comment))
- continue;
-
- bool found_orphan = false;
- for (const auto &orphanList : orphanComments().values()) {
- for (const auto &orphan : orphanList) {
- if (orphan.contains(comment)) {
- found_orphan = true;
- break;
- }
- }
-
- if (found_orphan)
- break;
- }
-
- if (found_orphan)
- continue;
-
- completeOrphans.append(Comment(m_engine, Comment::Location::Front, {comment}));
- }
-
- m_orphanComments[nullptr] = completeOrphans;
-}
-
-QList<SourceLocation> CommentAstVisitor::findCommentsInLine(quint32 line, bool includePrevious) const
-{
- QList<SourceLocation> results;
- if (line == 0)
- return results;
-
- for (const auto &location : m_engine->comments()) {
- Comment comment(m_engine, Comment::Location::Front, { location });
- if (line < location.startLine || line > comment.endLine())
- continue;
-
- if (isCommentAttached(location))
- continue;
-
- results.append(location);
-
- if (includePrevious) {
- // See if we can find any more comments above this one
- auto previous = findCommentsInLine(location.startLine - 1, true);
-
- // Iterate it in reverse to restore the correct order
- for (auto it = previous.rbegin(); it != previous.rend(); it++) {
- results.prepend(*it);
- }
- }
-
- break;
- }
-
- return results;
-}
-
-bool CommentAstVisitor::isCommentAttached(const SourceLocation &location) const
-{
- for (const auto &value : m_attachedComments.values()) {
- if (value.contains(location))
- return true;
- }
-
- for (const auto &value : m_listItemComments.values()) {
- if (value.contains(location))
- return true;
- }
-
- // If a comment is already marked as an orphan of a Node that counts as attached too.
- for (const auto &orphanList : m_orphanComments.values()) {
- for (const auto &value : orphanList) {
- if (value.contains(location))
- return true;
- }
- }
-
- return false;
-}
-
-Comment CommentAstVisitor::findComment(SourceLocation first, SourceLocation last,
- int locations) const
-{
- if (locations & Comment::Location::Front) {
- quint32 searchAt = first.startLine - 1;
-
- const auto comments = findCommentsInLine(searchAt, true);
- if (!comments.isEmpty())
- return Comment(m_engine, Comment::Location::Front, comments);
- }
-
- if (locations & Comment::Location::Front_Inline) {
- quint32 searchAt = first.startLine;
-
- const auto comments = findCommentsInLine(searchAt);
- if (!comments.isEmpty())
- return Comment(m_engine, Comment::Location::Front_Inline, comments);
- }
-
- if (locations & Comment::Location::Back_Inline) {
- quint32 searchAt = last.startLine;
-
- const auto comments = findCommentsInLine(searchAt);
- if (!comments.isEmpty())
- return Comment(m_engine, Comment::Location::Back_Inline, comments);
- }
-
- if (locations & Comment::Location::Back) {
- quint32 searchAt = last.startLine + 1;
-
- const auto comments = findCommentsInLine(searchAt);
- if (!comments.isEmpty())
- return Comment(m_engine, Comment::Location::Back, comments);
- }
-
- return Comment();
-
-}
-
-Comment CommentAstVisitor::findComment(Node *node, int locations) const
-{
- return findComment(node->firstSourceLocation(), node->lastSourceLocation(), locations);
-}
-
-QVector<Comment> CommentAstVisitor::findOrphanComments(Node *node) const
-{
- QVector<Comment> comments;
-
- for (auto &comment : m_engine->comments()) {
- if (isCommentAttached(comment))
- continue;
-
- if (comment.begin() <= node->firstSourceLocation().begin()
- || comment.end() > node->lastSourceLocation().end()) {
- continue;
- }
-
- comments.append(Comment(m_engine, Comment::Location::Front, {comment}));
- }
-
- return comments;
-}
-
-void CommentAstVisitor::attachComment(Node *node, int locations)
-{
- auto comment = findComment(node, locations);
-
- if (comment.isValid())
- m_attachedComments[node] = comment;
-}
-
-bool CommentAstVisitor::visit(UiScriptBinding *node)
-{
- attachComment(node);
- return true;
-}
-
-bool CommentAstVisitor::visit(StatementList *node)
-{
- for (auto *item = node; item != nullptr; item = item->next)
- attachComment(item->statement, Comment::Front | Comment::Back_Inline);
- return true;
-}
-
-void CommentAstVisitor::endVisit(StatementList *node)
-{
- m_orphanComments[node] = findOrphanComments(node);
-}
-
-bool CommentAstVisitor::visit(UiObjectBinding *node)
-{
- attachComment(node, Comment::Front | Comment::Front_Inline | Comment::Back);
- return true;
-}
-
-bool CommentAstVisitor::visit(UiObjectDefinition *node)
-{
- attachComment(node, Comment::Front | Comment::Front_Inline | Comment::Back);
- return true;
-}
-
-void CommentAstVisitor::endVisit(UiObjectDefinition *node)
-{
- m_orphanComments[node] = findOrphanComments(node);
-}
-
-bool CommentAstVisitor::visit(UiArrayBinding *node)
-{
- attachComment(node);
- return true;
-}
-
-void CommentAstVisitor::endVisit(UiArrayBinding *node)
-{
- m_orphanComments[node] = findOrphanComments(node);
-}
-
-bool CommentAstVisitor::visit(UiEnumDeclaration *node)
-{
- attachComment(node);
- return true;
-}
-
-void CommentAstVisitor::endVisit(UiEnumDeclaration *node)
-{
- m_orphanComments[node] = findOrphanComments(node);
-}
-
-bool CommentAstVisitor::visit(UiEnumMemberList *node)
-{
- for (auto *item = node; item != nullptr; item = item->next) {
- auto comment = findComment(item->memberToken,
- item->valueToken.isValid() ? item->valueToken : item->memberToken,
- Comment::Front | Comment::Back_Inline);
-
- if (comment.isValid())
- m_listItemComments[item->memberToken.begin()] = comment;
- }
-
- m_orphanComments[node] = findOrphanComments(node);
-
- return true;
-}
-
-bool CommentAstVisitor::visit(UiPublicMember *node)
-{
- attachComment(node);
- return true;
-}
-
-bool CommentAstVisitor::visit(FunctionDeclaration *node)
-{
- attachComment(node);
- return true;
-}
-
-bool CommentAstVisitor::visit(UiImport *node)
-{
- attachComment(node);
- return true;
-}
-
-bool CommentAstVisitor::visit(UiPragma *node)
-{
- attachComment(node);
- return true;
-}
diff --git a/tools/qmlformat/commentastvisitor.h b/tools/qmlformat/commentastvisitor.h
deleted file mode 100644
index 73a6015db7..0000000000
--- a/tools/qmlformat/commentastvisitor.h
+++ /dev/null
@@ -1,141 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef COMMENTASTVISITOR_H
-#define COMMENTASTVISITOR_H
-
-#include <QtQml/private/qqmljsastvisitor_p.h>
-#include <QtQml/private/qqmljsast_p.h>
-#include <QtQml/private/qqmljsengine_p.h>
-
-#include <QHash>
-#include <QString>
-#include <QVector>
-
-struct Comment
-{
- enum Location : int
- {
- Front = 1,
- Front_Inline = Front << 1,
- Back = Front_Inline << 1,
- Back_Inline = Back << 1,
- DefaultLocations = Front | Back_Inline,
- AllLocations = Front | Back | Front_Inline | Back_Inline
- } m_location = Front;
-
- Comment() = default;
- Comment(const QQmlJS::Engine *engine, Location location, QList<QQmlJS::SourceLocation> srcLocations)
- : m_location(location), m_srcLocations(srcLocations) {
- for (const auto& srcLoc : srcLocations) {
- m_text += engine->code().mid(static_cast<int>(srcLoc.begin()),
- static_cast<int>(srcLoc.end() - srcLoc.begin())) + "\n";
- }
-
- m_text.chop(1);
- }
-
- QList<QQmlJS::SourceLocation> m_srcLocations;
-
- bool hasSheBang() const { return !m_srcLocations.isEmpty() && m_srcLocations.first().begin() == 0; }
- bool isValid() const { return !m_srcLocations.isEmpty(); }
- bool isMultiline() const { return m_text.contains("\n"); }
- bool isSyntheticMultiline() const { return m_srcLocations.size() > 1; }
-
- bool contains(const QQmlJS::SourceLocation& location) const {
- for (const QQmlJS::SourceLocation& srcLoc : m_srcLocations) {
- if (srcLoc.begin() == location.begin() && srcLoc.end() == location.end())
- return true;
- }
-
- return false;
- }
-
- quint32 endLine() const
- {
- if (isSyntheticMultiline() || !isValid())
- return 0;
-
- return m_srcLocations[0].startLine + m_text.count(QLatin1Char('\n'));
- }
-
- QString m_text;
-};
-
-namespace AST = QQmlJS::AST;
-class CommentAstVisitor : protected QQmlJS::AST::Visitor
-{
-public:
- CommentAstVisitor(QQmlJS::Engine *engine, AST::Node *rootNode);
-
- void throwRecursionDepthError() override {}
-
- const QHash<AST::Node *, Comment> attachedComments() const { return m_attachedComments; }
- const QHash<quint32, Comment> listComments() const { return m_listItemComments; }
- const QHash<AST::Node *, QVector<Comment>> orphanComments() const { return m_orphanComments; }
-
- bool visit(AST::UiScriptBinding *node) override;
- bool visit(AST::UiObjectBinding *node) override;
-
- bool visit(AST::UiArrayBinding *node) override;
- void endVisit(AST::UiArrayBinding *node) override;
-
- bool visit(AST::UiObjectDefinition *node) override;
- void endVisit(AST::UiObjectDefinition *) override;
-
- bool visit(AST::UiEnumDeclaration *node) override;
- void endVisit(AST::UiEnumDeclaration *node) override;
-
- bool visit(AST::UiEnumMemberList *node) override;
-
- bool visit(AST::StatementList *node) override;
- void endVisit(AST::StatementList *node) override;
-
- bool visit(AST::UiImport *node) override;
- bool visit(AST::UiPragma *node) override;
- bool visit(AST::UiPublicMember *node) override;
- bool visit(AST::FunctionDeclaration *node) override;
-private:
- bool isCommentAttached(const QQmlJS::SourceLocation& location) const;
-
- QList<QQmlJS::SourceLocation> findCommentsInLine(quint32 line, bool includePrevious = false) const;
-
- Comment findComment(QQmlJS::SourceLocation first, QQmlJS::SourceLocation last,
- int locations = Comment::DefaultLocations) const;
-
- Comment findComment(AST::Node *node, int locations = Comment::DefaultLocations) const;
- QVector<Comment> findOrphanComments(AST::Node *node) const;
- void attachComment(AST::Node *node, int locations = Comment::DefaultLocations);
-
- QQmlJS::Engine *m_engine;
- QHash<AST::Node *, Comment> m_attachedComments;
- QHash<quint32, Comment> m_listItemComments;
- QHash<AST::Node *, QVector<Comment>> m_orphanComments;
-};
-
-#endif // COMMENTASTVISITOR_H
diff --git a/tools/qmlformat/dumpastvisitor.cpp b/tools/qmlformat/dumpastvisitor.cpp
deleted file mode 100644
index baf6651b20..0000000000
--- a/tools/qmlformat/dumpastvisitor.cpp
+++ /dev/null
@@ -1,1434 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "dumpastvisitor.h"
-#include <QtQml/private/qqmljslexer_p.h>
-
-using namespace QQmlJS::AST;
-
-DumpAstVisitor::DumpAstVisitor(QQmlJS::Engine *engine, Node *rootNode, CommentAstVisitor *comment,
- int indentWidth, DumpAstVisitor::Indentation indentation)
- : m_engine(engine), m_comment(comment), m_indentWidth(indentWidth), m_indentation(indentation)
-{
- // Add all completely orphaned comments
- m_result += getOrphanedComments(nullptr);
-
- m_scope_properties.push(ScopeProperties {});
-
- rootNode->accept(this);
-
- // We need to get rid of one new-line so our output doesn't append an empty line
- m_result.chop(1);
-
- // Remove trailing whitespace
- QStringList lines = m_result.split("\n");
- for (QString& line : lines) {
- while (line.endsWith(" "))
- line.chop(1);
- }
-
- m_result = lines.join("\n");
-}
-
-bool DumpAstVisitor::preVisit(Node *el)
-{
- UiObjectMember *m = el->uiObjectMemberCast();
- if (m != 0)
- Node::accept(m->annotations, this);
- return true;
-}
-
-static QString parseUiQualifiedId(UiQualifiedId *id)
-{
- QString name = id->name.toString();
- for (auto *item = id->next; item != nullptr; item = item->next) {
- name += "." + item->name;
- }
-
- return name;
-}
-
-static QString operatorToString(int op)
-{
- switch (op)
- {
- case QSOperator::Add: return "+";
- case QSOperator::And: return "&&";
- case QSOperator::InplaceAnd: return "&=";
- case QSOperator::Assign: return "=";
- case QSOperator::BitAnd: return "&";
- case QSOperator::BitOr: return "|";
- case QSOperator::BitXor: return "^";
- case QSOperator::InplaceSub: return "-=";
- case QSOperator::Div: return "/";
- case QSOperator::InplaceDiv: return "/=";
- case QSOperator::Equal: return "==";
- case QSOperator::Exp: return "**";
- case QSOperator::InplaceExp: return "**=";
- case QSOperator::Ge: return ">=";
- case QSOperator::Gt: return ">";
- case QSOperator::In: return "in";
- case QSOperator::InplaceAdd: return "+=";
- case QSOperator::InstanceOf: return "instanceof";
- case QSOperator::Le: return "<=";
- case QSOperator::LShift: return "<<";
- case QSOperator::InplaceLeftShift: return "<<=";
- case QSOperator::Lt: return "<";
- case QSOperator::Mod: return "%";
- case QSOperator::InplaceMod: return "%=";
- case QSOperator::Mul: return "*";
- case QSOperator::InplaceMul: return "*=";
- case QSOperator::NotEqual: return "!=";
- case QSOperator::Or: return "||";
- case QSOperator::InplaceOr: return "|=";
- case QSOperator::RShift: return ">>";
- case QSOperator::InplaceRightShift: return ">>=";
- case QSOperator::StrictEqual: return "===";
- case QSOperator::StrictNotEqual: return "!==";
- case QSOperator::Sub: return "-";
- case QSOperator::URShift: return ">>>";
- case QSOperator::InplaceURightShift: return ">>>=";
- case QSOperator::InplaceXor: return "^=";
- case QSOperator::As: return "as";
- case QSOperator::Coalesce: return "??";
- case QSOperator::Invalid:
- default:
- return "INVALID";
- }
-}
-
-QString DumpAstVisitor::formatComment(const Comment &comment) const
-{
- QString result;
-
- bool useMultilineComment = comment.isMultiline() && !comment.isSyntheticMultiline();
-
- if (useMultilineComment)
- result += "/*";
- else if (!comment.hasSheBang())
- result += "//";
-
- result += comment.m_text;
-
- if (comment.isSyntheticMultiline())
- result = result.replace("\n","\n" + formatLine("//", false));
-
- if (comment.m_location == Comment::Location::Back_Inline)
- result.prepend(" ");
-
- if (useMultilineComment)
- result += "*/";
-
- return result;
-}
-
-QString DumpAstVisitor::getComment(Node *node, Comment::Location location) const
-{
- const auto& comments = m_comment->attachedComments();
- if (!comments.contains(node))
- return "";
-
- auto comment = comments[node];
-
- if (comment.m_location != location)
- return "";
-
- return formatComment(comment);
-}
-
-QString DumpAstVisitor::getListItemComment(QQmlJS::SourceLocation srcLocation,
- Comment::Location location) const {
- const auto& comments = m_comment->listComments();
-
- if (!comments.contains(srcLocation.begin()))
- return "";
-
- auto comment = comments[srcLocation.begin()];
-
- if (comment.m_location != location)
- return "";
-
- return formatComment(comment);
-}
-
-QString DumpAstVisitor::getOrphanedComments(Node *node) const {
- const auto& orphans = m_comment->orphanComments()[node];
-
- if (orphans.size() == 0)
- return "";
-
- QString result = "";
-
- for (const Comment& orphan : orphans) {
- result += formatLine(formatComment(orphan));
- }
-
- result += "\n";
-
- return result;
-}
-
-QString DumpAstVisitor::parseArgumentList(ArgumentList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next)
- result += parseExpression(item->expression) + (item->next != nullptr ? ", " : "");
-
- return result;
-}
-
-QString DumpAstVisitor::parseUiParameterList(UiParameterList *list) {
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next)
- result += parseUiQualifiedId(item->type) + " " + item->name + (item->next != nullptr ? ", " : "");
-
- return result;
-}
-
-QString DumpAstVisitor::parsePatternElement(PatternElement *element, bool scope)
-{
- switch (element->type)
- {
- case PatternElement::Literal:
- return parseExpression(element->initializer);
- case PatternElement::Binding: {
- QString result = "";
- QString expr = parseExpression(element->initializer);
-
- if (scope) {
- switch (element->scope) {
- case VariableScope::NoScope:
- break;
- case VariableScope::Let:
- result = "let ";
- break;
- case VariableScope::Const:
- result = "const ";
- break;
- case VariableScope::Var:
- result = "var ";
- break;
- }
- }
-
- if (element->bindingIdentifier.isEmpty())
- result += parseExpression(element->bindingTarget);
- else
- result += element->bindingIdentifier.toString();
-
- if (element->typeAnnotation != nullptr)
- result += ": " + parseType(element->typeAnnotation->type);
-
- if (!expr.isEmpty())
- result += " = "+expr;
-
- return result;
- }
- default:
- m_error = true;
- return "pe_unknown";
- }
-}
-
-static QString escapeString(QString string)
-{
- // Handle escape sequences
- string = string.replace("\r", "\\r").replace("\n", "\\n").replace("\t", "\\t")
- .replace("\b","\\b").replace("\v", "\\v").replace("\f", "\\f");
-
- // Escape backslash
- string = string.replace("\\", "\\\\");
-
- // Escape "
- string = string.replace("\"", "\\\"");
-
- return "\"" + string + "\"";
-}
-
-QString DumpAstVisitor::parsePatternElementList(PatternElementList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next)
- result += parsePatternElement(item->element) + (item->next != nullptr ? ", " : "");
-
- return result;
-}
-
-QString DumpAstVisitor::parseFormalParameterList(FormalParameterList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next)
- result += parsePatternElement(item->element) + (item->next != nullptr ? ", " : "");
-
- return result;
-}
-
-QString DumpAstVisitor::parsePatternProperty(PatternProperty *property)
-{
- switch (property->type) {
- case PatternElement::Getter:
- return "get "+parseFunctionExpression(cast<FunctionExpression *>(property->initializer), true);
- case PatternElement::Setter:
- return "set "+parseFunctionExpression(cast<FunctionExpression *>(property->initializer), true);
- default:
- if (property->name->kind == Node::Kind_ComputedPropertyName) {
- return "["+parseExpression(cast<ComputedPropertyName *>(property->name)->expression)+"]: "+parsePatternElement(property, false);
- } else {
- return escapeString(property->name->asString())+": "+parsePatternElement(property, false);
- }
- }
-}
-
-QString DumpAstVisitor::parsePatternPropertyList(PatternPropertyList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next) {
- result += formatLine(parsePatternProperty(item->property) + (item->next != nullptr ? "," : ""));
- }
-
- return result;
-}
-
-QString DumpAstVisitor::parseFunctionExpression(FunctionExpression *functExpr, bool omitFunction)
-{
- m_indentLevel++;
- QString result;
- bool hasBraces = true;
-
- if (!functExpr->isArrowFunction) {
- result += omitFunction ? "" : "function";
-
- if (functExpr->isGenerator)
- result += "*";
-
- if (!functExpr->name.isEmpty())
- result += (omitFunction ? "" : " ") + functExpr->name;
-
- result += "("+parseFormalParameterList(functExpr->formals)+")";
-
- if (functExpr->typeAnnotation != nullptr)
- result += " : " + parseType(functExpr->typeAnnotation->type);
-
- result += " {\n" + parseStatementList(functExpr->body);
- } else {
- result += "("+parseFormalParameterList(functExpr->formals)+")";
-
- if (functExpr->typeAnnotation != nullptr)
- result += " : " + parseType(functExpr->typeAnnotation->type);
-
- result += " => ";
-
- if (functExpr->body == nullptr) {
- result += "{}";
- } else if (functExpr->body->next == nullptr && functExpr->body->statement->kind == Node::Kind_ReturnStatement) {
- m_indentLevel--;
- result += parseExpression(cast<ReturnStatement *>(functExpr->body->statement)->expression);
- hasBraces = false;
- } else {
- result += "{\n" + parseStatementList(functExpr->body);
- }
- }
-
- if (hasBraces) {
- m_indentLevel--;
- result += formatLine("}", false);
- }
-
- return result;
-
-}
-
-QString DumpAstVisitor::parseType(Type *type) {
- QString result = parseUiQualifiedId(type->typeId);
-
- if (type->typeArguments != nullptr) {
- TypeArgumentList *list = cast<TypeArgumentList *>(type->typeArguments);
-
- result += "<";
-
- for (auto *item = list; item != nullptr; item = item->next) {
- result += parseType(item->typeId) + (item->next != nullptr ? ", " : "");
- }
-
- result += ">";
- }
-
- return result;
-}
-
-QString DumpAstVisitor::parseExpression(ExpressionNode *expression)
-{
- if (expression == nullptr)
- return "";
-
- switch (expression->kind)
- {
- case Node::Kind_ArrayPattern:
- return "["+parsePatternElementList(cast<ArrayPattern *>(expression)->elements)+"]";
- case Node::Kind_IdentifierExpression:
- return cast<IdentifierExpression*>(expression)->name.toString();
- case Node::Kind_FieldMemberExpression: {
- auto *fieldMemberExpr = cast<FieldMemberExpression *>(expression);
- QString result = parseExpression(fieldMemberExpr->base);
-
- // If we're operating on a numeric literal, always put it in braces
- if (fieldMemberExpr->base->kind == Node::Kind_NumericLiteral)
- result = "(" + result + ")";
-
- result += (fieldMemberExpr->isOptional ? "?." : ".") + fieldMemberExpr->name.toString();
-
- return result;
- }
- case Node::Kind_ArrayMemberExpression: {
- auto *arrayMemberExpr = cast<ArrayMemberExpression *>(expression);
- return parseExpression(arrayMemberExpr->base)
- + (arrayMemberExpr->isOptional ? "?." : "") + "[" + parseExpression(arrayMemberExpr->expression) + "]";
- }
- case Node::Kind_NestedExpression:
- return "("+parseExpression(cast<NestedExpression *>(expression)->expression)+")";
- case Node::Kind_TrueLiteral:
- return "true";
- case Node::Kind_FalseLiteral:
- return "false";
- case Node::Kind_FunctionExpression:
- {
- auto *functExpr = cast<FunctionExpression *>(expression);
- return parseFunctionExpression(functExpr);
- }
- case Node::Kind_NullExpression:
- return "null";
- case Node::Kind_ThisExpression:
- return "this";
- case Node::Kind_PostIncrementExpression:
- return parseExpression(cast<PostIncrementExpression *>(expression)->base)+"++";
- case Node::Kind_PreIncrementExpression:
- return "++"+parseExpression(cast<PreIncrementExpression *>(expression)->expression);
- case Node::Kind_PostDecrementExpression:
- return parseExpression(cast<PostDecrementExpression *>(expression)->base)+"--";
- case Node::Kind_PreDecrementExpression:
- return "--"+parseExpression(cast<PreDecrementExpression *>(expression)->expression);
- case Node::Kind_NumericLiteral:
- return QString::number(cast<NumericLiteral *>(expression)->value);
- case Node::Kind_TemplateLiteral: {
- auto firstSrcLoc = cast<TemplateLiteral *>(expression)->firstSourceLocation();
- auto lastSrcLoc = cast<TemplateLiteral *>(expression)->lastSourceLocation();
- return m_engine->code().mid(static_cast<int>(firstSrcLoc.begin()),
- static_cast<int>(lastSrcLoc.end() - firstSrcLoc.begin()));
- }
- case Node::Kind_StringLiteral: {
- auto srcLoc = cast<StringLiteral *>(expression)->firstSourceLocation();
- return m_engine->code().mid(static_cast<int>(srcLoc.begin()),
- static_cast<int>(srcLoc.end() - srcLoc.begin()));
- }
- case Node::Kind_BinaryExpression: {
- auto *binExpr = expression->binaryExpressionCast();
- return parseExpression(binExpr->left) + " " + operatorToString(binExpr->op)
- + " " + parseExpression(binExpr->right);
- }
- case Node::Kind_CallExpression: {
- auto *callExpr = cast<CallExpression *>(expression);
-
- return parseExpression(callExpr->base) + (callExpr->isOptional ? "?." : "") + "(" + parseArgumentList(callExpr->arguments) + ")";
- }
- case Node::Kind_NewExpression:
- return "new "+parseExpression(cast<NewExpression *>(expression)->expression);
- case Node::Kind_NewMemberExpression: {
- auto *newMemberExpression = cast<NewMemberExpression *>(expression);
- return "new "+parseExpression(newMemberExpression->base)
- + "(" +parseArgumentList(newMemberExpression->arguments)+")";
- }
- case Node::Kind_DeleteExpression:
- return "delete " + parseExpression(cast<DeleteExpression *>(expression)->expression);
- case Node::Kind_VoidExpression:
- return "void " + parseExpression(cast<VoidExpression *>(expression)->expression);
- case Node::Kind_TypeOfExpression:
- return "typeof " + parseExpression(cast<TypeOfExpression *>(expression)->expression);
- case Node::Kind_UnaryPlusExpression:
- return "+" + parseExpression(cast<UnaryPlusExpression *>(expression)->expression);
- case Node::Kind_UnaryMinusExpression:
- return "-" + parseExpression(cast<UnaryMinusExpression *>(expression)->expression);
- case Node::Kind_NotExpression:
- return "!" + parseExpression(cast<NotExpression *>(expression)->expression);
- case Node::Kind_TildeExpression:
- return "~" + parseExpression(cast<TildeExpression *>(expression)->expression);
- case Node::Kind_ConditionalExpression: {
- auto *condExpr = cast<ConditionalExpression *>(expression);
-
- QString result = "";
-
- result += parseExpression(condExpr->expression) + " ? ";
- result += parseExpression(condExpr->ok) + " : ";
- result += parseExpression(condExpr->ko);
-
- return result;
- }
- case Node::Kind_YieldExpression: {
- auto *yieldExpr = cast<YieldExpression*>(expression);
-
- QString result = "yield";
-
- if (yieldExpr->isYieldStar)
- result += "*";
-
- if (yieldExpr->expression)
- result += " " + parseExpression(yieldExpr->expression);
-
- return result;
- }
- case Node::Kind_ObjectPattern: {
- auto *objectPattern = cast<ObjectPattern*>(expression);
-
- if (objectPattern->properties == nullptr)
- return "{}";
-
- QString result = "{\n";
-
- m_indentLevel++;
- result += parsePatternPropertyList(objectPattern->properties);
- m_indentLevel--;
-
- result += formatLine("}", false);
-
- return result;
- }
- case Node::Kind_Expression: {
- auto* expr = cast<Expression*>(expression);
- return parseExpression(expr->left)+", "+parseExpression(expr->right);
- }
- case Node::Kind_TypeExpression: {
- auto* type = cast<TypeExpression*>(expression);
- return parseType(type->m_type);
- }
- case Node::Kind_RegExpLiteral: {
- auto* regexpLiteral = cast<RegExpLiteral*>(expression);
- QString result = "/"+regexpLiteral->pattern+"/";
-
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_Unicode)
- result += "u";
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_Global)
- result += "g";
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_Multiline)
- result += "m";
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_Sticky)
- result += "y";
- if (regexpLiteral->flags & QQmlJS::Lexer::RegExp_IgnoreCase)
- result += "i";
-
- return result;
- }
- default:
- m_error = true;
- return "unknown_expression_"+QString::number(expression->kind);
- }
-}
-
-QString DumpAstVisitor::parseVariableDeclarationList(VariableDeclarationList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next) {
- result += parsePatternElement(item->declaration, (item == list))
- + (item->next != nullptr ? ", " : "");
- }
-
- return result;
-}
-
-QString DumpAstVisitor::parseCaseBlock(CaseBlock *block)
-{
- QString result = "{\n";
-
- for (auto *item = block->clauses; item != nullptr; item = item->next) {
- result += formatLine("case "+parseExpression(item->clause->expression)+":");
- m_indentLevel++;
- result += parseStatementList(item->clause->statements);
- m_indentLevel--;
- }
-
- if (block->defaultClause) {
- result += formatLine("default:");
- m_indentLevel++;
- result += parseStatementList(block->defaultClause->statements);
- m_indentLevel--;
- }
-
- result += formatLine("}", false);
-
- return result;
-}
-
-QString DumpAstVisitor::parseExportSpecifier(ExportSpecifier *specifier)
-{
- QString result = specifier->identifier.toString();
-
- if (!specifier->exportedIdentifier.isEmpty())
- result += " as " + specifier->exportedIdentifier;
-
- return result;
-}
-
-QString DumpAstVisitor::parseExportsList(ExportsList *list)
-{
- QString result = "";
-
- for (auto *item = list; item != nullptr; item = item->next) {
- result += formatLine(parseExportSpecifier(item->exportSpecifier)
- + (item->next != nullptr ? "," : ""));
- }
-
- return result;
-}
-
-static bool needsSemicolon(int kind)
-{
- switch (kind) {
- case Node::Kind_ForStatement:
- case Node::Kind_ForEachStatement:
- case Node::Kind_IfStatement:
- case Node::Kind_SwitchStatement:
- case Node::Kind_WhileStatement:
- case Node::Kind_DoWhileStatement:
- case Node::Kind_TryStatement:
- case Node::Kind_WithStatement:
- return false;
- default:
- return true;
- }
-}
-
-QString DumpAstVisitor::parseBlock(Block *block, bool hasNext, bool allowBraceless)
-{
- bool hasOneLine =
- (block->statements != nullptr && block->statements->next == nullptr) && allowBraceless;
-
- QString result = hasOneLine ? "\n" : "{\n";
- m_indentLevel++;
- result += parseStatementList(block->statements);
- m_indentLevel--;
-
- if (hasNext)
- result += formatLine(hasOneLine ? "" : "} ", false);
-
- if (!hasNext && !hasOneLine)
- result += formatLine("}", false);
-
- if (block->statements) {
- m_blockNeededBraces |= !needsSemicolon(block->statements->statement->kind)
- || (block->statements->next != nullptr);
- } else {
- m_blockNeededBraces = true;
- }
-
- return result;
-}
-
-static bool endsWithSemicolon(const QStringView s)
-{
- return s.trimmed().endsWith(';');
-}
-
-QString DumpAstVisitor::parseStatement(Statement *statement, bool blockHasNext,
- bool blockAllowBraceless)
-{
- if (statement == nullptr)
- return "";
-
- switch (statement->kind)
- {
- case Node::Kind_EmptyStatement:
- return "";
- case Node::Kind_ExpressionStatement:
- return parseExpression(cast<ExpressionStatement *>(statement)->expression);
- case Node::Kind_VariableStatement:
- return parseVariableDeclarationList(cast<VariableStatement *>(statement)->declarations);
- case Node::Kind_ReturnStatement:
- return "return "+parseExpression(cast<ReturnStatement *>(statement)->expression);
- case Node::Kind_ContinueStatement:
- return "continue";
- case Node::Kind_BreakStatement:
- return "break";
- case Node::Kind_SwitchStatement: {
- auto *switchStatement = cast<SwitchStatement *>(statement);
-
- QString result = "switch ("+parseExpression(switchStatement->expression)+") ";
-
- result += parseCaseBlock(switchStatement->block);
-
- return result;
- }
- case Node::Kind_IfStatement: {
- auto *ifStatement = cast<IfStatement *>(statement);
-
- m_blockNeededBraces = !blockAllowBraceless;
-
- QString ifFalse = parseStatement(ifStatement->ko, false, true);
- QString ifTrue = parseStatement(ifStatement->ok, !ifFalse.isEmpty(), true);
-
- bool ifTrueBlock = ifStatement->ok->kind == Node::Kind_Block;
- bool ifFalseBlock = ifStatement->ko
- ? (ifStatement->ko->kind == Node::Kind_Block || ifStatement->ko->kind == Node::Kind_IfStatement)
- : false;
-
- if (m_blockNeededBraces) {
- ifFalse = parseStatement(ifStatement->ko, false, false);
- ifTrue = parseStatement(ifStatement->ok, !ifFalse.isEmpty(), false);
- }
-
- if (ifStatement->ok->kind != Node::Kind_Block && !endsWithSemicolon(ifTrue))
- ifTrue += ";";
-
- if (ifStatement->ko && ifStatement->ko->kind != Node::Kind_Block
- && ifStatement->ko->kind != Node::Kind_IfStatement && !endsWithSemicolon(ifFalse))
- ifFalse += ";";
-
- QString result = "if (" + parseExpression(ifStatement->expression) + ")";
-
- if (m_blockNeededBraces) {
- if (ifStatement->ok->kind != Node::Kind_Block) {
- QString result = "{\n";
- m_indentLevel++;
- result += formatLine(ifTrue);
- m_indentLevel--;
- result += formatLine("} ", false);
- ifTrue = result;
- ifTrueBlock = true;
- }
-
- if (ifStatement->ko && ifStatement->ko->kind != Node::Kind_Block && ifStatement->ko->kind != Node::Kind_IfStatement) {
- QString result = "{\n";
- m_indentLevel++;
- result += formatLine(ifFalse);
- m_indentLevel--;
- result += formatLine("} ", false);
- ifFalse = result;
- ifFalseBlock = true;
- }
- }
-
- if (ifTrueBlock) {
- result += " " + ifTrue;
- } else {
- result += "\n";
- m_indentLevel++;
- result += formatPartlyFormatedLines(ifTrue);
- m_indentLevel--;
- }
-
- if (!ifFalse.isEmpty())
- {
- if (ifTrueBlock)
- result += "else";
- else
- result += formatLine("else", false);
-
- if (ifFalseBlock) {
- // Blocks generate an extra newline that we don't want here.
- if (!m_blockNeededBraces && ifFalse.endsWith(QLatin1String("\n")))
- ifFalse.chop(1);
-
- result += " " + ifFalse;
- } else {
- result += "\n";
- m_indentLevel++;
- result += formatPartlyFormatedLines(ifFalse, false);
- m_indentLevel--;
- }
- }
-
- return result;
- }
- case Node::Kind_ForStatement: {
- auto *forStatement = cast<ForStatement *>(statement);
-
- QString expr = parseExpression(forStatement->expression);
- QString result = "for (";
-
- result += parseVariableDeclarationList(forStatement->declarations);
-
- result += "; ";
-
- result += parseExpression(forStatement->condition) + "; ";
- result += parseExpression(forStatement->expression)+")";
-
- const QString statement = parseStatement(forStatement->statement);
-
- if (!statement.isEmpty())
- result += " "+statement;
- else
- result += ";";
-
- return result;
- }
- case Node::Kind_ForEachStatement: {
- auto *forEachStatement = cast<ForEachStatement *>(statement);
-
- QString result = "for (";
-
- PatternElement *patternElement = cast<PatternElement *>(forEachStatement->lhs);
-
- if (patternElement != nullptr)
- result += parsePatternElement(patternElement);
- else
- result += parseExpression(forEachStatement->lhs->expressionCast());
-
- switch (forEachStatement->type)
- {
- case ForEachType::In:
- result += " in ";
- break;
- case ForEachType::Of:
- result += " of ";
- break;
- }
-
- result += parseExpression(forEachStatement->expression) + ")";
-
- const QString statement = parseStatement(forEachStatement->statement);
-
- if (!statement.isEmpty())
- result += " "+statement;
- else
- result += ";";
-
- return result;
- }
- case Node::Kind_WhileStatement: {
- auto *whileStatement = cast<WhileStatement *>(statement);
-
- m_blockNeededBraces = false;
-
- auto statement = parseStatement(whileStatement->statement, false, true);
-
- QString result = "while ("+parseExpression(whileStatement->expression) + ")";
-
- if (!statement.isEmpty())
- result += (m_blockNeededBraces ? " " : "") + statement;
- else
- result += ";";
-
- return result;
- }
- case Node::Kind_DoWhileStatement: {
- auto *doWhileStatement = cast<DoWhileStatement *>(statement);
- return "do " + parseBlock(cast<Block *>(doWhileStatement->statement), true, false)
- + "while (" + parseExpression(doWhileStatement->expression) + ")";
- }
- case Node::Kind_TryStatement: {
- auto *tryStatement = cast<TryStatement *>(statement);
-
- Catch *catchExpr = tryStatement->catchExpression;
- Finally *finallyExpr = tryStatement->finallyExpression;
-
- QString result;
-
- result += "try " + parseBlock(cast<Block *>(tryStatement->statement), true, false);
-
- result += "catch (" + parsePatternElement(catchExpr->patternElement, false) + ") "
- + parseBlock(cast<Block *>(catchExpr->statement), finallyExpr, false);
-
- if (finallyExpr) {
- result += "finally " + parseBlock(cast<Block *>(tryStatement->statement), false, false);
- }
-
- return result;
- }
- case Node::Kind_Block: {
- return parseBlock(cast<Block *>(statement), blockHasNext, blockAllowBraceless);
- }
- case Node::Kind_ThrowStatement:
- return "throw "+parseExpression(cast<ThrowStatement *>(statement)->expression);
- case Node::Kind_LabelledStatement: {
- auto *labelledStatement = cast<LabelledStatement *>(statement);
- QString result = labelledStatement->label+":\n";
- result += formatLine(parseStatement(labelledStatement->statement), false);
-
- return result;
- }
- case Node::Kind_WithStatement: {
- auto *withStatement = cast<WithStatement *>(statement);
- return "with (" + parseExpression(withStatement->expression) + ") "
- + parseStatement(withStatement->statement);
- }
- case Node::Kind_DebuggerStatement: {
- return "debugger";
- }
- case Node::Kind_ExportDeclaration:
- m_error = true;
- return "export_decl_unsupported";
- case Node::Kind_ImportDeclaration:
- m_error = true;
- return "import_decl_unsupported";
- default:
- m_error = true;
- return "unknown_statement_"+QString::number(statement->kind);
- }
-}
-
-QString DumpAstVisitor::parseStatementList(StatementList *list)
-{
- QString result = "";
-
- if (list == nullptr)
- return "";
-
- result += getOrphanedComments(list);
-
- for (auto *item = list; item != nullptr; item = item->next) {
- QString statement = parseStatement(item->statement->statementCast(), false, true);
- if (statement.isEmpty())
- continue;
-
- QString commentFront = getComment(item->statement, Comment::Location::Front);
- QString commentBackInline = getComment(item->statement, Comment::Location::Back_Inline);
-
- if (!commentFront.isEmpty())
- result += formatLine(commentFront);
-
- result += formatLine(statement + (needsSemicolon(item->statement->kind) ? ";" : "")
- + commentBackInline);
- }
-
- return result;
-}
-
-bool DumpAstVisitor::visit(UiPublicMember *node) {
-
- QString commentFront = getComment(node, Comment::Location::Front);
- QString commentBackInline = getComment(node, Comment::Location::Back_Inline);
-
- switch (node->type)
- {
- case UiPublicMember::Signal:
- if (scope().m_firstSignal) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstSignal = false;
- }
-
- addLine(commentFront);
- addLine("signal "+node->name.toString()+"("+parseUiParameterList(node->parameters) + ")"
- + commentBackInline);
- break;
- case UiPublicMember::Property: {
- if (scope().m_firstProperty) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstProperty = false;
- }
-
- const bool is_required = node->requiredToken.isValid();
- const bool is_default = node->defaultToken.isValid();
- const bool is_readonly = node->readonlyToken.isValid();
- const bool has_type_modifier = node->typeModifierToken.isValid();
-
- QString prefix = "";
- QString statement = parseStatement(node->statement);
-
- if (!statement.isEmpty())
- statement.prepend(": ");
-
- if (is_required)
- prefix += "required ";
-
- if (is_default)
- prefix += "default ";
-
- if (is_readonly)
- prefix += "readonly ";
-
- QString member_type = parseUiQualifiedId(node->memberType);
-
- if (has_type_modifier)
- member_type = node->typeModifier + "<" + member_type + ">";
-
- addLine(commentFront);
- if (is_readonly && statement.isEmpty()
- && scope().m_bindings.contains(node->name.toString())) {
- m_result += formatLine(prefix + "property " + member_type + " ", false);
-
- scope().m_pendingBinding = true;
- } else {
- addLine(prefix + "property " + member_type + " "
- + node->name+statement + commentBackInline);
- }
- break;
- }
- }
-
- return true;
-}
-
-QString DumpAstVisitor::generateIndent(int indentLevel) const
-{
- return QString(m_indentWidth * indentLevel, m_indentation == Indentation::Tabs ? '\t' : ' ');
-}
-
-QString DumpAstVisitor::formatLine(QString line, bool newline) const
-{
- QString result = generateIndent(m_indentLevel) + line;
- if (newline)
- result += "\n";
-
- return result;
-}
-
-QString DumpAstVisitor::formatPartlyFormatedLines(QString line, bool newline) const
-{
- QString result;
-
- const auto lines = QStringView { line }.split('\n');
- auto it = lines.cbegin();
- const auto endi = lines.cend();
- if (it != endi) {
- result += generateIndent(m_indentLevel) + *it;
- ++it;
- const QString addonIdent = generateIndent(1);
- for (; it != endi; ++it) {
- result += '\n';
- result += addonIdent + *it;
- }
- }
-
- if (newline)
- result += "\n";
-
- return result;
-}
-
-void DumpAstVisitor::addNewLine(bool always) {
- if (!always && m_result.endsWith("\n\n"))
- return;
-
- m_result += "\n";
-}
-
-void DumpAstVisitor::addLine(QString line) {
- // addLine does not support empty lines, use addNewLine(true) for that
- if (line.isEmpty())
- return;
-
- m_result += formatLine(line);
-}
-
-QHash<QString, UiObjectMember*> findBindings(UiObjectMemberList *list) {
- QHash<QString, UiObjectMember*> bindings;
-
- // This relies on RestructureASTVisitor having run beforehand
-
- for (auto *item = list; item != nullptr; item = item->next) {
- switch (item->member->kind) {
- case Node::Kind_UiPublicMember: {
- UiPublicMember *member = cast<UiPublicMember *>(item->member);
-
- if (member->type != UiPublicMember::Property)
- continue;
-
- bindings[member->name.toString()] = nullptr;
-
- break;
- }
- case Node::Kind_UiObjectBinding: {
- UiObjectBinding *binding = cast<UiObjectBinding *>(item->member);
-
- const QString name = parseUiQualifiedId(binding->qualifiedId);
-
- if (bindings.contains(name))
- bindings[name] = binding;
-
- break;
- }
- case Node::Kind_UiArrayBinding: {
- UiArrayBinding *binding = cast<UiArrayBinding *>(item->member);
-
- const QString name = parseUiQualifiedId(binding->qualifiedId);
-
- if (bindings.contains(name))
- bindings[name] = binding;
-
- break;
- }
- case Node::Kind_UiScriptBinding:
- // We can ignore UiScriptBindings since those are actually properly attached to the property
- break;
- }
- }
-
- return bindings;
-}
-
-bool DumpAstVisitor::visit(UiInlineComponent *node)
-{
- m_component_name = node->name.toString();
- return true;
-}
-
-bool DumpAstVisitor::visit(UiObjectDefinition *node) {
- if (scope().m_firstObject) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstObject = false;
- }
-
- addLine(getComment(node, Comment::Location::Front));
- addLine(getComment(node, Comment::Location::Front_Inline));
-
- QString component = "";
-
- if (!m_component_name.isEmpty()) {
- component = "component "+m_component_name+": ";
- m_component_name = "";
- }
-
- addLine(component + parseUiQualifiedId(node->qualifiedTypeNameId) + " {");
-
- m_indentLevel++;
-
- ScopeProperties props;
- props.m_bindings = findBindings(node->initializer->members);
- m_scope_properties.push(props);
-
- m_result += getOrphanedComments(node);
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiObjectDefinition *node) {
- m_indentLevel--;
-
- m_scope_properties.pop();
-
- bool need_comma = scope().m_inArrayBinding && scope().m_lastInArrayBinding != node;
-
- addLine(need_comma ? "}," : "}");
- addLine(getComment(node, Comment::Location::Back));
- if (!scope().m_inArrayBinding)
- addNewLine();
-}
-
-bool DumpAstVisitor::visit(UiEnumDeclaration *node) {
-
- addNewLine();
-
- addLine(getComment(node, Comment::Location::Front));
- addLine("enum " + node->name + " {");
- m_indentLevel++;
- m_result += getOrphanedComments(node);
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiEnumDeclaration *) {
- m_indentLevel--;
- addLine("}");
-
- addNewLine();
-}
-
-bool DumpAstVisitor::visit(UiEnumMemberList *node) {
- for (auto *members = node; members != nullptr; members = members->next) {
-
- addLine(getListItemComment(members->memberToken, Comment::Location::Front));
-
- QString line = members->member.toString();
-
- if (members->valueToken.isValid())
- line += " = "+QString::number(members->value);
-
- if (members->next != nullptr)
- line += ",";
-
- line += getListItemComment(members->memberToken, Comment::Location::Back_Inline);
-
- addLine(line);
- }
-
- return true;
-}
-
-bool DumpAstVisitor::visit(UiScriptBinding *node) {
- if (scope().m_firstBinding) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- if (parseUiQualifiedId(node->qualifiedId) != "id")
- scope().m_firstBinding = false;
- }
-
- addLine(getComment(node, Comment::Location::Front));
-
- bool multiline = !needsSemicolon(node->statement->kind);
-
- if (multiline) {
- m_indentLevel++;
- }
-
- QString statement = parseStatement(node->statement);
-
- if (multiline) {
- statement = "{\n" + formatLine(statement);
- m_indentLevel--;
- statement += formatLine("}", false);
- }
-
- QString result = parseUiQualifiedId(node->qualifiedId) + ":";
-
- if (!statement.isEmpty())
- result += " "+statement;
- else
- result += ";";
-
- result += getComment(node, Comment::Location::Back_Inline);
-
- addLine(result);
-
- return true;
-}
-
-bool DumpAstVisitor::visit(UiArrayBinding *node) {
- if (!scope().m_pendingBinding && scope().m_firstBinding) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstBinding = false;
- }
-
- if (scope().m_pendingBinding) {
- m_result += parseUiQualifiedId(node->qualifiedId)+ ": [\n";
- scope().m_pendingBinding = false;
- } else {
- addLine(getComment(node, Comment::Location::Front));
- addLine(parseUiQualifiedId(node->qualifiedId)+ ": [");
- }
-
- m_indentLevel++;
-
- ScopeProperties props;
- props.m_inArrayBinding = true;
-
- for (auto *item = node->members; item != nullptr; item = item->next) {
- if (item->next == nullptr)
- props.m_lastInArrayBinding = item->member;
- }
-
- m_scope_properties.push(props);
-
- m_result += getOrphanedComments(node);
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiArrayBinding *) {
- m_indentLevel--;
- m_scope_properties.pop();
- addLine("]");
-}
-
-bool DumpAstVisitor::visit(FunctionDeclaration *node) {
- if (scope().m_firstFunction) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstFunction = false;
- }
-
- addLine(getComment(node, Comment::Location::Front));
-
- QString head = "function";
-
- if (node->isGenerator)
- head += "*";
-
- head += " "+node->name+"("+parseFormalParameterList(node->formals)+")";
-
- if (node->typeAnnotation != nullptr)
- head += " : " + parseType(node->typeAnnotation->type);
-
- head += " {";
-
- addLine(head);
- m_indentLevel++;
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(FunctionDeclaration *node)
-{
- m_result += parseStatementList(node->body);
- m_indentLevel--;
- addLine("}");
- addNewLine();
-}
-
-bool DumpAstVisitor::visit(UiObjectBinding *node) {
- if (!scope().m_pendingBinding && scope().m_firstObject) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstObject = false;
- }
-
- QString name = parseUiQualifiedId(node->qualifiedTypeNameId);
-
- QString result = name;
-
- ScopeProperties props;
- props.m_bindings = findBindings(node->initializer->members);
- m_scope_properties.push(props);
-
- if (node->hasOnToken)
- result += " on "+parseUiQualifiedId(node->qualifiedId);
- else
- result.prepend(parseUiQualifiedId(node->qualifiedId) + ": ");
-
- if (scope().m_pendingBinding) {
- m_result += result + " {\n";
-
- scope().m_pendingBinding = false;
- } else {
- addNewLine();
- addLine(getComment(node, Comment::Location::Front));
- addLine(getComment(node, Comment::Location::Front_Inline));
- addLine(result + " {");
- }
-
- m_indentLevel++;
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiObjectBinding *node) {
- m_indentLevel--;
- m_scope_properties.pop();
-
- addLine("}");
- addLine(getComment(node, Comment::Location::Back));
-
- addNewLine();
-}
-
-bool DumpAstVisitor::visit(UiImport *node) {
- scope().m_firstOfAll = false;
-
- addLine(getComment(node, Comment::Location::Front));
-
- QString result = "import ";
-
- if (!node->fileName.isEmpty())
- result += escapeString(node->fileName.toString());
- else
- result += parseUiQualifiedId(node->importUri);
-
- if (node->version) {
- const auto version = node->version->version;
-
- if (version.hasMajorVersion()) {
- result += " " + QString::number(version.majorVersion());
-
- if (version.hasMinorVersion())
- result += "." + QString::number(version.minorVersion());
- }
- }
-
- if (node->asToken.isValid()) {
- result +=" as " + node->importId;
- }
-
- result += getComment(node, Comment::Location::Back_Inline);
-
- addLine(result);
-
- return true;
-}
-
-bool DumpAstVisitor::visit(UiPragma *node) {
- scope().m_firstOfAll = false;
-
- addLine(getComment(node, Comment::Location::Front));
- QString result = "pragma "+ node->name;
- result += getComment(node, Comment::Location::Back_Inline);
-
- addLine(result);
-
- return true;
-}
-
-bool DumpAstVisitor::visit(UiAnnotation *node)
-{
- if (scope().m_firstObject) {
- if (scope().m_firstOfAll)
- scope().m_firstOfAll = false;
- else
- addNewLine();
-
- scope().m_firstObject = false;
- }
-
- addLine(getComment(node, Comment::Location::Front));
- addLine(QLatin1String("@") + parseUiQualifiedId(node->qualifiedTypeNameId) + " {");
-
- m_indentLevel++;
-
- ScopeProperties props;
- props.m_bindings = findBindings(node->initializer->members);
- m_scope_properties.push(props);
-
- m_result += getOrphanedComments(node);
-
- return true;
-}
-
-void DumpAstVisitor::endVisit(UiAnnotation *node) {
- m_indentLevel--;
-
- m_scope_properties.pop();
-
- addLine("}");
- addLine(getComment(node, Comment::Location::Back));
-}
diff --git a/tools/qmlformat/dumpastvisitor.h b/tools/qmlformat/dumpastvisitor.h
deleted file mode 100644
index 7d37a4b90f..0000000000
--- a/tools/qmlformat/dumpastvisitor.h
+++ /dev/null
@@ -1,158 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef DUMPAST_H
-#define DUMPAST_H
-
-#include <QtQml/private/qqmljsastvisitor_p.h>
-#include <QtQml/private/qqmljsast_p.h>
-
-#include <QHash>
-#include <QStack>
-
-#include "commentastvisitor.h"
-
-class DumpAstVisitor : protected QQmlJS::AST::Visitor
-{
-public:
- enum Indentation { Tabs, Spaces };
-
- DumpAstVisitor(QQmlJS::Engine *engine, QQmlJS::AST::Node *rootNode, CommentAstVisitor *comment,
- int indentWidth, Indentation indentation);
-
- QString toString() const { return m_result; }
-
- bool preVisit(QQmlJS::AST::Node *) override;
-
- bool visit(QQmlJS::AST::UiScriptBinding *node) override;
-
- bool visit(QQmlJS::AST::UiArrayBinding *node) override;
- void endVisit(QQmlJS::AST::UiArrayBinding *node) override;
-
- bool visit(QQmlJS::AST::UiObjectBinding *node) override;
- void endVisit(QQmlJS::AST::UiObjectBinding *node) override;
-
- bool visit(QQmlJS::AST::FunctionDeclaration *node) override;
- void endVisit(QQmlJS::AST::FunctionDeclaration *node) override;
-
- bool visit(QQmlJS::AST::UiInlineComponent *node) override;
-
- bool visit(QQmlJS::AST::UiObjectDefinition *node) override;
- void endVisit(QQmlJS::AST::UiObjectDefinition *node) override;
-
- bool visit(QQmlJS::AST::UiEnumDeclaration *node) override;
- void endVisit(QQmlJS::AST::UiEnumDeclaration *node) override;
-
- bool visit(QQmlJS::AST::UiEnumMemberList *node) override;
- bool visit(QQmlJS::AST::UiPublicMember *node) override;
- bool visit(QQmlJS::AST::UiImport *node) override;
- bool visit(QQmlJS::AST::UiPragma *node) override;
-
- bool visit(QQmlJS::AST::UiAnnotation *node) override;
- void endVisit(QQmlJS::AST::UiAnnotation *node) override;
-
- void throwRecursionDepthError() override {}
-
- bool error() const { return m_error; }
-private:
- struct ScopeProperties {
- bool m_firstOfAll = true;
- bool m_firstSignal = true;
- bool m_firstProperty = true;
- bool m_firstBinding = true;
- bool m_firstObject = true;
- bool m_firstFunction = true;
- bool m_inArrayBinding = false;
- bool m_pendingBinding = false;
-
- QQmlJS::AST::UiObjectMember* m_lastInArrayBinding = nullptr;
- QHash<QString, QQmlJS::AST::UiObjectMember*> m_bindings;
- };
-
- QString generateIndent(int indentLevel) const;
- QString formatLine(QString line, bool newline = true) const;
- QString formatPartlyFormatedLines(QString line, bool newline = true) const;
-
- QString formatComment(const Comment &comment) const;
-
- QString getComment(QQmlJS::AST::Node *node, Comment::Location location) const;
- QString getListItemComment(QQmlJS::SourceLocation srcLocation, Comment::Location location) const;
-
- void addNewLine(bool always = false);
- void addLine(QString line);
-
- QString getOrphanedComments(QQmlJS::AST::Node *node) const;
-
- QString parseStatement(QQmlJS::AST::Statement *statement, bool blockHasNext = false,
- bool blockAllowBraceless = false);
- QString parseStatementList(QQmlJS::AST::StatementList *list);
-
- QString parseExpression(QQmlJS::AST::ExpressionNode *expression);
-
- QString parsePatternElement(QQmlJS::AST::PatternElement *element, bool scope = true);
- QString parsePatternElementList(QQmlJS::AST::PatternElementList *element);
-
- QString parsePatternProperty(QQmlJS::AST::PatternProperty *property);
- QString parsePatternPropertyList(QQmlJS::AST::PatternPropertyList *list);
-
- QString parseArgumentList(QQmlJS::AST::ArgumentList *list);
-
- QString parseUiParameterList(QQmlJS::AST::UiParameterList *list);
-
- QString parseVariableDeclarationList(QQmlJS::AST::VariableDeclarationList *list);
-
- QString parseCaseBlock(QQmlJS::AST::CaseBlock *block);
- QString parseBlock(QQmlJS::AST::Block *block, bool hasNext, bool allowBraceless);
-
- QString parseExportsList(QQmlJS::AST::ExportsList *list);
- QString parseExportSpecifier(QQmlJS::AST::ExportSpecifier *specifier);
-
- QString parseFormalParameterList(QQmlJS::AST::FormalParameterList *list);
-
- QString parseType(QQmlJS::AST::Type *type);
-
- QString parseFunctionExpression(QQmlJS::AST::FunctionExpression *expression, bool omitFunction = false);
-
- ScopeProperties& scope() { return m_scope_properties.top(); }
-
- int m_indentLevel = 0;
-
- bool m_error = false;
- bool m_blockNeededBraces = false;
-
- QStack<ScopeProperties> m_scope_properties;
-
- QString m_result = "";
- QString m_component_name = "";
- QQmlJS::Engine *m_engine;
- CommentAstVisitor *m_comment;
- int m_indentWidth;
- Indentation m_indentation;
-};
-
-#endif // DUMPAST_H
diff --git a/tools/qmlformat/main.cpp b/tools/qmlformat/qmlformat.cpp
index 3f11ce257a..7f7cdfbb24 100644
--- a/tools/qmlformat/main.cpp
+++ b/tools/qmlformat/qmlformat.cpp
@@ -35,14 +35,16 @@
#include <QtQml/private/qqmljsengine_p.h>
#include <QtQml/private/qqmljsastvisitor_p.h>
#include <QtQml/private/qqmljsast_p.h>
+#include <QtQmlDom/private/qqmldomitem_p.h>
+#include <QtQmlDom/private/qqmldomexternalitems_p.h>
+#include <QtQmlDom/private/qqmldomtop_p.h>
+#include <QtQmlDom/private/qqmldomoutwriter_p.h>
#if QT_CONFIG(commandlineparser)
-#include <QCommandLineParser>
+# include <QCommandLineParser>
#endif
-#include "commentastvisitor.h"
-#include "dumpastvisitor.h"
-#include "restructureastvisitor.h"
+using namespace QQmlJS::Dom;
struct Options
{
@@ -51,6 +53,7 @@ struct Options
bool force = false;
bool tabs = false;
bool valid = false;
+ bool normalize = false;
int indentWidth = 4;
bool indentWidthSet = false;
@@ -63,121 +66,94 @@ struct Options
bool parseFile(const QString &filename, const Options &options)
{
- QFile file(filename);
-
- if (!file.open(QIODevice::Text | QIODevice::ReadOnly)) {
- qWarning().noquote() << "Failed to open" << filename << "for reading.";
- return false;
- }
-
- QString code = QString::fromUtf8(file.readAll());
- file.close();
-
- QQmlJS::Engine engine;
- QQmlJS::Lexer lexer(&engine);
-
- lexer.setCode(code, 1, true);
- QQmlJS::Parser parser(&engine);
-
- bool success = parser.parse();
-
- if (!success) {
- const auto diagnosticMessages = parser.diagnosticMessages();
- for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
- qWarning().noquote() << QString::fromLatin1("%1:%2 : %3")
- .arg(filename).arg(m.loc.startLine).arg(m.message);
- }
-
+ DomItem env =
+ DomEnvironment::create(QStringList(),
+ QQmlJS::Dom::DomEnvironment::Option::SingleThreaded
+ | QQmlJS::Dom::DomEnvironment::Option::NoDependencies);
+ DomItem tFile; // place where to store the loaded file
+ env.loadFile(
+ filename, QString(),
+ [&tFile](Path, const DomItem &, const DomItem &newIt) {
+ tFile = newIt; // callback called when everything is loaded that receives the loaded
+ // external file pair (path, oldValue, newValue)
+ },
+ LoadOption::DefaultLoad);
+ env.loadPendingDependencies();
+ DomItem qmlFile = tFile.fileObject();
+ std::shared_ptr<QmlFile> qmlFilePtr = qmlFile.ownerAs<QmlFile>();
+ if (!qmlFilePtr || !qmlFilePtr->isValid()) {
+ qmlFile.iterateErrors(
+ [](DomItem, ErrorMessage msg) {
+ errorToQDebug(msg);
+ return true;
+ },
+ true);
qWarning().noquote() << "Failed to parse" << filename;
return false;
}
- // Try to attach comments to AST nodes
- CommentAstVisitor comment(&engine, parser.rootNode());
-
- if (options.verbose)
- qWarning().noquote() << comment.attachedComments().size() << "comment(s) attached.";
-
- if (options.verbose) {
- int orphaned = 0;
-
- for (const auto& orphanList : comment.orphanComments().values())
- orphaned += orphanList.size();
-
- qWarning().noquote() << orphaned << "comments are orphans.";
- }
-
- // Do the actual restructuring
- RestructureAstVisitor restructure(parser.rootNode());
-
// Turn AST back into source code
if (options.verbose)
qWarning().noquote() << "Dumping" << filename;
- DumpAstVisitor dump(
- &engine, parser.rootNode(), &comment, options.tabs ? 1 : options.indentWidth,
- options.tabs ? DumpAstVisitor::Indentation::Tabs : DumpAstVisitor::Indentation::Spaces);
-
- QString dumpCode = dump.toString();
-
- lexer.setCode(dumpCode, 1, true);
-
- bool dumpSuccess = parser.parse();
-
- if (!dumpSuccess) {
- if (options.verbose) {
- const auto diagnosticMessages = parser.diagnosticMessages();
- for (const QQmlJS::DiagnosticMessage &m : diagnosticMessages) {
- qWarning().noquote() << QString::fromLatin1("<formatted>:%2 : %3")
- .arg(m.loc.startLine).arg(m.message);
+ LineWriterOptions lwOptions;
+ lwOptions.formatOptions.indentSize = options.indentWidth;
+ lwOptions.formatOptions.useTabs = options.tabs;
+ lwOptions.updateOptions = LineWriterOptions::Update::None;
+ if (options.newline == "native") {
+ // find out current line endings...
+ QStringView code = qmlFilePtr->code();
+ int newlineIndex = code.indexOf(QChar(u'\n'));
+ int crIndex = code.indexOf(QChar(u'\r'));
+ if (newlineIndex >= 0) {
+ if (crIndex >= 0) {
+ if (crIndex + 1 == newlineIndex)
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::Windows;
+ else
+ qWarning().noquote() << "Invalid line ending in file, using default";
+
+ } else {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::Unix;
}
+ } else if (crIndex >= 0) {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::OldMacOs;
+ } else {
+ qWarning().noquote() << "Unknown line ending in file, using default";
}
-
- qWarning().noquote() << "Failed to parse formatted code.";
+ } else if (options.newline == "macos") {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::OldMacOs;
+ } else if (options.newline == "windows") {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::Windows;
+ } else if (options.newline == "unix") {
+ lwOptions.lineEndings = LineWriterOptions::LineEndings::Unix;
+ } else {
+ qWarning().noquote() << "Unknown line ending type" << options.newline;
+ return false;
}
- if (dump.error() || !dumpSuccess) {
- if (options.force) {
- qWarning().noquote() << "An error has occurred. The output may not be reliable.";
- } else {
- qWarning().noquote() << "An error has occurred. Aborting.";
- return false;
- }
- }
-
- const bool native = options.newline == "native";
-
- if (!native) {
- if (options.newline == "macos") {
- dumpCode = dumpCode.replace("\n", "\r");
- } else if (options.newline == "windows") {
- dumpCode = dumpCode.replace("\n", "\r\n");
- } else if (options.newline == "unix") {
- // Nothing needs to be done for unix line-endings
- } else {
- qWarning().noquote() << "Unknown line ending type" << options.newline;
- return false;
- }
- }
-
- if (options.inplace) {
- if (options.verbose)
- qWarning().noquote() << "Writing to file" << filename;
-
- if (!file.open(native ? QIODevice::WriteOnly | QIODevice::Text : QIODevice::WriteOnly)) {
- qWarning().noquote() << "Failed to open" << filename << "for writing";
- return false;
- }
-
- file.write(dumpCode.toUtf8());
- file.close();
- } else {
- QFile out;
- out.open(stdout, QIODevice::WriteOnly);
- out.write(dumpCode.toUtf8());
- }
-
- return true;
+ if (options.normalize)
+ lwOptions.attributesSequence = LineWriterOptions::AttributesSequence::Normalize;
+ else
+ lwOptions.attributesSequence = LineWriterOptions::AttributesSequence::Preserve;
+ WriteOutChecks checks = WriteOutCheck::Default;
+ if (options.force || qmlFilePtr->code().size() > 32000)
+ checks = WriteOutCheck::None;
+
+ MutableDomItem res;
+ if (options.inplace) {
+ if (options.verbose)
+ qWarning().noquote() << "Writing to file" << filename;
+ FileWriter fw;
+ res = qmlFile.writeOut(filename, 2, lwOptions, &fw, checks);
+ } else {
+ QFile out;
+ out.open(stdout, QIODevice::WriteOnly);
+ LineWriter lw([&out](QStringView s) { out.write(s.toUtf8()); }, filename, lwOptions);
+ OutWriter ow(lw);
+ res = qmlFile.writeOutForFile(ow, checks);
+ ow.flush();
+ }
+ return bool(res);
}
Options buildCommandLineOptions(const QCoreApplication &app)
@@ -188,14 +164,16 @@ Options buildCommandLineOptions(const QCoreApplication &app)
parser.addHelpOption();
parser.addVersionOption();
- parser.addOption(QCommandLineOption({"V", "verbose"},
- QStringLiteral("Verbose mode. Outputs more detailed information.")));
+ parser.addOption(
+ QCommandLineOption({ "V", "verbose" },
+ QStringLiteral("Verbose mode. Outputs more detailed information.")));
- parser.addOption(QCommandLineOption({"i", "inplace"},
- QStringLiteral("Edit file in-place instead of outputting to stdout.")));
+ parser.addOption(QCommandLineOption(
+ { "i", "inplace" },
+ QStringLiteral("Edit file in-place instead of outputting to stdout.")));
- parser.addOption(QCommandLineOption({"f", "force"},
- QStringLiteral("Continue even if an error has occurred.")));
+ parser.addOption(QCommandLineOption({ "f", "force" },
+ QStringLiteral("Continue even if an error has occurred.")));
parser.addOption(
QCommandLineOption({ "t", "tabs" }, QStringLiteral("Use tabs instead of spaces.")));
@@ -204,12 +182,17 @@ Options buildCommandLineOptions(const QCoreApplication &app)
QStringLiteral("How many spaces are used when indenting."),
"width", "4"));
+ parser.addOption(QCommandLineOption({ "n", "normalize" },
+ QStringLiteral("Reorders the attributes of the objects "
+ "according to the QML Coding Guidelines.")));
+
parser.addOption(QCommandLineOption(
{ "F", "files" }, QStringLiteral("Format all files listed in file, in-place"), "file"));
- parser.addOption(QCommandLineOption({"l", "newline"},
- QStringLiteral("Override the new line format to use (native macos unix windows)."),
- "newline", "native"));
+ parser.addOption(QCommandLineOption(
+ { "l", "newline" },
+ QStringLiteral("Override the new line format to use (native macos unix windows)."),
+ "newline", "native"));
parser.addPositionalArgument("filenames", "files to be processed by qmlformat");
@@ -224,7 +207,7 @@ Options buildCommandLineOptions(const QCoreApplication &app)
}
QStringList files;
- if (parser.isSet("files")) {
+ if (!parser.value("files").isEmpty()) {
QFile file(parser.value("files"));
file.open(QIODevice::Text | QIODevice::ReadOnly);
if (file.isOpen()) {
@@ -245,6 +228,7 @@ Options buildCommandLineOptions(const QCoreApplication &app)
options.inplace = parser.isSet("inplace");
options.force = parser.isSet("force");
options.tabs = parser.isSet("tabs");
+ options.normalize = parser.isSet("normalize");
options.valid = true;
options.indentWidth = indentWidth;
diff --git a/tools/qmlformat/restructureastvisitor.cpp b/tools/qmlformat/restructureastvisitor.cpp
deleted file mode 100644
index 18021a0a2a..0000000000
--- a/tools/qmlformat/restructureastvisitor.cpp
+++ /dev/null
@@ -1,196 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#include "restructureastvisitor.h"
-
-#include <QList>
-
-using namespace QQmlJS::AST;
-
-RestructureAstVisitor::RestructureAstVisitor(Node *rootNode)
-{
- rootNode->accept(this);
-}
-
-template<typename T>
-static QList<T *> findKind(UiObjectMemberList *list)
-{
- QList<T *> members;
- for (auto *item = list; item != nullptr; item = item->next) {
- if (cast<T *>(item->member) != nullptr)
- members.append(cast<T *>(item->member));
- }
-
- return members;
-}
-
-template<typename T>
-static QList<T *> findKind(UiHeaderItemList *list)
-{
- QList<T *> members;
- for (auto *item = list; item != nullptr; item = item->next) {
- if (cast<T *>(item->headerItem) != nullptr)
- members.append(cast<T *>(item->headerItem));
- }
-
- return members;
-}
-
-static QString parseUiQualifiedId(UiQualifiedId *id)
-{
- QString name = id->name.toString();
- for (auto *item = id->next; item != nullptr; item = item->next) {
- name += "." + item->name;
- }
-
- return name;
-}
-
-void RestructureAstVisitor::endVisit(UiObjectMemberList *node)
-{
- QList<UiObjectMember*> correctOrder;
-
- QList<UiScriptBinding*> largeScriptBinding;
-
- UiObjectMember *states = nullptr;
- UiObjectMember *transitions = nullptr;
-
- auto enumDeclarations = findKind<UiEnumDeclaration>(node);
- auto scriptBindings = findKind<UiScriptBinding>(node);
- auto arrayBindings = findKind<UiArrayBinding>(node);
- auto publicMembers = findKind<UiPublicMember>(node);
- auto sourceElements = findKind<UiSourceElement>(node);
- auto objectDefinitions = findKind<UiObjectDefinition>(node);
-
- // Look for transitions and states
- for (auto *binding : findKind<UiObjectBinding>(node)) {
- const QString name = parseUiQualifiedId(binding->qualifiedId);
-
- if (name == "transitions")
- transitions = binding;
- else if (name == "states")
- states = binding;
- }
-
- for (auto it = arrayBindings.begin(); it != arrayBindings.end();) {
- const QString name = parseUiQualifiedId((*it)->qualifiedId);
-
- if (name == "transitions") {
- transitions = *it;
- it = arrayBindings.erase(it);
- } else if (name == "states") {
- states = *it;
- it = arrayBindings.erase(it);
- } else {
- it++;
- }
- }
-
- // Find large script bindings
- for (auto it = scriptBindings.begin(); it != scriptBindings.end();) {
- // A binding is considered large if it uses a block
- if ((*it)->statement->kind != Node::Kind_Block) {
- it++;
- continue;
- }
-
- largeScriptBinding.push_back(*it);
- it = scriptBindings.erase(it);
- }
-
- // This structure is based on https://doc.qt.io/qt-5/qml-codingconventions.html
-
- // 1st id
- for (auto *binding : scriptBindings) {
- if (parseUiQualifiedId(binding->qualifiedId) == "id") {
- correctOrder.append(binding);
-
- scriptBindings.removeOne(binding);
- break;
- }
- }
-
- // 2nd enums
- for (auto *enumDeclaration : enumDeclarations)
- correctOrder.append(enumDeclaration);
-
- // 3rd property declarations
- for (auto *publicMember : publicMembers) {
- if (publicMember->type != UiPublicMember::Property)
- continue;
-
- correctOrder.append(publicMember);
- }
-
- // 4th signals
- for (auto *publicMember : publicMembers) {
- if (publicMember->type != UiPublicMember::Signal)
- continue;
-
- correctOrder.append(publicMember);
- }
-
- // 5th functions
- for (auto *source : sourceElements)
- correctOrder.append(source);
-
- // 6th properties
- // small script bindings...
- for (auto *binding : scriptBindings)
- correctOrder.append(binding);
-
- // ...then large ones
- for (auto *binding : largeScriptBinding)
- correctOrder.append(binding);
-
- for (auto *binding : arrayBindings)
- correctOrder.append(binding);
-
- // 7th child objects
- for (auto *objectDefinition : objectDefinitions)
- correctOrder.append(objectDefinition);
-
- // 8th all the rest
- for (auto *item = node; item != nullptr; item = item->next) {
- if (!correctOrder.contains(item->member))
- correctOrder.append(item->member);
- }
-
- // 9th states and transitions
- if (states != nullptr)
- correctOrder.append(states);
-
- if (transitions != nullptr)
- correctOrder.append(transitions);
-
- // Rebuild member list from correctOrder
- for (auto *item = node; item != nullptr; item = item->next) {
- item->member = correctOrder.front();
- correctOrder.pop_front();
- }
-}
diff --git a/tools/qmlformat/restructureastvisitor.h b/tools/qmlformat/restructureastvisitor.h
deleted file mode 100644
index 4d1cb7e643..0000000000
--- a/tools/qmlformat/restructureastvisitor.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/****************************************************************************
-**
-** Copyright (C) 2019 The Qt Company Ltd.
-** Contact: https://www.qt.io/licensing/
-**
-** This file is part of the tools applications of the Qt Toolkit.
-**
-** $QT_BEGIN_LICENSE:GPL-EXCEPT$
-** Commercial License Usage
-** Licensees holding valid commercial Qt licenses may use this file in
-** accordance with the commercial license agreement provided with the
-** Software or, alternatively, in accordance with the terms contained in
-** a written agreement between you and The Qt Company. For licensing terms
-** and conditions see https://www.qt.io/terms-conditions. For further
-** information use the contact form at https://www.qt.io/contact-us.
-**
-** GNU General Public License Usage
-** Alternatively, this file may be used under the terms of the GNU
-** General Public License version 3 as published by the Free Software
-** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
-** included in the packaging of this file. Please review the following
-** information to ensure the GNU General Public License requirements will
-** be met: https://www.gnu.org/licenses/gpl-3.0.html.
-**
-** $QT_END_LICENSE$
-**
-****************************************************************************/
-
-#ifndef RESTRUCTUREASTVISITOR_H
-#define RESTRUCTUREASTVISITOR_H
-
-#include <QtQml/private/qqmljsastvisitor_p.h>
-#include <QtQml/private/qqmljsast_p.h>
-
-class RestructureAstVisitor : protected QQmlJS::AST::Visitor
-{
-public:
- RestructureAstVisitor(QQmlJS::AST::Node *rootNode);
-
- void throwRecursionDepthError() override {}
-
- void endVisit(QQmlJS::AST::UiObjectMemberList *node) override;
-};
-
-#endif // RESTRUCTUREASTVISITOR_H