Revision control

++ // Copyright (C) 2023 The Qt Company Ltd.
++ // Copyright (C) 2020 Alexey Edelev <semlanik@gmail.com>, Tatyana Borisova <tanusshhka@mail.ru>
++ // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
++ // Qt-Security score:critical reason:data-parser
++
++ #include "messagedeclarationprinter.h"
++ #include "utils.h"
++ #include "options.h"
++ #include "generatorcommon.h"
++
++ #include <google/protobuf/descriptor.h>
++ #include <google/protobuf/descriptor.pb.h>
++
++ #include <cassert>
++
++ using namespace ::QtProtobuf;
++ using namespace ::qtprotoccommon;
++ using namespace ::google::protobuf;
++ using namespace ::google::protobuf::io;
++ using namespace ::google::protobuf::compiler;
++
++ MessageDeclarationPrinter::MessageDeclarationPrinter(const Descriptor *message,
++ std::shared_ptr<Printer> printer)
++ : DescriptorPrinterBase<Descriptor>(message,
++ std::move(printer),
++ common::produceMessageTypeMap(message, nullptr))
++ {
++ }
++
++ MessageDeclarationPrinter::~MessageDeclarationPrinter() = default;
++
++ void MessageDeclarationPrinter::printClassForwardDeclarationPrivate()
++ {
++ m_printer->Print(m_typeMap, CommonTemplates::ClassMessageForwardDeclarationTemplate());
++
++ if (common::hasNestedTypes(m_descriptor)) {
++ auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
++ m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceTemplate());
++
++ m_printer->Print({ { "type", CommonTemplates::QtProtobufFieldEnum() } },
++ CommonTemplates::EnumClassForwardDeclarationTemplate());
++
++ for (int i = 0; i < m_descriptor->enum_type_count(); ++i) {
++ m_printer->Print(common::produceEnumTypeMap(m_descriptor->enum_type(i), nullptr),
++ CommonTemplates::EnumForwardDeclarationTemplate());
++ }
++
++ common::iterateOneofFields(
++ m_descriptor, [this](const OneofDescriptor *, PropertyMap typeMap) {
++ m_printer->Print(typeMap,
++ CommonTemplates::EnumClassForwardDeclarationTemplate());
++ });
++
++ common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) {
++ MessageDeclarationPrinter nesterPrinter(nestedMessage, m_printer);
++ nesterPrinter.printClassForwardDeclarationPrivate();
++ });
++
++ m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceClosingTemplate());
++ m_printer->Print("\n");
++ }
++ }
++
++ void MessageDeclarationPrinter::printClassForwardDeclaration()
++ {
++ printClassForwardDeclarationPrivate();
++ }
++
++ void MessageDeclarationPrinter::printClassDeclaration()
++ {
++ printClassDeclarationPrivate();
++ }
++
++ void MessageDeclarationPrinter::printClassDeclarationPrivate()
++ {
++ printComments(m_descriptor);
++ printClassDeclarationBegin();
++ printClassBody();
++ encloseClass();
++
++ if (common::hasNestedTypes(m_descriptor)) {
++ auto scopeNamespaces = common::getNestedScopeNamespace(m_typeMap["classname"]);
++ m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceTemplate());
++
++ static const std::string exportMacro = common::buildExportMacro(false);
++ if (!exportMacro.empty()) {
++ m_printer->Print({{ "export_macro", exportMacro }},
++ CommonTemplates::QNamespaceDeclarationTemplate());
++ } else {
++ m_printer->Print(m_typeMap, CommonTemplates::QNamespaceDeclarationNoExportTemplate());
++ }
++
++ if (Options::instance().hasQml())
++ m_printer->Print(m_typeMap, CommonTemplates::QmlNamedElement());
++
++ m_printer->Print("\n");
++
++ printEnums();
++
++ common::iterateNestedMessages(m_descriptor, [this](const Descriptor *nestedMessage) {
++ MessageDeclarationPrinter nesterPrinter(nestedMessage, m_printer);
++ nesterPrinter.printClassDeclarationPrivate();
++ });
++ m_printer->Print(scopeNamespaces, CommonTemplates::NamespaceClosingTemplate());
++ }
++ }
++
++ void MessageDeclarationPrinter::printCopyFunctionality()
++ {
++ assert(m_descriptor != nullptr);
++ m_printer->Print(m_typeMap, CommonTemplates::CopyConstructorDeclarationTemplate());
++
++ m_printer->Print(m_typeMap, CommonTemplates::AssignmentOperatorDeclarationTemplate());
++ }
++
++ void MessageDeclarationPrinter::printMoveSemantic()
++ {
++ assert(m_descriptor != nullptr);
++ m_printer->Print(m_typeMap, CommonTemplates::MoveConstructorDeclarationTemplate());
++
++ m_printer->Print(m_typeMap, CommonTemplates::MoveAssignmentOperatorDeclarationTemplate());
++
++ m_printer->Print(m_typeMap, CommonTemplates::SwapDeclarationTemplate());
++ }
++
++ void MessageDeclarationPrinter::printQVariantOperator()
++ {
++ assert(m_descriptor != nullptr);
++ m_printer->Print(m_typeMap, CommonTemplates::QVariantOperatorDeclarationTemplate());
++ }
++
++ void MessageDeclarationPrinter::printComparisonOperators()
++ {
++ assert(m_descriptor != nullptr);
++ m_printer->Print(m_typeMap, CommonTemplates::EqualityDeclarationTemplate());
++ }
++
++ void MessageDeclarationPrinter::printConstructors()
++ {
++ m_printer->Print(m_typeMap, CommonTemplates::ConstructorMessageDeclarationTemplate());
++ }
++
++ void MessageDeclarationPrinter::printMaps()
++ {
++ Indent();
++ const int numFields = m_descriptor->field_count();
++ for (int i = 0; i < numFields; ++i) {
++ const FieldDescriptor *field = m_descriptor->field(i);
++ if (field->is_map()) {
++ m_printer->Print(common::producePropertyMap(field, m_descriptor),
++ CommonTemplates::UsingMapTemplate());
++ }
++ }
++ Outdent();
++ }
++
++ void MessageDeclarationPrinter::printNested()
++ {
++ Indent();
++ m_printer->Print({ { "type", CommonTemplates::QtProtobufFieldEnum() },
++ { "scope_namespaces",
++ m_typeMap["classname"] + CommonTemplates::QtProtobufNestedNamespace() } },
++ CommonTemplates::UsingEnumTemplate());
++
++ for (int i = 0; i < m_descriptor->enum_type_count(); ++i) {
++ const auto *enumDescr = m_descriptor->enum_type(i);
++ auto typeMap = common::produceEnumTypeMap(enumDescr, m_descriptor);
++ m_printer->Print(typeMap, CommonTemplates::UsingEnumTemplate());
++ }
++
++ common::iterateOneofFields(m_descriptor, [this](const OneofDescriptor *, PropertyMap typeMap) {
++ typeMap["scope_namespaces"] =
++ m_typeMap["classname"] + CommonTemplates::QtProtobufNestedNamespace();
++ m_printer->Print(typeMap, CommonTemplates::UsingEnumTemplate());
++ });
++
++ common::iterateNestedMessages(m_descriptor, [&](const Descriptor *nestedMessage) {
++ m_printer->Print(common::produceMessageTypeMap(nestedMessage, m_descriptor),
++ CommonTemplates::UsingNestedMessageTemplate());
++ });
++
++ Outdent();
++ }
++
++ void MessageDeclarationPrinter::printClassDeclarationBegin()
++ {
++ const Options::FinalPolicy policy = Options::instance().messageGenerationType();
++ m_printer->Print(m_typeMap, CommonTemplates::ClassMessageBeginDeclarationTemplate(policy));
++
++ Indent();
++ static const std::string exportMacro = common::buildExportMacro(false);
++ if (exportMacro.empty()) {
++ m_printer->Print({{ "export_macro", exportMacro }},
++ CommonTemplates::Q_PROTOBUF_OBJECTMacro());
++ } else {
++ m_printer->Print({{ "export_macro", exportMacro }},
++ CommonTemplates::Q_PROTOBUF_OBJECT_EXPORTMacro());
++ }
++ Outdent();
++
++ if (Options::instance().hasQml()) {
++ m_printer->Print(m_typeMap, CommonTemplates::ClassMessageQmlBeginDeclarationTemplate());
++ }
++ }
++
++ void MessageDeclarationPrinter::printProperties()
++ {
++ assert(m_descriptor != nullptr);
++ // private section
++ Indent();
++
++ const int numFields = m_descriptor->field_count();
++ const Options::FinalPolicy propertyType = Options::instance().propertyGenerationType();
++ common::iterateMessageFields(
++ m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
++ const char *propertyTemplate = CommonTemplates::PropertyTemplate(propertyType);
++ if (common::isOneofField(field)) {
++ m_printer->Print(propertyMap,
++ common::isPureMessage(field)
++ ? CommonTemplates::PropertyOneofMessageTemplate(propertyType)
++ : CommonTemplates::PropertyOneofTemplate(propertyType));
++ m_printer->Print(propertyMap,
++ CommonTemplates::PropertyHasFieldTemplate(propertyType));
++ return;
++ }
++
++ if (common::isOptionalField(field)) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::PropertyOneofTemplate(propertyType));
++ m_printer->Print(propertyMap,
++ CommonTemplates::PropertyHasFieldTemplate(propertyType));
++ return;
++ }
++
++ if (common::isPureMessage(field)) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::PropertyMessageTemplate(propertyType));
++ m_printer->Print(propertyMap,
++ CommonTemplates::PropertyHasFieldTemplate(propertyType));
++ return;
++ }
++
++ if (common::isRepeatedMessage(field)) {
++ m_printer->Print(
++ propertyMap,
++ CommonTemplates::PropertyRepeatedMessageTemplate(propertyType));
++ m_printer->Print(
++ propertyMap,
++ CommonTemplates::PropertyRepeatedMessageTemplateDeprecated(propertyType));
++ return;
++ } else if (field->is_repeated() && !field->is_map()) {
++ propertyTemplate = CommonTemplates::PropertyRepeatedTemplate(propertyType);
++ }
++ m_printer->Print(propertyMap, propertyTemplate);
++ });
++
++ // Generate extra QML property, that can be used in QML context
++ if (Options::instance().hasQml()) {
++ for (int i = 0; i < numFields; ++i) {
++ const FieldDescriptor *field = m_descriptor->field(i);
++ if (common::isPureMessage(field)) {
++ m_printer->Print(common::producePropertyMap(field, m_descriptor),
++ CommonTemplates::PropertyQmlMessageTemplate(propertyType));
++ }
++ }
++ }
++
++ Outdent();
++ }
++
++ void MessageDeclarationPrinter::printGetters()
++ {
++ Indent();
++ common::iterateMessageFields(
++ m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
++ printComments(field);
++ m_printer->Print("\n");
++ if (common::isOneofField(field)) {
++ m_printer->Print(
++ propertyMap,
++ common::isPureMessage(field)
++ ? CommonTemplates::GetterOneofMessageDeclarationTemplate()
++ : CommonTemplates::GetterOneofDeclarationTemplate());
++ return;
++ }
++ if (common::isOptionalField(field)) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::GetterOneofDeclarationTemplate());
++ return;
++ }
++
++ switch (field->type()) {
++ case FieldDescriptor::TYPE_MESSAGE:
++ if (common::isPureMessage(field)) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::GetterMessageDeclarationTemplate());
++ m_printer
++ ->Print(propertyMap,
++ CommonTemplates::GetterMessageMutableDeclarationTemplate());
++ m_printer->Print(propertyMap,
++ Options::instance().hasQml()
++ ? CommonTemplates::ClearQmlMessageDeclarationTemplate()
++ : CommonTemplates::ClearMessageDeclarationTemplate());
++ } else {
++ m_printer->Print(propertyMap,
++ CommonTemplates::GetterComplexDeclarationTemplate());
++ }
++ break;
++ case FieldDescriptor::FieldDescriptor::TYPE_STRING:
++ case FieldDescriptor::FieldDescriptor::TYPE_BYTES:
++ m_printer->Print(propertyMap,
++ CommonTemplates::GetterComplexDeclarationTemplate());
++ break;
++ case FieldDescriptor::TYPE_FLOAT:
++ case FieldDescriptor::TYPE_DOUBLE:
++ default:
++ m_printer->Print(propertyMap,
++ field->is_repeated()
++ ? CommonTemplates::GetterComplexDeclarationTemplate()
++ : CommonTemplates::GetterDeclarationTemplate());
++ break;
++ }
++ });
++ common::iterateOneofFields(
++ m_descriptor, [&](const OneofDescriptor *, const PropertyMap &propertyMap) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::GetterOneofFieldNumberDeclarationTemplate());
++ });
++ Outdent();
++ }
++
++ void MessageDeclarationPrinter::printSetters()
++ {
++ Indent();
++ common::iterateMessageFields(
++ m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
++ bool isTriviallyCopyable = common::isTriviallyCopyable(field);
++
++ if (common::isOneofField(field)) {
++ m_printer
++ ->Print(propertyMap,
++ isTriviallyCopyable
++ ? CommonTemplates::SetterOneofDeclarationTemplate()
++ : CommonTemplates::SetterComplexOneofDeclarationTemplate());
++ return;
++ }
++ if (common::isOptionalField(field)) {
++ m_printer->Print(propertyMap,
++ isTriviallyCopyable
++ ? CommonTemplates::SetterDeclarationTemplate()
++ : CommonTemplates::SetterComplexDeclarationTemplate());
++ m_printer->Print(propertyMap,
++ Options::instance().hasQml()
++ ? CommonTemplates::ClearQmlOneofDeclarationTemplate()
++ : CommonTemplates::ClearOneofDeclarationTemplate());
++ return;
++ }
++
++ switch (field->type()) {
++ case FieldDescriptor::TYPE_MESSAGE:
++ if (!field->is_map() && !field->is_repeated() && !common::isQtType(field)) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::SetterMessageDeclarationTemplate());
++ } else {
++ m_printer->Print(propertyMap,
++ CommonTemplates::SetterComplexDeclarationTemplate());
++ }
++ break;
++ case FieldDescriptor::FieldDescriptor::TYPE_STRING:
++ case FieldDescriptor::FieldDescriptor::TYPE_BYTES:
++ m_printer->Print(propertyMap,
++ CommonTemplates::SetterComplexDeclarationTemplate());
++ break;
++ default:
++ m_printer->Print(propertyMap,
++ field->is_repeated()
++ ? CommonTemplates::SetterComplexDeclarationTemplate()
++ : CommonTemplates::SetterDeclarationTemplate());
++ break;
++ }
++ });
++ common::
++ iterateOneofFields(m_descriptor,
++ [&](const OneofDescriptor *, const PropertyMap &propertyMap) {
++ m_printer->Print(propertyMap,
++ Options::instance().hasQml()
++ ? CommonTemplates::ClearQmlOneofDeclarationTemplate()
++ : CommonTemplates::ClearOneofDeclarationTemplate());
++ });
++ Outdent();
++ }
++
++ void MessageDeclarationPrinter::printPrivateGetters()
++ {
++ Indent();
++ common::iterateMessageFields(
++ m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
++ if (common::isOneofField(field)) {
++ m_printer->Print(
++ propertyMap,
++ common::isPureMessage(field)
++ ? CommonTemplates::
++ PrivateGetterOneofMessageDeclarationTemplate()
++ : CommonTemplates::PrivateGetterOneofDeclarationTemplate());
++ } else if (common::isOptionalField(field)) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::PrivateGetterOneofDeclarationTemplate());
++ } else if (common::isPureMessage(field)) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::PrivateGetterMessageDeclarationTemplate());
++ }
++ });
++ Outdent();
++ }
++
++ void MessageDeclarationPrinter::printPrivateSetters()
++ {
++ Indent();
++ common::iterateMessageFields(
++ m_descriptor, [&](const FieldDescriptor *field, const PropertyMap &propertyMap) {
++ if (common::isOneofField(field)) {
++ m_printer->Print(
++ propertyMap,
++ common::isPureMessage(field)
++ ? CommonTemplates::
++ PrivateSetterOneofMessageDeclarationTemplate()
++ : CommonTemplates::PrivateSetterOneofDeclarationTemplate());
++ } else if (common::isOptionalField(field)) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::PrivateSetterOneofDeclarationTemplate());
++ } else if (common::isPureMessage(field)) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::PrivateSetterMessageDeclarationTemplate());
++ }
++ });
++ Outdent();
++ }
++
++ void MessageDeclarationPrinter::printEnums()
++ {
++ if (Options::instance().generateFieldEnum())
++ printFieldEnum();
++
++ printQEnums();
++ printOneofEnums();
++ }
++
++ void MessageDeclarationPrinter::printQEnums()
++ {
++ for (int i = 0; i < m_descriptor->enum_type_count(); ++i) {
++ const auto *enumDescr = m_descriptor->enum_type(i);
++ auto typeMap = common::produceEnumTypeMap(enumDescr, m_descriptor);
++ m_printer->Print(typeMap, CommonTemplates::EnumClassDefinitionTemplate());
++
++ Indent();
++ for (int j = 0; j < enumDescr->value_count(); ++j) {
++ const auto *valueDescr = enumDescr->value(j);
++ m_printer->Print({ { "enumvalue", common::qualifiedCppName(valueDescr->name()) },
++ { "value", std::to_string(valueDescr->number()) } },
++ CommonTemplates::EnumFieldTemplate());
++ }
++ Outdent();
++ m_printer->Print(CommonTemplates::SemicolonBlockEnclosureTemplate());
++ m_printer->Print(typeMap, CommonTemplates::QEnumNSTemplate());
++ }
++ }
++
++ void MessageDeclarationPrinter::printOneofEnums()
++ {
++ common::iterateOneofFields(
++ m_descriptor, [this](const OneofDescriptor *oneofDescr, const PropertyMap &typeMap) {
++ m_printer->Print(typeMap, CommonTemplates::EnumClassDefinitionTemplate());
++ Indent();
++ m_printer->Print({ { "enumvalue", "UninitializedField" },
++ { "value", "QtProtobuf::InvalidFieldNumber" } },
++ CommonTemplates::EnumFieldTemplate());
++ for (int j = 0; j < oneofDescr->field_count(); ++j) {
++ const auto *valueDescr = oneofDescr->field(j);
++ m_printer->Print({ { "enumvalue",
++ utils::capitalizeAsciiName(valueDescr->camelcase_name()) },
++ { "value", std::to_string(valueDescr->number()) } },
++ CommonTemplates::EnumFieldTemplate());
++ }
++ Outdent();
++ m_printer->Print(CommonTemplates::SemicolonBlockEnclosureTemplate());
++ m_printer->Print(typeMap, CommonTemplates::QEnumNSTemplate());
++ });
++ }
++
++ void MessageDeclarationPrinter::printPublicExtras()
++ {
++ if (m_descriptor->full_name() == "google.protobuf.Timestamp") {
++ static const std::string exportMacro = common::buildExportMacro();
++ m_printer->Print({ { "export_macro", exportMacro } },
++ CommonTemplates::QDateTimeExtrasTemplate());
++ } else if (m_descriptor->full_name() == "google.protobuf.Duration") {
++ static const std::string exportMacro = common::buildExportMacro();
++ m_printer->Print({ { "export_macro", exportMacro } },
++ CommonTemplates::DurationExtrasTemplate());
++ }
++ }
++
++ void MessageDeclarationPrinter::printClassBody()
++ {
++ printProperties();
++
++ printPublicBlock();
++ printNested();
++ printMaps();
++
++ Indent();
++ printConstructors();
++ printDestructor();
++
++ printCopyFunctionality();
++ printMoveSemantic();
++ printQVariantOperator();
++
++ Outdent();
++
++ printGetters();
++ printSetters();
++
++ Indent();
++ m_printer->Print(m_typeMap, CommonTemplates::MetaTypeRegistrationDeclaration());
++ printPublicExtras();
++ Outdent();
++
++ printPrivateBlock();
++ Indent();
++ printComparisonOperators();
++ Outdent();
++ printPrivateGetters();
++ printPrivateSetters();
++
++ printSharedDataPointer();
++ }
++
++ void MessageDeclarationPrinter::printSharedDataPointer()
++ {
++ Indent();
++ m_printer->Print(m_typeMap, CommonTemplates::MemberSharedDataPointerTemplate());
++ Outdent();
++ }
++
++ void MessageDeclarationPrinter::printDestructor()
++ {
++ m_printer->Print(m_typeMap, CommonTemplates::DestructorMessageDeclarationTemplate());
++ }
++
++ void MessageDeclarationPrinter::printFieldEnum()
++ {
++ if (m_descriptor->field_count() > 0) {
++ m_printer->Print(CommonTemplates::FieldEnumTemplate());
++ Indent();
++ common::iterateMessageFields(m_descriptor,
++ [&](const FieldDescriptor *, const PropertyMap &propertyMap) {
++ m_printer->Print(propertyMap,
++ CommonTemplates::FieldNumberTemplate());
++ });
++ Outdent();
++ m_printer->Print(CommonTemplates::SemicolonBlockEnclosureTemplate());
++ m_printer->Print({ { "type", CommonTemplates::QtProtobufFieldEnum() } },
++ CommonTemplates::QEnumNSTemplate());
++ }
++ }