// Copyright (C) 2016 The Qt Company Ltd. // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0+ OR GPL-3.0 WITH Qt-GPL-exception-1.0 #include "addarraymembervisitor.h" #include using namespace QmlDesigner; using namespace QmlDesigner::Internal; AddArrayMemberVisitor::AddArrayMemberVisitor(TextModifier &modifier, quint32 parentLocation, const QString &propertyName, const QString &content): QMLRewriter(modifier), m_parentLocation(parentLocation), m_propertyName(propertyName), m_content(content), m_convertObjectBindingIntoArrayBinding(false) { } void AddArrayMemberVisitor::findArrayBindingAndInsert(const QString &propertyName, QmlJS::AST::UiObjectMemberList *ast) { for (QmlJS::AST::UiObjectMemberList *iter = ast; iter; iter = iter->next) { if (auto arrayBinding = QmlJS::AST::cast(iter->member)) { if (toString(arrayBinding->qualifiedId) == propertyName) insertInto(arrayBinding); } else if (auto objectBinding = QmlJS::AST::cast(iter->member)) { if (toString(objectBinding->qualifiedId) == propertyName && willConvertObjectBindingIntoArrayBinding()) convertAndAdd(objectBinding); } } } bool AddArrayMemberVisitor::visit(QmlJS::AST::UiObjectBinding *ast) { if (didRewriting()) return false; if (ast->firstSourceLocation().offset == m_parentLocation) findArrayBindingAndInsert(m_propertyName, ast->initializer->members); return !didRewriting(); } bool AddArrayMemberVisitor::visit(QmlJS::AST::UiObjectDefinition *ast) { if (didRewriting()) return false; if (ast->firstSourceLocation().offset == m_parentLocation) findArrayBindingAndInsert(m_propertyName, ast->initializer->members); return !didRewriting(); } // FIXME: duplicate code in the QmlJS::Rewriter class, remove this void AddArrayMemberVisitor::insertInto(QmlJS::AST::UiArrayBinding *arrayBinding) { QmlJS::AST::UiObjectMember *lastMember = nullptr; for (QmlJS::AST::UiArrayMemberList *iter = arrayBinding->members; iter; iter = iter->next) if (iter->member) lastMember = iter->member; if (!lastMember) return; // an array binding cannot be empty, so there will (or should) always be a last member. const int insertionPoint = lastMember->lastSourceLocation().end(); const int indentDepth = calculateIndentDepth(lastMember->firstSourceLocation()); replace(insertionPoint, 0, QStringLiteral(",\n") + addIndentation(m_content, indentDepth)); setDidRewriting(true); } void AddArrayMemberVisitor::convertAndAdd(QmlJS::AST::UiObjectBinding *objectBinding) { const int indentDepth = calculateIndentDepth(objectBinding->firstSourceLocation()); const QString arrayPrefix = QStringLiteral("[\n") + addIndentation(QString(), indentDepth); replace(objectBinding->qualifiedTypeNameId->identifierToken.offset, 0, arrayPrefix); const int insertionPoint = objectBinding->lastSourceLocation().end(); replace(insertionPoint, 0, QStringLiteral(",\n") + addIndentation(m_content, indentDepth) + QLatin1Char('\n') + addIndentation(QStringLiteral("]"), indentDepth) ); setDidRewriting(true); }