generator.cpp 6.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191
  1. /*
  2. * MIT License
  3. *
  4. * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
  5. *
  6. * This file is part of qtprotobuf project https://git.semlanik.org/semlanik/qtprotobuf
  7. *
  8. * Permission is hereby granted, free of charge, to any person obtaining a copy of this
  9. * software and associated documentation files (the "Software"), to deal in the Software
  10. * without restriction, including without limitation the rights to use, copy, modify,
  11. * merge, publish, distribute, sublicense, and/or sell copies of the Software, and
  12. * to permit persons to whom the Software is furnished to do so, subject to the following
  13. * conditions:
  14. *
  15. * The above copyright notice and this permission notice shall be included in all copies
  16. * or substantial portions of the Software.
  17. *
  18. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
  19. * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
  20. * PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
  21. * FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
  22. * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #include "generator.h"
  26. #include "templates.h"
  27. #include "classgeneratorbase.h"
  28. #include <google/protobuf/stubs/logging.h>
  29. #include <google/protobuf/stubs/common.h>
  30. #include <google/protobuf/io/printer.h>
  31. #include <google/protobuf/io/zero_copy_stream.h>
  32. #include <google/protobuf/descriptor.h>
  33. #include <algorithm>
  34. #include <unordered_map>
  35. #include <vector>
  36. #include <sstream>
  37. #include <string>
  38. using namespace ::google::protobuf;
  39. using namespace ::google::protobuf::compiler;
  40. using namespace qtprotobuf;
  41. class QtClassGenerator : public ClassGeneratorBase
  42. {
  43. std::string mPackage;
  44. const Descriptor* mMessage;
  45. std::set<std::string> mExtractedModels;
  46. public:
  47. QtClassGenerator(const std::string &package, const Descriptor *message, std::unique_ptr<io::ZeroCopyOutputStream> out) :
  48. ClassGeneratorBase(message->name(), std::move(out))
  49. , mPackage(std::move(package))
  50. , mMessage(message){}
  51. void run() {
  52. //Post generation collect all generated model types
  53. for (int i = 0; i < mMessage->field_count(); i++) {
  54. const FieldDescriptor* field = mMessage->field(i);
  55. if (field->is_repeated()
  56. && field->type() == FieldDescriptor::TYPE_MESSAGE) {
  57. std::string typeName = field->message_type()->name();
  58. mExtractedModels.insert(typeName);
  59. }
  60. }
  61. printPreamble();
  62. printIncludes(mMessage, mExtractedModels);
  63. printNamespaces(mPackage);
  64. printClass();
  65. printProperties(mMessage);
  66. printPublic();
  67. printFieldsOrderingDefinition();
  68. encloseClass();
  69. enclose();
  70. }
  71. const std::set<std::string> &extractedModels() const {
  72. return mExtractedModels;
  73. }
  74. void printFieldsOrderingDefinition() {
  75. Indent();
  76. mPrinter.Print(FieldsOrderingDefinitionContainerTemplate);
  77. Outdent();
  78. }
  79. };
  80. class QtSourcesGenerator : public ClassGeneratorBase
  81. {
  82. std::string mPackage;
  83. const Descriptor* mMessage;
  84. std::set<std::string> mExtractedModels;
  85. public:
  86. QtSourcesGenerator(const std::string &package, const Descriptor *message, std::unique_ptr<io::ZeroCopyOutputStream> out) :
  87. ClassGeneratorBase(message->name(), std::move(out))
  88. , mPackage(std::move(package))
  89. , mMessage(message){}
  90. void run() {
  91. printClassHeaderInclude();
  92. printNamespaces(mPackage);
  93. printFieldsOrdering();
  94. enclose();
  95. }
  96. void printClassHeaderInclude() {
  97. std::string includeFileName = mClassName;
  98. std::transform(std::begin(includeFileName), std::end(includeFileName), std::begin(includeFileName), ::tolower);
  99. mPrinter.Print({{"type_lower", includeFileName}}, InternalIncludeTemplate);
  100. }
  101. void printFieldsOrdering() {
  102. mPrinter.Print({{"type", mClassName}}, FieldsOrderingContainerTemplate);
  103. Indent();
  104. for (int i = 0; i < mMessage->field_count(); i++) {
  105. const FieldDescriptor* field = mMessage->field(i);
  106. if (i != 0) {
  107. mPrinter.Print("\n,");
  108. }
  109. //property_number is incremented by 1 because user properties stating from 1.
  110. //Property with index 0 is "objectName"
  111. mPrinter.Print({{"field_number", std::to_string(field->number())},
  112. {"property_number", std::to_string(i + 1)}}, FieldOrderTemplate);
  113. }
  114. Outdent();
  115. mPrinter.Print(SemicolonBlockEnclosureTemplate);
  116. }
  117. };
  118. class GlobalEnumsGenerator : public ClassGeneratorBase
  119. {
  120. const FileDescriptor *mFile;
  121. public:
  122. GlobalEnumsGenerator(const FileDescriptor *file, std::unique_ptr<io::ZeroCopyOutputStream> out) :
  123. ClassGeneratorBase("GlobalEnums", std::move(out))
  124. , mFile(file)
  125. {}
  126. void run() {
  127. printPreamble();
  128. printNamespaces(mFile->package());
  129. printClass();
  130. printQEnums<FileDescriptor>(mFile);
  131. encloseClass();
  132. enclose();
  133. }
  134. };
  135. bool QtGenerator::Generate(const FileDescriptor *file,
  136. const std::string &/*parameter*/,
  137. GeneratorContext *generatorContext,
  138. std::string *error) const
  139. {
  140. if (file->syntax() != FileDescriptor::SYNTAX_PROTO3) {
  141. *error = "Invalid proto used. This plugin only supports 'proto3' syntax";
  142. return false;
  143. }
  144. std::set<std::string> extractedModels;
  145. for(int i = 0; i < file->message_type_count(); i++) {
  146. const Descriptor *message = file->message_type(i);
  147. std::string baseFilename(message->name());
  148. std::transform(std::begin(baseFilename), std::end(baseFilename), std::begin(baseFilename), ::tolower);
  149. std::string filename = baseFilename + ".h";
  150. QtClassGenerator classGen(file->package(), message,
  151. std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(filename))));
  152. classGen.run();
  153. extractedModels.insert(std::begin(classGen.extractedModels()), std::end(classGen.extractedModels()));
  154. std::string sourceFileName = baseFilename + ".cpp";
  155. QtSourcesGenerator classSourceGen(file->package(), message,
  156. std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(sourceFileName))));
  157. classSourceGen.run();
  158. }
  159. std::string globalEnumsFilename = "globalenums.h";
  160. GlobalEnumsGenerator enumGen(file, std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(globalEnumsFilename))));
  161. enumGen.run();
  162. return true;
  163. }