/**************************************************************************** ** ** Copyright (C) 2021 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:COMM$ ** ** 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. ** ** $QT_END_LICENSE$ ** ** ** ** ** ** ** ** ****************************************************************************/ #include "restructureastvisitor.h" #include RestructureAstVisitor::RestructureAstVisitor(Node *rootNode, bool sortImports) : m_sortImports(sortImports) { rootNode->accept(this); } template static QList findKind(UiObjectMemberList *list) { QList members; for (auto *item = list; item != nullptr; item = item->next) { if (cast(item->member) != nullptr) members.append(cast(item->member)); } return members; } template static QList findKind(UiHeaderItemList *list) { QList members; for (auto *item = list; item != nullptr; item = item->next) { if (cast(item->headerItem) != nullptr) members.append(cast(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(UiHeaderItemList *node) { QList correctOrder; auto imports = findKind(node); if (!m_sortImports) return; // Sort imports std::sort(imports.begin(), imports.end(), [](UiImport *a, UiImport *b) { auto nameA = a->fileName.isEmpty() ? parseUiQualifiedId(a->importUri) : a->fileName.toString(); auto nameB = b->fileName.isEmpty() ? parseUiQualifiedId(b->importUri) : b->fileName.toString(); return nameA < nameB; }); // Add imports for (auto *import : imports) correctOrder.append(import); // Add all the other items for (auto *item = node; item != nullptr; item = item->next) { if (!correctOrder.contains(item->headerItem)) correctOrder.append(item->headerItem); } // Rebuild member list from correctOrder for (auto *item = node; item != nullptr; item = item->next) { item->headerItem = correctOrder.front(); correctOrder.pop_front(); } } void RestructureAstVisitor::endVisit(UiObjectMemberList *node) { QList correctOrder; auto enumDeclarations = findKind(node); auto scriptBindings = findKind(node); auto arrayBindings = findKind(node); auto publicMembers = findKind(node); auto sourceElements = findKind(node); auto objectDefinitions = findKind(node); // This structure is based on https://doc.qt.io/qt-5/qml-codingconventions.html // 1st id for (auto *binding : scriptBindings) { if (binding->qualifiedId->name == "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 for (auto *binding : scriptBindings) 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); } // Rebuild member list from correctOrder for (auto *item = node; item != nullptr; item = item->next) { item->member = correctOrder.front(); correctOrder.pop_front(); } }