Browse Source

Generate list types for all repeated fields

- Fix type registration
- Add global enum list registration
Tatyana Borisova 5 years ago
parent
commit
1a7e7e944d

+ 1 - 0
src/generator/CMakeLists.txt

@@ -5,6 +5,7 @@ add_executable(${PROJECT_NAME}
     servergenerator.cpp
     protobufclassgenerator.cpp
     globalenumsgenerator.cpp
+    globalenumssourcegenerator.cpp
     servicegeneratorbase.cpp
     templates.cpp
     clientgenerator.cpp

+ 1 - 1
src/generator/classgeneratorbase.cpp

@@ -157,7 +157,7 @@ std::string ClassGeneratorBase::getTypeName(const FieldDescriptor *field, const
             typeName = namespaceTypeName.append(Templates::GlobalEnumClassNameTemplate)
                     .append("::").append(enumType->name());
         } else {
-            typeName = namespaceTypeName.append(enumType->name());
+            typeName = mNamespacesColonDelimited.append("::" + namespaceTypeName).append(enumType->name());
         }
         if (field->is_repeated()) {
             return typeName.append("List");

+ 7 - 2
src/generator/generator.cpp

@@ -29,6 +29,7 @@
 #include "protobufclassgenerator.h"
 #include "protobufsourcegenerator.h"
 #include "globalenumsgenerator.h"
+#include "globalenumssourcegenerator.h"
 #include "servergenerator.h"
 #include "clientgenerator.h"
 #include "clientsourcegenerator.h"
@@ -154,7 +155,7 @@ bool QtGenerator::Generate(const FileDescriptor *file,
 
 bool QtGenerator::GenerateAll(const std::vector<const FileDescriptor *> &files, const string &parameter, GeneratorContext *generatorContext, string *error) const
 {
-    std::string globalEnumsFilename = "globalenums.h";
+    std::string globalEnumsFilename = "globalenums";
 
     PackagesList packageList;
     for (auto file : files) {
@@ -162,9 +163,13 @@ bool QtGenerator::GenerateAll(const std::vector<const FileDescriptor *> &files,
     }
 
     GlobalEnumsGenerator enumGen(packageList,
-                                 std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(globalEnumsFilename))));
+                                 std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(globalEnumsFilename + ".h"))));
     enumGen.run();
 
+    GlobalEnumsSourceGenerator enumSourceGen(packageList,
+                                             std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(globalEnumsFilename + ".cpp"))));
+    enumSourceGen.run();
+
     // FIXME: not sure about the actual protobuf version where GenerateAll was actually implemented
 #if GOOGLE_PROTOBUF_VERSION < 3006000
     CodeGenerator::GenerateAll(files, parameter, generatorContext, error);

+ 30 - 0
src/generator/globalenumsgenerator.cpp

@@ -39,6 +39,10 @@ GlobalEnumsGenerator::GlobalEnumsGenerator(const PackagesList &packageList, std:
 void GlobalEnumsGenerator::startEnum(const std::vector<std::string>& namespaces) {
     printNamespaces(namespaces);
     printEnumClass();
+    printPublic();
+    Indent();
+    mPrinter.Print(Templates::ComplexTypeRegistrationMethodTemplate);
+    Outdent();
 }
 
 void GlobalEnumsGenerator::run() {
@@ -51,6 +55,9 @@ void GlobalEnumsGenerator::run() {
             run(file);
         }
         encloseEnum(namespaces);
+        for (auto file : package.second) {
+            printMetatype(file, namespaces);
+        }
     }
 }
 
@@ -58,6 +65,29 @@ void GlobalEnumsGenerator::run(const FileDescriptor *file) {
     printQEnums(file);
 }
 
+void GlobalEnumsGenerator::printMetatype(const google::protobuf::FileDescriptor *file,
+                                         const std::vector<std::string>& namespaces) {
+    std::string fullNamespace;
+    for (auto name : namespaces) {
+        if (fullNamespace.empty()) {
+            fullNamespace.append(name);
+            continue;
+        }
+        fullNamespace.append("::").append(name);
+    }
+    std::string fullClassname;
+    for (int i = 0; i < file->enum_type_count(); i++) {
+        const auto enumDescr = file->enum_type(i);
+        if (!enumDescr->name().empty()) {
+            fullClassname.append(Templates::GlobalEnumClassNameTemplate).append("::").append(enumDescr->name());
+        }
+    }
+    if (!fullClassname.empty()) {
+        mPrinter.Print({{"classname", fullClassname}, {"namespaces", fullNamespace}},
+                       Templates::DeclareMetaTypeListTemplate);
+    }
+}
+
 void GlobalEnumsGenerator::encloseEnum(const std::vector<std::string>& namespaces) {
     encloseClass();
     encloseNamespaces(namespaces.size());

+ 2 - 0
src/generator/globalenumsgenerator.h

@@ -44,6 +44,8 @@ public:
     void startEnum(const std::vector<std::string>& namespaces);
     void run(const ::google::protobuf::FileDescriptor *file);
     void encloseEnum(const std::vector<std::string>& namespaces);
+    void printMetatype(const google::protobuf::FileDescriptor *file,
+                       const std::vector<std::string>& namespaces);
     void printEnumClass();
 };
 

