1/****************************************************************************
2**
3** Copyright (C) 2019 The Qt Company Ltd.
4** Contact: https://www.qt.io/licensing/
5**
6** This file is part of the tools applications of the Qt Toolkit.
7**
8** $QT_BEGIN_LICENSE:GPL-EXCEPT$
9** Commercial License Usage
10** Licensees holding valid commercial Qt licenses may use this file in
11** accordance with the commercial license agreement provided with the
12** Software or, alternatively, in accordance with the terms contained in
13** a written agreement between you and The Qt Company. For licensing terms
14** and conditions see https://www.qt.io/terms-conditions. For further
15** information use the contact form at https://www.qt.io/contact-us.
16**
17** GNU General Public License Usage
18** Alternatively, this file may be used under the terms of the GNU
19** General Public License version 3 as published by the Free Software
20** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
21** included in the packaging of this file. Please review the following
22** information to ensure the GNU General Public License requirements will
23** be met: https://www.gnu.org/licenses/gpl-3.0.html.
24**
25** $QT_END_LICENSE$
26**
27****************************************************************************/
28
29#include "restructureastvisitor.h"
30
31#include <QList>
32
33RestructureAstVisitor::RestructureAstVisitor(Node *rootNode, bool sortImports) : m_sortImports(sortImports)
34{
35 rootNode->accept(visitor: this);
36}
37
38template<typename T>
39static QList<T *> findKind(UiObjectMemberList *list)
40{
41 QList<T *> members;
42 for (auto *item = list; item != nullptr; item = item->next) {
43 if (cast<T *>(item->member) != nullptr)
44 members.append(cast<T *>(item->member));
45 }
46
47 return members;
48}
49
50template<typename T>
51static QList<T *> findKind(UiHeaderItemList *list)
52{
53 QList<T *> members;
54 for (auto *item = list; item != nullptr; item = item->next) {
55 if (cast<T *>(item->headerItem) != nullptr)
56 members.append(cast<T *>(item->headerItem));
57 }
58
59 return members;
60}
61
62static QString parseUiQualifiedId(UiQualifiedId *id)
63{
64 QString name = id->name.toString();
65 for (auto *item = id->next; item != nullptr; item = item->next) {
66 name += "." + item->name;
67 }
68
69 return name;
70}
71
72void RestructureAstVisitor::endVisit(UiHeaderItemList *node)
73{
74 QList<Node *> correctOrder;
75
76 auto imports = findKind<UiImport>(list: node);
77
78 if (!m_sortImports)
79 return;
80
81 // Sort imports
82 std::sort(first: imports.begin(), last: imports.end(), comp: [](UiImport *a, UiImport *b)
83 {
84 auto nameA = a->fileName.isEmpty() ? parseUiQualifiedId(id: a->importUri)
85 : a->fileName.toString();
86 auto nameB = b->fileName.isEmpty() ? parseUiQualifiedId(id: b->importUri)
87 : b->fileName.toString();
88
89 return nameA < nameB;
90 });
91
92 // Add imports
93 for (auto *import : imports)
94 correctOrder.append(t: import);
95
96 // Add all the other items
97 for (auto *item = node; item != nullptr; item = item->next) {
98 if (!correctOrder.contains(t: item->headerItem))
99 correctOrder.append(t: item->headerItem);
100 }
101
102 // Rebuild member list from correctOrder
103 for (auto *item = node; item != nullptr; item = item->next) {
104 item->headerItem = correctOrder.front();
105 correctOrder.pop_front();
106 }
107}
108
109void RestructureAstVisitor::endVisit(UiObjectMemberList *node)
110{
111 QList<UiObjectMember*> correctOrder;
112
113 auto enumDeclarations = findKind<UiEnumDeclaration>(list: node);
114 auto scriptBindings = findKind<UiScriptBinding>(list: node);
115 auto arrayBindings = findKind<UiArrayBinding>(list: node);
116 auto publicMembers = findKind<UiPublicMember>(list: node);
117 auto sourceElements = findKind<UiSourceElement>(list: node);
118 auto objectDefinitions = findKind<UiObjectDefinition>(list: node);
119
120 // This structure is based on https://doc.qt.io/qt-5/qml-codingconventions.html
121
122 // 1st id
123 for (auto *binding : scriptBindings) {
124 if (binding->qualifiedId->name == "id") {
125 correctOrder.append(t: binding);
126
127 scriptBindings.removeOne(t: binding);
128 break;
129 }
130 }
131
132 // 2nd enums
133 for (auto *enumDeclaration : enumDeclarations)
134 correctOrder.append(t: enumDeclaration);
135
136 // 3rd property declarations
137 for (auto *publicMember : publicMembers) {
138 if (publicMember->type != UiPublicMember::Property)
139 continue;
140
141 correctOrder.append(t: publicMember);
142 }
143
144 // 4th signals
145 for (auto *publicMember : publicMembers) {
146 if (publicMember->type != UiPublicMember::Signal)
147 continue;
148
149 correctOrder.append(t: publicMember);
150 }
151
152 // 5th functions
153 for (auto *source : sourceElements)
154 correctOrder.append(t: source);
155
156 // 6th properties
157 for (auto *binding : scriptBindings)
158 correctOrder.append(t: binding);
159
160 for (auto *binding : arrayBindings)
161 correctOrder.append(t: binding);
162
163 // 7th child objects
164 for (auto *objectDefinition : objectDefinitions)
165 correctOrder.append(t: objectDefinition);
166
167 // 8th all the rest
168 for (auto *item = node; item != nullptr; item = item->next) {
169 if (!correctOrder.contains(t: item->member))
170 correctOrder.append(t: item->member);
171 }
172
173 // Rebuild member list from correctOrder
174 for (auto *item = node; item != nullptr; item = item->next) {
175 item->member = correctOrder.front();
176 correctOrder.pop_front();
177 }
178}
179

source code of qtdeclarative/tools/qmlformat/restructureastvisitor.cpp