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 | |
33 | RestructureAstVisitor::RestructureAstVisitor(Node *rootNode, bool sortImports) : m_sortImports(sortImports) |
34 | { |
35 | rootNode->accept(visitor: this); |
36 | } |
37 | |
38 | template<typename T> |
39 | static 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 | |
50 | template<typename T> |
51 | static 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 | |
62 | static 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 | |
72 | void 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 | |
109 | void 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 |