+ 83 - 0
src/generator/globalenumssourcegenerator.cpp

@@ -0,0 +1,83 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) Tatyana Borisova <tanusshhka@mail.ru>
+ *
+ * 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 "globalenumssourcegenerator.h"
+
+#include <google/protobuf/io/zero_copy_stream.h>
+
+using namespace ::qtprotobuf::generator;
+using namespace ::google::protobuf;
+using namespace ::google::protobuf::io;
+using namespace ::google::protobuf::compiler;
+
+GlobalEnumsSourceGenerator::GlobalEnumsSourceGenerator(const PackagesList &packageList, std::unique_ptr<io::ZeroCopyOutputStream> out) :
+    ClassGeneratorBase(Templates::GlobalEnumClassNameTemplate, std::move(out))
+  , mPackageList(packageList) {}
+
+void GlobalEnumsSourceGenerator::run() {
+    printPreamble();
+
+    std::vector<std::string> namespaces;
+    for (auto package : mPackageList) {
+        utils::split(package.first, namespaces, '.');
+
+        printNamespaces(namespaces);
+        printRegisterBody(package.second, namespaces);
+        encloseNamespaces(namespaces.size());
+    }
+}
+
+void GlobalEnumsSourceGenerator::printRegisterBody(const std::list<const FileDescriptor *> &list,
+                                                   const std::vector<std::string> &namespaces)
+{
+    std::string fullNamespace;
+    for (auto name : namespaces) {
+        if (fullNamespace.empty()) {
+            fullNamespace.append(name);
+            continue;
+        }
+        fullNamespace.append("::").append(name);
+    }
+    const std::map<std::string, std::string> registrationProperties = {{"classname", mClassName},
+                                                                       {"namespaces", fullNamespace}};
+    mPrinter.Print(registrationProperties, Templates::ComplexGlobalEnumRegistrationTemplate);
+    for (auto file : list) {
+        std::string fullClassname;
+        for (int i = 0; i < file->enum_type_count(); i++) {
+            const auto enumDescr = file->enum_type(i);
+            if (!enumDescr->name().empty()) {
+                const std::map<std::string, std::string> properties = {{"classname", mClassName},
+                                                                       {"enum", enumDescr->name() + "List"},
+                                                                       {"namespaces", fullNamespace}};
+                mPrinter.Print(properties, Templates::ComplexGlobalEnumFieldRegistrationTemplate);
+            }
+        }
+    }
+
+    Indent();
+    mPrinter.Print(Templates::SimpleBlockEnclosureTemplate);
+    Outdent();
+    mPrinter.Print(Templates::SimpleBlockEnclosureTemplate);
+}

+ 48 - 0
src/generator/globalenumssourcegenerator.h

@@ -0,0 +1,48 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Tatyana Borisova <tanusshhka@mail.ru>
+ *
+ * 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.
+ */
+
+#pragma once
+
+#include "classgeneratorbase.h"
+#include "utils.h"
+
+namespace qtprotobuf {
+namespace generator {
+
+class GlobalEnumsSourceGenerator : public ClassGeneratorBase
+{
+    PackagesList mPackageList;
+public:
+    GlobalEnumsSourceGenerator(const PackagesList &packageList, std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> out);
+    virtual ~GlobalEnumsSourceGenerator() = default;
+
+    void run() override;
+    void printRegisterBody(const std::list<const ::google::protobuf::FileDescriptor *> &list,
+                           const std::vector<std::string> &namespaces);
+};
+
+} //namespace generator
+} //namespace qtprotobuf
+

+ 8 - 1
src/generator/templates.cpp

@@ -48,12 +48,18 @@ const char *Templates::UsingQtProtobufNamespaceTemplate = "\nusing namespace qtp
 const char *Templates::ComplexTypeRegistrationMethodTemplate = "static void registerTypes();\n";
 const char *Templates::ComplexTypeRegistrationTemplate = "void $classname$::registerTypes()\n{\n"
                                                          "    static bool registationDone = false;\n"
