/* * MIT License * * Copyright (c) 2019 Alexey Edelev * * This file is part of QtProtobuf project https://git.semlanik.org/semlanik/qtprotobuf * * Permission is hereby granted, free of charge, to any person obtaining a copy of this * software and associated documentation files (the "Software"), to deal in the Software * without restriction, including without limitation the rights to use, copy, modify, * merge, publish, distribute, sublicense, and/or sell copies of the Software, and * to permit persons to whom the Software is furnished to do so, subject to the following * conditions: * * The above copyright notice and this permission notice shall be included in all copies * or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. */ #include "generatorbase.h" #include #include #include #include #include #include "utils.h" #include "templates.h" #include "generatoroptions.h" #include "generatorcommon.h" using namespace ::QtProtobuf::generator; using namespace ::google::protobuf; using namespace ::google::protobuf::compiler; GeneratorBase::GeneratorBase(Mode mode) : m_mode(mode) { } bool GeneratorBase::GenerateAll(const std::vector &files, const string ¶meter, GeneratorContext *generatorContext, string *error) const { return CodeGenerator::GenerateAll(files, parameter, generatorContext, error); } std::string GeneratorBase::generateBaseName(const ::google::protobuf::FileDescriptor *file, std::string name) { std::vector packages = utils::split(file->package(), '.'); std::string outFileBasename = ""; if (GeneratorOptions::instance().isFolder()) { for (auto package : packages) { outFileBasename += package + "/"; } outFileBasename += name; } else { outFileBasename = name; } return outFileBasename; } void GeneratorBase::printDisclaimer(const std::shared_ptr<::google::protobuf::io::Printer> printer) { printer->Print(Templates::DisclaimerTemplate); } void GeneratorBase::printPreamble(const std::shared_ptr<::google::protobuf::io::Printer> printer) { printer->Print(Templates::PreambleTemplate); } void GeneratorBase::printInclude(const std::shared_ptr<::google::protobuf::io::Printer> printer, const google::protobuf::Descriptor *message, const FieldDescriptor *field, std::set &existingIncludes) { assert(field != nullptr); std::string newInclude; const char *includeTemplate = ""; switch (field->type()) { case FieldDescriptor::TYPE_MESSAGE: if (field->is_map()) { newInclude = "QMap"; assert(field->message_type() != nullptr); assert(field->message_type()->field_count() == 2); printInclude(printer, message, field->message_type()->field(0), existingIncludes); printInclude(printer, message, field->message_type()->field(1), existingIncludes); includeTemplate = Templates::ExternalIncludeTemplate; } else if (common::isQtType(field)) { newInclude = field->message_type()->name(); includeTemplate = Templates::ExternalIncludeTemplate; } else { if (!common::isNested(field->message_type())) { std::string outFileBasename = ""; std::string fieldPackage = field->message_type()->file()->package(); if (fieldPackage != message->file()->package()) { std::vector packages = utils::split(fieldPackage, '.'); for (auto package : packages) { outFileBasename += package + "/"; } } std::string typeName = field->message_type()->name(); utils::tolower(typeName); newInclude = outFileBasename + typeName; includeTemplate = Templates::InternalIncludeTemplate; } else if (!common::isNestedOf(field->message_type(), message)) { auto containingMessage = common::findHighestMessage(field->message_type()); if (containingMessage != message) { std::string outFileBasename = ""; std::string fieldPackage = containingMessage->file()->package(); if (fieldPackage != message->file()->package()) { std::vector packages = utils::split(fieldPackage, '.'); for (auto package : packages) { outFileBasename += package + "/"; } } std::string typeName = containingMessage->name(); utils::tolower(typeName); newInclude = outFileBasename + typeName; includeTemplate = Templates::InternalIncludeTemplate; } } } break; case FieldDescriptor::TYPE_BYTES: newInclude = "QByteArray"; includeTemplate = Templates::ExternalIncludeTemplate; break; case FieldDescriptor::TYPE_STRING: newInclude = "QString"; includeTemplate = Templates::ExternalIncludeTemplate; break; case FieldDescriptor::TYPE_ENUM: { common::EnumVisibility enumVisibily = common::enumVisibility(field->enum_type(), message); if (enumVisibily == common::GLOBAL_ENUM) { includeTemplate = Templates::GlobalEnumIncludeTemplate; } else if (enumVisibily == common::NEIGHBOR_ENUM) { includeTemplate = Templates::InternalIncludeTemplate; std::string fullEnumName = field->enum_type()->full_name(); std::vector fullEnumNameParts = utils::split(fullEnumName, '.'); std::string enumTypeOwner = fullEnumNameParts.at(fullEnumNameParts.size() - 2); utils::tolower(enumTypeOwner); newInclude = enumTypeOwner; } else { return; } } break; default: return; } if (existingIncludes.find(newInclude) == std::end(existingIncludes)) { printer->Print({{"include", newInclude}}, includeTemplate); existingIncludes.insert(newInclude); } } void GeneratorBase::printNamespaces(const std::shared_ptr<::google::protobuf::io::Printer> printer, const std::vector namespaces) { printer->Print("\n"); for (auto ns : namespaces) { printer->Print({{"namespace", ns}}, Templates::NamespaceTemplate); } }