-                                                         "    if (!registationDone) {\n\n"
+                                                         "    if (!registationDone) {\n"
+                                                         "        registationDone = true;\n"
                                                          "        qRegisterMetaType<$classname$>(\"$classname$\");\n"
                                                          "        qRegisterMetaType<$classname$List>(\"$classname$List\");\n"
                                                          "        qRegisterMetaType<$classname$>(\"$namespaces$::$classname$\");\n"
                                                          "        qRegisterMetaType<$classname$List>(\"$namespaces$::$classname$List\");\n"
                                                          "";
+const char *Templates::ComplexGlobalEnumRegistrationTemplate = "void $classname$::registerTypes()\n{\n"
+                                                               "    static bool registationDone = false;\n"
+                                                               "    if (!registationDone) {\n\n"
+                                                               "        registationDone = true;\n";
+const char *Templates::ComplexGlobalEnumFieldRegistrationTemplate = "        qRegisterMetaType<$classname$::$enum$>(\"$namespaces$::$classname$::$enum$\");\n";
 const char *Templates::ComplexListTypeUsingTemplate = "using $classname$List = QList<QSharedPointer<$classname$>>;\n";
 const char *Templates::MapTypeUsingTemplate = "using $classname$ = QMap<$key$, $value$>;\n";
 const char *Templates::MessageMapTypeUsingTemplate = "using $classname$ = QMap<$key$, QSharedPointer<$value$>>;\n";
@@ -152,6 +158,7 @@ const char *Templates::PropertyInitializerTemplate = "\n    ,m_$property_name$($
 const char *Templates::ConstructorContentTemplate = "\n{\n    registerTypes();\n}\n";
 
 const char *Templates::DeclareMetaTypeTemplate = "Q_DECLARE_METATYPE($namespaces$::$classname$)\n";
+const char *Templates::DeclareMetaTypeListTemplate = "Q_DECLARE_METATYPE($namespaces$::$classname$List)\n";
 const char *Templates::DeclareMessageMetaTypeTemplate = "Q_DECLARE_METATYPE($namespaces$::$classname$)\n"
                                                         "Q_DECLARE_OPAQUE_POINTER($namespaces$::$classname$)\n";
 

+ 3 - 0
src/generator/templates.h

@@ -43,6 +43,8 @@ public:
     static const char *UsingQtProtobufNamespaceTemplate;
     static const char *ComplexTypeRegistrationMethodTemplate;
     static const char *ComplexTypeRegistrationTemplate;
+    static const char *ComplexGlobalEnumRegistrationTemplate;
+    static const char *ComplexGlobalEnumFieldRegistrationTemplate;
     static const char *ComplexListTypeUsingTemplate;
     static const char *MapTypeUsingTemplate;
     static const char *MessageMapTypeUsingTemplate;
@@ -93,6 +95,7 @@ public:
     static const char *PropertyInitializerTemplate;
     static const char *ConstructorContentTemplate;
     static const char *DeclareMetaTypeTemplate;
+    static const char *DeclareMetaTypeListTemplate;
     static const char *DeclareMessageMetaTypeTemplate;
     static const char *DeclareComplexListTypeTemplate;
     static const char *RegisterMetaTypeDefaultTemplate;

+ 2 - 2
tests/test_protobuf/simpletest.cpp

@@ -347,8 +347,8 @@ TEST_F(SimpleTest, SimpleFileEnumsTest)
     const char* propertyName = "globalEnumList";
     SimpleFileEnumMessage test;
     int propertyNumber = SimpleFileEnumMessage::propertyOrdering.at(2); //See simpletest.proto
-    ASSERT_STREQ(SimpleFileEnumMessage::staticMetaObject.property(propertyNumber).typeName(), "GlobalEnums::TestEnumList");
-    ASSERT_EQ(SimpleFileEnumMessage::staticMetaObject.property(propertyNumber).userType(), qMetaTypeId<GlobalEnums::TestEnumList>());
+    ASSERT_STREQ(SimpleFileEnumMessage::staticMetaObject.property(propertyNumber).typeName(), "qtprotobufnamespace::tests::GlobalEnums::TestEnumList");
+    ASSERT_EQ(SimpleFileEnumMessage::staticMetaObject.property(propertyNumber).userType(), qMetaTypeId<qtprotobufnamespace::tests::GlobalEnums::TestEnumList>());
     ASSERT_STREQ(SimpleFileEnumMessage::staticMetaObject.property(propertyNumber).name(), propertyName);
 
     GlobalEnums::TestEnumList value({GlobalEnums::TEST_ENUM_VALUE1,