Browse Source

Refactor generator

- Code cleanup
Alexey Edelev 6 years ago
parent
commit
1f18f3a18d

+ 3 - 1
CMakeLists.txt

@@ -14,7 +14,9 @@ add_subdirectory("src/lib")
 add_executable(${PROJECT_NAME} src/generator/main.cpp
     src/generator/generator.cpp
     src/generator/classgeneratorbase.cpp
-    src/generator/servergenerator.cpp)
+    src/generator/servergenerator.cpp
+    src/generator/protobufclassgenerator.cpp
+    src/generator/globalenumsgenerator.cpp)
 
 if (WIN32)
     #Needs to set path to protobuf libraries

+ 20 - 333
src/generator/classgeneratorbase.cpp

@@ -33,48 +33,18 @@
 
 #include <set>
 
-using namespace qtprotobuf;
+using namespace ::qtprotobuf::generator;
 using namespace ::google::protobuf;
 using namespace ::google::protobuf::io;
 using namespace ::google::protobuf::compiler;
 
-namespace {
-const std::string VariantList("QVariantList");
-}
-
-ClassGeneratorBase::ClassGeneratorBase(std::string mClassName, std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> out) : mOutput(std::move(out))
+ClassGeneratorBase::ClassGeneratorBase(std::string fullClassName, std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> out) : mOutput(std::move(out))
   , mPrinter(mOutput.get(), '$')
-  , mClassName(std::move(mClassName))
-  , mNamespaceCount(0)
-{
-
-}
-
-bool ClassGeneratorBase::producePropertyMap(const FieldDescriptor *field, PropertyMap &propertyMap)
 {
-    assert(field != nullptr);
-    std::string typeName = getTypeName(field);
-
-    if (typeName.size() <= 0) {
-        std::cerr << "Type "
-                  << field->type_name()
-                  << " is not supported by Qt Generator"
-                     " please look at https://doc.qt.io/qt-5/qtqml-typesystem-basictypes.html"
-                     " for details" << std::endl;
-        return false;
-    }
-
-    std::string typeNameLower(typeName);
-    utils::tolower(typeNameLower);
-
-    std::string capProperty = field->camelcase_name();
-    capProperty[0] = ::toupper(capProperty[0]);
-
-    propertyMap = {{"type", typeName},
-                   {"type_lower", typeNameLower},
-                   {"property_name", field->camelcase_name()},
-                   {"property_name_cap", capProperty}};
-    return true;
+    utils::split(fullClassName, mNamespaces, '.');
+    assert(mNamespaces.size() > 0);
+    mClassName = mNamespaces.back();
+    mNamespaces.erase(mNamespaces.end() - 1);
 }
 
 void ClassGeneratorBase::printPreamble()
@@ -82,300 +52,44 @@ void ClassGeneratorBase::printPreamble()
     mPrinter.Print(PreambleTemplate);
 }
 
-void ClassGeneratorBase::printIncludes(const Descriptor *message, std::set<std::string> listModel)
+void ClassGeneratorBase::printNamespaces()
 {
-    assert(message != nullptr);
-    PropertyMap properties;
-    std::set<std::string> existingIncludes;
-    std::string newInclude;
-    const char* includeTemplate;
-    for (int i = 0; i < message->field_count(); i++) {
-        const FieldDescriptor* field = message->field(i);
-        if (producePropertyMap(field, properties)) {
-            if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
-                newInclude = properties["type_lower"];
-                includeTemplate = InternalIncludeTemplate;
-            } else if (field->type() == FieldDescriptor::TYPE_STRING) {
-                includeTemplate = ExternalIncludeTemplate;
-            } else {
-                continue;
-            }
-
-            if (!field->is_repeated()) {
-                if (existingIncludes.find(newInclude) == std::end(existingIncludes)) {
-                    mPrinter.Print(properties, includeTemplate);
-                    existingIncludes.insert(newInclude);
-                }
-            } else {
-                std::string stringInclude = properties["type"];
-                if (stringInclude == VariantList
-                        && existingIncludes.find(stringInclude) == std::end(existingIncludes)) {
-                    mPrinter.Print(properties, ExternalIncludeTemplate);
-                    existingIncludes.insert(stringInclude);
-                }
-            }
-        }
-    }
-
-    // Print List model class name
-    if (listModel.size() > 0) {
-        mPrinter.Print(ListModelsIncludeTemplate);
-    }
-
-    for(auto modelTypeName : listModel) {
-        std::string modelTypeNameLower(modelTypeName);
-        utils::tolower(modelTypeNameLower);
-        mPrinter.Print({{"type_lower", modelTypeNameLower}}, InternalIncludeTemplate);
-    }
+    printNamespaces(mNamespaces);
 }
 
-void ClassGeneratorBase::printNamespaces(const std::string &package)
+void ClassGeneratorBase::printNamespaces(const std::vector<std::string> &namespaces)
 {
-    std::vector<std::string> namespaces;
-    utils::split(package, namespaces, '.');
-    mNamespaceCount = namespaces.size();
     for (auto ns: namespaces) {
         mPrinter.Print({{"namespace", ns}}, NamespaceTemplate);
     }
 }
 
-void ClassGeneratorBase::printClass()
+void ClassGeneratorBase::printClassDeclaration()
 {
     mPrinter.Print({{"classname", mClassName}}, ClassDefinitionTemplate);
 }
 
-void ClassGeneratorBase::printProperties(const Descriptor *message)
-{
-    assert(message != nullptr);
-    //private section
-    Indent();
-    for (int i = 0; i < message->field_count(); i++) {
-        const FieldDescriptor* field = message->field(i);
-        if (!isListType(field)) {
-            const char* propertyTemplate = field->type() == FieldDescriptor::TYPE_MESSAGE ? MessagePropertyTemplate :
-                                                                                            PropertyTemplate;
-            printField(field, propertyTemplate);
-        }
-    }
-    for (int i = 0; i < message->field_count(); i++) {
-        printField(message->field(i), MemberTemplate);
-    }
-    Outdent();
-
-    printQEnums(message);
-
-    //public section
-    printPublic();
-
-    //Body
-    Indent();
-    printConstructor();
-    printCopyFunctionality(message);
-    printMoveSemantic(message);
-    printComparisonOperators(message);
-
-    for (int i = 0; i < message->field_count(); i++) {
-        printField(message->field(i), GetterTemplate);
-    }
-    for (int i = 0; i < message->field_count(); i++) {
-        auto field = message->field(i);
-        if (field->type() == FieldDescriptor::TYPE_MESSAGE
-                || field->type() == FieldDescriptor::TYPE_STRING) {
-            printField(field, SetterTemplateComplexType);
-        } else {
-            printField(field, SetterTemplateSimpleType);
-        }
-    }
-    Outdent();
-
-    mPrinter.Print(SignalsBlockTemplate);
-
-    Indent();
-    for (int i = 0; i < message->field_count(); i++) {
-        printField(message->field(i), SignalTemplate);
-    }
-    Outdent();
-}
-
-void ClassGeneratorBase::printField(const FieldDescriptor *field, const char *fieldTemplate)
-{
-    assert(field != nullptr);
-    std::map<std::string, std::string> propertyMap;
-    if (producePropertyMap(field, propertyMap)) {
-        mPrinter.Print(propertyMap, fieldTemplate);
-    }
-}
-
 void ClassGeneratorBase::encloseClass()
 {
     mPrinter.Print(SemicolonBlockEnclosureTemplate);
 }
 
-void ClassGeneratorBase::enclose()
+void ClassGeneratorBase::encloseNamespaces(int count)
 {
-    while (mNamespaceCount > 0) {
+    for (int i = 0; i < count; i++) {
         mPrinter.Print(SimpleBlockEnclosureTemplate);
-        --mNamespaceCount;
-    }
-}
-
-std::string ClassGeneratorBase::getTypeName(const FieldDescriptor *field)
-{
-    assert(field != nullptr);
-    std::string typeName;
-    if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
-        if (field->is_repeated()) {
-            return VariantList;
-        }
-        typeName = field->message_type()->name();
-    } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
-        if (field->is_repeated()) {
-            return VariantList;
-        }
-        typeName = field->enum_type()->name();
-    } else {
-        auto it = TypeReflection.find(field->type());
-        if (it != std::end(TypeReflection)) {
-            typeName = it->second;
-            if (field->is_repeated()) {
-                std::string namespaceDefinition("qtprotobuf::");
-                typeName[0] = ::toupper(typeName[0]);
-                typeName.append("List");
-                if (typeName != "QStringList"
-                        && typeName != "QByteArrayList") {
-                    typeName = namespaceDefinition.append(typeName);
-                }
-            }
-        }
     }
-
-    return typeName;
 }
 
-void ClassGeneratorBase::printCopyFunctionality(const Descriptor *message)
+void ClassGeneratorBase::encloseNamespaces()
 {
-    assert(message != nullptr);
-    mPrinter.Print({{"classname", mClassName}},
-                   CopyConstructorTemplate);
-
-    Indent();
-    for (int i = 0; i < message->field_count(); i++) {
-        printField(message->field(i), CopyFieldTemplate);
-    }
-    Outdent();
-
-    mPrinter.Print(SimpleBlockEnclosureTemplate);
-    mPrinter.Print({{"classname", mClassName}},
-                   AssignmentOperatorTemplate);
-
-    Indent();
-    for (int i = 0; i < message->field_count(); i++) {
-        printField(message->field(i), CopyFieldTemplate);
-    }
-    mPrinter.Print(AssignmentOperatorReturnTemplate);
-    Outdent();
-
-    mPrinter.Print(SimpleBlockEnclosureTemplate);
-
-}
-
-bool ClassGeneratorBase::isListType(const FieldDescriptor *field)
-{
-    assert(field != nullptr);
-    return field && field->is_repeated()
-            && field->type() == FieldDescriptor::TYPE_MESSAGE;
-}
-
-bool ClassGeneratorBase::isComplexType(const FieldDescriptor *field)
-{
-    assert(field != nullptr);
-    return field->type() == FieldDescriptor::TYPE_MESSAGE
-            || field->type() == FieldDescriptor::TYPE_STRING
-            || field->type() == FieldDescriptor::TYPE_BYTES;
-}
-
-void ClassGeneratorBase::printMoveSemantic(const Descriptor *message)
-{
-    assert(message != nullptr);
-    mPrinter.Print({{"classname", mClassName}},
-                   MoveConstructorTemplate);
-
-    Indent();
-    for (int i = 0; i < message->field_count(); i++) {
-        const FieldDescriptor* field = message->field(i);
-        if (isComplexType(field) || field->is_repeated()) {
-            printField(field, MoveComplexFieldTemplate);
-        } else {
-            printField(field, MoveFieldTemplate);
-        }
-    }
-    Outdent();
-
-    mPrinter.Print(SimpleBlockEnclosureTemplate);
-    mPrinter.Print({{"classname", mClassName}},
-                   MoveAssignmentOperatorTemplate);
-
-    Indent();
-    for (int i = 0; i < message->field_count(); i++) {
-        const FieldDescriptor* field = message->field(i);
-        if (isComplexType(field) || field->is_repeated()) {
-            printField(field, MoveComplexFieldTemplate);
-        } else {
-            printField(field, MoveFieldTemplate);
-        }
-    }
-    mPrinter.Print(AssignmentOperatorReturnTemplate);
-    Outdent();
-
-    mPrinter.Print(SimpleBlockEnclosureTemplate);
+    encloseNamespaces(mNamespaces.size());
 }
 
 void ClassGeneratorBase::printConstructor()
 {
     mPrinter.Print({{"classname", mClassName}},
                    ConstructorTemplate);
-
-    //FIXME: Explicit default values are not allowed in proto3 seems
-    //this function is useless
-    //    for (int i = 0; i < mMessage->field_count(); i++) {
-    //        const FieldDescriptor* field = mMessage->field(i);
-    //        std::string defaultValue;
-    //        if (field->has_default_value()) {
-    //            switch (field->type()) {
-    //            case FieldDescriptor::TYPE_DOUBLE:
-    //                defaultValue = std::to_string(field->default_value_double());
-    //                break;
-    //            case FieldDescriptor::TYPE_FLOAT:
-    //                defaultValue = std::to_string(field->default_value_float());
-    //                break;
-    //            case FieldDescriptor::TYPE_INT32:
-    //            case FieldDescriptor::TYPE_UINT32:
-    //            case FieldDescriptor::TYPE_SFIXED32:
-    //            case FieldDescriptor::TYPE_SINT32:
-    //                defaultValue = std::to_string(field->default_value_int32());
-    //                break;
-    //            case FieldDescriptor::TYPE_BOOL:
-    //                defaultValue = field->default_value_bool() ? "true" : "false";
-    //                break;
-    //            case FieldDescriptor::TYPE_STRING:
-    //                defaultValue = field->default_value_string();
-    //                break;
-    //            case FieldDescriptor::TYPE_ENUM:
-    //                defaultValue = field->default_value_enum()->name();
-    //                break;
-    //            default:
-    //                std::cerr << "Default value substitution"
-    //                             " is not supported for type"
-    //                          << field->type_name() << std::endl;
-    //                break;
-    //            }
-    //            if (defaultValue.size() > 0) {
-    //                mPrinter.Print({{"property_name", field->camelcase_name()},
-    //                                {"default_value", defaultValue}},
-    //                               "    , $m_property_name$($default_value$)\n");
-    //            }
-    //        }
-    //    }
     mPrinter.Print(EmptyBlockTemplate);
 }
 
@@ -384,42 +98,15 @@ void ClassGeneratorBase::printPublic()
     mPrinter.Print(PublicBlockTemplate);
 }
 
-void ClassGeneratorBase::printComparisonOperators(const Descriptor *message)
+void ClassGeneratorBase::printMetaTypeDeclaration()
 {
-    assert(message != nullptr);
-    bool isFirst = true;
-    PropertyMap properties;
-    mPrinter.Print({{"type", mClassName}}, EqualOperatorTemplate);
-    for (int i = 0; i < message->field_count(); i++) {
-        const FieldDescriptor* field = message->field(i);
-        if (producePropertyMap(field, properties)) {
-            if (!isFirst) {
-                mPrinter.Print("\n&& ");
-            } else {
-                Indent();
-                Indent();
-                isFirst = false;
-            }
-            mPrinter.Print(properties, EqualOperatorPropertyTemplate);
+    std::string namespaces;
+    for(int i = 0; i < mNamespaces.size(); i++) {
+        if(i > 0) {
+            namespaces = namespaces.append("::");
         }
+        namespaces = namespaces.append(mNamespaces[i]);
     }
-
-    //Only if at least one field "copied"
-    if (!isFirst) {
-        Outdent();
-        Outdent();
-    }
-
-    mPrinter.Print(";\n");
-    mPrinter.Print(SimpleBlockEnclosureTemplate);
-
-    mPrinter.Print({{"type", mClassName}}, NotEqualOperatorTemplate);
-}
-
-void ClassGeneratorBase::printMetaTypeDeclaration(const std::string &package)
-{
-    std::string namespaces = package;
-    utils::replace(namespaces, std::string("."), std::string("::"));
     mPrinter.Print({{"type", mClassName},
                     {"namespaces", namespaces}}, DeclareMetaTypeTemplate);
 }

+ 16 - 21
src/generator/classgeneratorbase.h

@@ -38,30 +38,33 @@ class ZeroCopyOutputStream;
 }}}
 
 namespace qtprotobuf {
+namespace generator {
 
 using PropertyMap = std::map<std::string, std::string>;
 
 class ClassGeneratorBase
 {
 public:
-    ClassGeneratorBase(std::string mClassName, std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> out);
-
+    ClassGeneratorBase(std::string className, std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> out);
+    virtual ~ClassGeneratorBase() = default;
+    virtual void run() = 0;
 protected:
     std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> mOutput;
     ::google::protobuf::io::Printer mPrinter;
     std::string mClassName;
-    int mNamespaceCount;
+    std::vector<std::string> mNamespaces;
 
-    bool producePropertyMap(const ::google::protobuf::FieldDescriptor *field, PropertyMap &propertyMap);
     void printPreamble();
-    void printIncludes(const ::google::protobuf::Descriptor *message, std::set<std::string> listModel);
-    void printNamespaces(const std::string &package);
-    void printClass();
-    void printField(const ::google::protobuf::FieldDescriptor *field, const char *fieldTemplate);
+    void printNamespaces();
+    void printNamespaces(const std::vector<std::string> &namespaces);
+    void printClassDeclaration();
+    void printConstructor();
+    void printPublic();
     void encloseClass();
-    void printMetaTypeDeclaration(const std::string &package);
-    void enclose();
-    std::string getTypeName(const ::google::protobuf::FieldDescriptor *field);
+    void printMetaTypeDeclaration();
+    void encloseNamespaces();
+    void encloseNamespaces(int count);
+
 
     template<typename T>
     void printQEnums(const T *message) {
@@ -88,12 +91,6 @@ protected:
         Outdent();
     }
 
-    void printCopyFunctionality(const ::google::protobuf::Descriptor *message);
-    void printMoveSemantic(const ::google::protobuf::Descriptor *message);
-    void printComparisonOperators(const ::google::protobuf::Descriptor *message);
-    void printProperties(const ::google::protobuf::Descriptor *message);
-    void printConstructor();
-    void printPublic();
 
     void Indent() {
         mPrinter.Indent();
@@ -104,9 +101,7 @@ protected:
         mPrinter.Outdent();
         mPrinter.Outdent();
     }
-
-    bool isComplexType(const ::google::protobuf::FieldDescriptor *field);
-    bool isListType(const ::google::protobuf::FieldDescriptor *field);
 };
 
-}
+} //namespace generator
+} //namespace qtprotobuf

+ 18 - 101
src/generator/generator.cpp

@@ -26,6 +26,8 @@
 #include "generator.h"
 #include "templates.h"
 #include "classgeneratorbase.h"
+#include "protobufclassgenerator.h"
+#include "globalenumsgenerator.h"
 #include "servergenerator.h"
 #include "utils.h"
 
@@ -42,75 +44,23 @@
 #include <string>
 #include <list>
 
+using namespace ::qtprotobuf::generator;
 using namespace ::google::protobuf;
 using namespace ::google::protobuf::compiler;
 
-using namespace qtprotobuf;
-
-class QtClassGenerator : public ClassGeneratorBase
-{
-    std::string mPackage;
-    const Descriptor* mMessage;
-    std::set<std::string> mExtractedModels;
-
-public:
-    QtClassGenerator(const std::string &package, const Descriptor *message, std::unique_ptr<io::ZeroCopyOutputStream> out) :
-        ClassGeneratorBase(message->name(), std::move(out))
-      , mPackage(std::move(package))
-      , mMessage(message){}
-
-    void run() {
-        //Post generation collect all generated model types
-        for (int i = 0; i < mMessage->field_count(); i++) {
-            const FieldDescriptor* field = mMessage->field(i);
-            if (field->is_repeated()
-                    && field->type() == FieldDescriptor::TYPE_MESSAGE) {
-                std::string typeName = field->message_type()->name();
-                mExtractedModels.insert(typeName);
-            }
-        }
-
-        printPreamble();
-        printIncludes(mMessage, mExtractedModels);
-        printNamespaces(mPackage);
-        printClass();
-        printProperties(mMessage);
-        printPublic();
-        printFieldsOrderingDefinition();
-        encloseClass();
-        enclose();
-        printMetaTypeDeclaration(mPackage);
-    }
-
-    const std::set<std::string> &extractedModels() const {
-        return mExtractedModels;
-    }
-
-    void printFieldsOrderingDefinition() {
-        Indent();
-        mPrinter.Print(FieldsOrderingDefinitionContainerTemplate);
-        Outdent();
-    }
-
-
-};
-
 class QtSourcesGenerator : public ClassGeneratorBase
 {
-    std::string mPackage;
     const Descriptor* mMessage;
-    std::set<std::string> mExtractedModels;
 public:
-    QtSourcesGenerator(const std::string &package, const Descriptor *message, std::unique_ptr<io::ZeroCopyOutputStream> out) :
-        ClassGeneratorBase(message->name(), std::move(out))
-      , mPackage(std::move(package))
-      , mMessage(message){}
+    QtSourcesGenerator(const Descriptor *message, std::unique_ptr<io::ZeroCopyOutputStream> out) :
+        ClassGeneratorBase(message->full_name(), std::move(out))
+      , mMessage(message) {}
 
     void run() {
         printClassHeaderInclude();
-        printNamespaces(mPackage);
+        printNamespaces();
         printFieldsOrdering();
-        enclose();
+        encloseNamespaces();
     }
 
     void printClassHeaderInclude() {
@@ -137,36 +87,6 @@ public:
     }
 };
 
-class GlobalEnumsGenerator : public ClassGeneratorBase
-{
-    const FileDescriptor *mFile;
-
-public:
-    GlobalEnumsGenerator(std::unique_ptr<io::ZeroCopyOutputStream> out) :
-        ClassGeneratorBase("GlobalEnums", std::move(out))
-    {
-        printPreamble();
-    }
-
-    void startEnum(std::string package) {
-        printNamespaces(package);
-        printEnumClass();
-    }
-
-    void run(const FileDescriptor *file) {
-        printQEnums<FileDescriptor>(file);
-    }
-
-    void encloseEnum() {
-        encloseClass();
-        enclose();
-    }
-
-    void printEnumClass() {
-        mPrinter.Print({{"classname", mClassName}}, NonProtoClassDefinitionTemplate);
-    }
-};
-
 bool QtGenerator::Generate(const FileDescriptor *file,
                            const std::string &/*parameter*/,
                            GeneratorContext *generatorContext,
@@ -185,13 +105,15 @@ bool QtGenerator::Generate(const FileDescriptor *file,
         utils::tolower(baseFilename);
 
         std::string filename = baseFilename + ".h";
-        QtClassGenerator classGen(file->package(), message,
+        ProtobufClassGenerator classGen(message,
                                   std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(filename))));
         classGen.run();
-        extractedModels.insert(std::begin(classGen.extractedModels()), std::end(classGen.extractedModels()));
+
+        std::set<std::string> models = classGen.extractModels();
+        extractedModels.insert(std::begin(models), std::end(models));
 
         std::string sourceFileName = baseFilename + ".cpp";
-        QtSourcesGenerator classSourceGen(file->package(), message,
+        QtSourcesGenerator classSourceGen(message,
                                   std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(sourceFileName))));
         classSourceGen.run();
     }
@@ -202,7 +124,7 @@ bool QtGenerator::Generate(const FileDescriptor *file,
         utils::tolower(baseFilename);
 
         std::string headeFilename = baseFilename + ".h";
-        ServerGenerator serverGen(file->package(), service,
+        ServerGenerator serverGen(service,
                                   std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(headeFilename))));
         serverGen.run();
 
@@ -214,19 +136,14 @@ 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";
-    GlobalEnumsGenerator enumGen(std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(globalEnumsFilename))));
-    std::unordered_map<std::string/*package*/, std::list<const FileDescriptor *>> packageList;
+
+    PackagesList packageList;
     for (auto file : files) {
         packageList[file->package()].push_back(file);
     }
 
-    for (auto package : packageList) {
-        enumGen.startEnum(package.first);
-        for (auto file : package.second) {
-            enumGen.run(file);
-        }
-        enumGen.encloseEnum();
-    }
+    GlobalEnumsGenerator enumGen(packageList, std::move(std::unique_ptr<io::ZeroCopyOutputStream>(generatorContext->Open(globalEnumsFilename))));
+    enumGen.run();
 
     return CodeGenerator::GenerateAll(files, parameter, generatorContext, error);
 }

+ 3 - 1
src/generator/generator.h

@@ -36,6 +36,7 @@ class GeneratorContext;
 }}}
 
 namespace qtprotobuf {
+namespace generator {
 
 class QtGenerator : public ::google::protobuf::compiler::CodeGenerator
 {
@@ -50,4 +51,5 @@ class QtGenerator : public ::google::protobuf::compiler::CodeGenerator
                              std::string *error) const override;
 };
 
-}  // namespace qtprotobuf
+} //namespace generator
+} // namespace qtprotobuf

+ 68 - 0
src/generator/globalenumsgenerator.cpp

@@ -0,0 +1,68 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ *
+ * 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 "globalenumsgenerator.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;
+
+GlobalEnumsGenerator::GlobalEnumsGenerator(const PackagesList &packageList, std::unique_ptr<io::ZeroCopyOutputStream> out) :
+    ClassGeneratorBase("GlobalEnums", std::move(out))
+  , mPackageList(packageList) {}
+
+void GlobalEnumsGenerator::startEnum(const std::vector<std::string>& namespaces) {
+    printNamespaces(namespaces);
+    printEnumClass();
+}
+
+void GlobalEnumsGenerator::run() {
+    printPreamble();
+    std::vector<std::string> namespaces;
+    for (auto package : mPackageList) {
+        utils::split(package.first, namespaces, '.');
+        startEnum(namespaces);
+        for (auto file : package.second) {
+            run(file);
+        }
+        encloseEnum(namespaces);
+    }
+}
+
+void GlobalEnumsGenerator::run(const FileDescriptor *file) {
+    printQEnums(file);
+}
+
+void GlobalEnumsGenerator::encloseEnum(const std::vector<std::string>& namespaces) {
+    encloseClass();
+    encloseNamespaces(namespaces.size());
+}
+
+void GlobalEnumsGenerator::printEnumClass() {
+    mPrinter.Print({{"classname", mClassName}}, NonProtoClassDefinitionTemplate);
+}

+ 52 - 0
src/generator/globalenumsgenerator.h

@@ -0,0 +1,52 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>, 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 GlobalEnumsGenerator : public ClassGeneratorBase
+{
+    const ::google::protobuf::FileDescriptor *mFile;
+    PackagesList mPackageList;
+public:
+    GlobalEnumsGenerator(const PackagesList &packageList, std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> out);
+    virtual ~GlobalEnumsGenerator() = default;
+
+    void run();
+
+    void startEnum(const std::vector<std::string>& namespaces);
+    void run(const ::google::protobuf::FileDescriptor *file);
+    void encloseEnum(const std::vector<std::string>& namespaces);
+    void printEnumClass();
+};
+
+} //namespace generator
+} //namespace qtprotobuf
+

+ 1 - 1
src/generator/main.cpp

@@ -29,6 +29,6 @@
 
 int main(int argc, char *argv[])
 {
-    qtprotobuf::QtGenerator generator;
+    qtprotobuf::generator::QtGenerator generator;
     return ::google::protobuf::compiler::PluginMain(argc, argv, &generator);
 }

+ 361 - 0
src/generator/protobufclassgenerator.cpp

@@ -0,0 +1,361 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ *
+ * 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 "protobufclassgenerator.h"
+#include "utils.h"
+
+#include <google/protobuf/descriptor.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;
+
+namespace {
+const std::string VariantList("QVariantList");
+}
+
+ProtobufClassGenerator::ProtobufClassGenerator(const Descriptor *message, std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> out)
+    : ClassGeneratorBase(message->full_name(), std::move(out))
+    , mMessage(message)
+{
+
+}
+
+void ProtobufClassGenerator::printCopyFunctionality()
+{
+    assert(mMessage != nullptr);
+    mPrinter.Print({{"classname", mClassName}},
+                   CopyConstructorTemplate);
+
+    Indent();
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        printField(mMessage->field(i), CopyFieldTemplate);
+    }
+    Outdent();
+
+    mPrinter.Print(SimpleBlockEnclosureTemplate);
+    mPrinter.Print({{"classname", mClassName}},
+                   AssignmentOperatorTemplate);
+
+    Indent();
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        printField(mMessage->field(i), CopyFieldTemplate);
+    }
+    mPrinter.Print(AssignmentOperatorReturnTemplate);
+    Outdent();
+
+    mPrinter.Print(SimpleBlockEnclosureTemplate);
+
+}
+
+void ProtobufClassGenerator::printMoveSemantic()
+{
+    assert(mMessage != nullptr);
+    mPrinter.Print({{"classname", mClassName}},
+                   MoveConstructorTemplate);
+
+    Indent();
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        const FieldDescriptor* field = mMessage->field(i);
+        if (isComplexType(field) || field->is_repeated()) {
+            printField(field, MoveComplexFieldTemplate);
+        } else {
+            printField(field, MoveFieldTemplate);
+        }
+    }
+    Outdent();
+
+    mPrinter.Print(SimpleBlockEnclosureTemplate);
+    mPrinter.Print({{"classname", mClassName}},
+                   MoveAssignmentOperatorTemplate);
+
+    Indent();
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        const FieldDescriptor* field = mMessage->field(i);
+        if (isComplexType(field) || field->is_repeated()) {
+            printField(field, MoveComplexFieldTemplate);
+        } else {
+            printField(field, MoveFieldTemplate);
+        }
+    }
+    mPrinter.Print(AssignmentOperatorReturnTemplate);
+    Outdent();
+
+    mPrinter.Print(SimpleBlockEnclosureTemplate);
+}
+
+void ProtobufClassGenerator::printComparisonOperators()
+{
+    assert(mMessage != nullptr);
+    bool isFirst = true;
+    PropertyMap properties;
+    mPrinter.Print({{"type", mClassName}}, EqualOperatorTemplate);
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        const FieldDescriptor* field = mMessage->field(i);
+        if (producePropertyMap(field, properties)) {
+            if (!isFirst) {
+                mPrinter.Print("\n&& ");
+            } else {
+                Indent();
+                Indent();
+                isFirst = false;
+            }
+            mPrinter.Print(properties, EqualOperatorPropertyTemplate);
+        }
+    }
+
+    //Only if at least one field "copied"
+    if (!isFirst) {
+        Outdent();
+        Outdent();
+    }
+
+    mPrinter.Print(";\n");
+    mPrinter.Print(SimpleBlockEnclosureTemplate);
+
+    mPrinter.Print({{"type", mClassName}}, NotEqualOperatorTemplate);
+}
+
+void ProtobufClassGenerator::printIncludes(std::set<std::string> listModel)
+{
+    assert(mMessage != nullptr);
+    PropertyMap properties;
+    std::set<std::string> existingIncludes;
+    std::string newInclude;
+    const char* includeTemplate;
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        const FieldDescriptor* field = mMessage->field(i);
+        if (producePropertyMap(field, properties)) {
+            if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
+                newInclude = properties["type_lower"];
+                includeTemplate = InternalIncludeTemplate;
+            } else if (field->type() == FieldDescriptor::TYPE_STRING) {
+                includeTemplate = ExternalIncludeTemplate;
+            } else {
+                continue;
+            }
+
+            if (!field->is_repeated()) {
+                if (existingIncludes.find(newInclude) == std::end(existingIncludes)) {
+                    mPrinter.Print(properties, includeTemplate);
+                    existingIncludes.insert(newInclude);
+                }
+            } else {
+                std::string stringInclude = properties["type"];
+                if (stringInclude == VariantList
+                        && existingIncludes.find(stringInclude) == std::end(existingIncludes)) {
+                    mPrinter.Print(properties, ExternalIncludeTemplate);
+                    existingIncludes.insert(stringInclude);
+                }
+            }
+        }
+    }
+
+    // Print List model class name
+    if (listModel.size() > 0) {
+        mPrinter.Print(ListModelsIncludeTemplate);
+    }
+
+    for(auto modelTypeName : listModel) {
+        std::string modelTypeNameLower(modelTypeName);
+        utils::tolower(modelTypeNameLower);
+        mPrinter.Print({{"type_lower", modelTypeNameLower}}, InternalIncludeTemplate);
+    }
+}
+
+void ProtobufClassGenerator::printField(const FieldDescriptor *field, const char *fieldTemplate)
+{
+    assert(field != nullptr);
+    std::map<std::string, std::string> propertyMap;
+    if (producePropertyMap(field, propertyMap)) {
+        mPrinter.Print(propertyMap, fieldTemplate);
+    }
+}
+
+std::string ProtobufClassGenerator::getTypeName(const FieldDescriptor *field)
+{
+    assert(field != nullptr);
+    std::string typeName;
+    if (field->type() == FieldDescriptor::TYPE_MESSAGE) {
+        if (field->is_repeated()) {
+            return VariantList;
+        }
+        typeName = field->message_type()->name();
+    } else if (field->type() == FieldDescriptor::TYPE_ENUM) {
+        if (field->is_repeated()) {
+            return VariantList;
+        }
+        typeName = field->enum_type()->name();
+    } else {
+        auto it = TypeReflection.find(field->type());
+        if (it != std::end(TypeReflection)) {
+            typeName = it->second;
+            if (field->is_repeated()) {
+                std::string namespaceDefinition("qtprotobuf::");
+                typeName[0] = ::toupper(typeName[0]);
+                typeName.append("List");
+                if (typeName != "QStringList"
+                        && typeName != "QByteArrayList") {
+                    typeName = namespaceDefinition.append(typeName);
+                }
+            }
+        }
+    }
+
+    return typeName;
+}
+
+bool ProtobufClassGenerator::producePropertyMap(const FieldDescriptor *field, PropertyMap &propertyMap)
+{
+    assert(field != nullptr);
+    std::string typeName = getTypeName(field);
+
+    if (typeName.size() <= 0) {
+        std::cerr << "Type "
+                  << field->type_name()
+                  << " is not supported by Qt Generator"
+                     " please look at https://doc.qt.io/qt-5/qtqml-typesystem-basictypes.html"
+                     " for details" << std::endl;
+        return false;
+    }
+
+    std::string typeNameLower(typeName);
+    utils::tolower(typeNameLower);
+
+    std::string capProperty = field->camelcase_name();
+    capProperty[0] = ::toupper(capProperty[0]);
+
+    propertyMap = {{"type", typeName},
+                   {"type_lower", typeNameLower},
+                   {"property_name", field->camelcase_name()},
+                   {"property_name_cap", capProperty}};
+    return true;
+}
+
+bool ProtobufClassGenerator::isListType(const FieldDescriptor *field)
+{
+    assert(field != nullptr);
+    return field && field->is_repeated()
+            && field->type() == FieldDescriptor::TYPE_MESSAGE;
+}
+
+bool ProtobufClassGenerator::isComplexType(const FieldDescriptor *field)
+{
+    assert(field != nullptr);
+    return field->type() == FieldDescriptor::TYPE_MESSAGE
+            || field->type() == FieldDescriptor::TYPE_STRING
+            || field->type() == FieldDescriptor::TYPE_BYTES;
+}
+
+
+void ProtobufClassGenerator::printProperties()
+{
+    assert(mMessage != nullptr);
+    //private section
+    Indent();
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        const FieldDescriptor* field = mMessage->field(i);
+        if (!isListType(field)) {
+            const char* propertyTemplate = field->type() == FieldDescriptor::TYPE_MESSAGE ? MessagePropertyTemplate :
+                                                                                            PropertyTemplate;
+            printField(field, propertyTemplate);
+        }
+    }
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        printField(mMessage->field(i), MemberTemplate);
+    }
+    Outdent();
+
+    printQEnums(mMessage);
+
+    //public section
+    printPublic();
+
+    //Body
+    Indent();
+    printConstructor();
+    printCopyFunctionality();
+    printMoveSemantic();
+    printComparisonOperators();
+
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        printField(mMessage->field(i), GetterTemplate);
+    }
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        auto field = mMessage->field(i);
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE
+                || field->type() == FieldDescriptor::TYPE_STRING) {
+            printField(field, SetterTemplateComplexType);
+        } else {
+            printField(field, SetterTemplateSimpleType);
+        }
+    }
+    Outdent();
+
+    mPrinter.Print(SignalsBlockTemplate);
+
+    Indent();
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        printField(mMessage->field(i), SignalTemplate);
+    }
+    Outdent();
+}
+
+void ProtobufClassGenerator::printFieldsOrderingDefinition()
+{
+    Indent();
+    mPrinter.Print(FieldsOrderingDefinitionContainerTemplate);
+    Outdent();
+}
+
+std::set<std::string> ProtobufClassGenerator::extractModels() const
+{
+    std::set<std::string> extractedModels;
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        const FieldDescriptor* field = mMessage->field(i);
+        if (field->is_repeated()
+                && field->type() == FieldDescriptor::TYPE_MESSAGE) {
+            std::string typeName = field->message_type()->name();
+            extractedModels.insert(typeName);
+        }
+    }
+    return std::move(extractedModels);
+}
+
+void ProtobufClassGenerator::run()
+{
+    printPreamble();
+    printIncludes(extractModels());
+    printNamespaces();
+    printClassDeclaration();
+    printProperties();
+    printPublic();
+    printFieldsOrderingDefinition();
+    encloseClass();
+    encloseNamespaces(mNamespaces.size());
+    printMetaTypeDeclaration();
+}

+ 72 - 0
src/generator/protobufclassgenerator.h

@@ -0,0 +1,72 @@
+/*
+ * MIT License
+ *
+ * Copyright (c) 2019 Alexey Edelev <semlanik@gmail.com>
+ *
+ * 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 <google/protobuf/io/printer.h>
+#include <memory>
+
+#include "templates.h"
+
+namespace google { namespace protobuf {
+class FieldDescriptor;
+class Descriptor;
+namespace io {
+class ZeroCopyOutputStream;
+}}}
+
+namespace qtprotobuf {
+namespace generator {
+
+using PropertyMap = std::map<std::string, std::string>;
+
+class ProtobufClassGenerator : public ClassGeneratorBase
+{
+    const ::google::protobuf::Descriptor* mMessage;
+public:
+    ProtobufClassGenerator(const ::google::protobuf::Descriptor* message, std::unique_ptr<::google::protobuf::io::ZeroCopyOutputStream> out);
+    virtual ~ProtobufClassGenerator() = default;
+
+    void run() override;
+
+    void printIncludes(std::set<std::string> listModel);
+    void printCopyFunctionality();
+    void printMoveSemantic();
+    void printComparisonOperators();
+    void printField(const ::google::protobuf::FieldDescriptor *field, const char *fieldTemplate);
+    void printProperties();
+    void printFieldsOrderingDefinition();
+
+    std::set<std::string> extractModels() const;
+
+    static std::string getTypeName(const ::google::protobuf::FieldDescriptor *field);
+    static bool producePropertyMap(const ::google::protobuf::FieldDescriptor *field, PropertyMap &propertyMap);
+    static bool isComplexType(const ::google::protobuf::FieldDescriptor *field);
+    static bool isListType(const ::google::protobuf::FieldDescriptor *field);
+};
+
+}
+}

+ 3 - 5
src/generator/servergenerator.cpp

@@ -36,16 +36,14 @@
 #include "utils.h"
 #include "templates.h"
 
+using namespace ::qtprotobuf::generator;
 using namespace ::google::protobuf;
 using namespace ::google::protobuf::compiler;
 
-using namespace qtprotobuf;
-
 //TODO: need to decompose common and non-common logic and fields of ClassGeneratorBase 
-ServerGenerator::ServerGenerator(const std::string &package, const ServiceDescriptor *service, std::unique_ptr<io::ZeroCopyOutputStream> out) :
-    ClassGeneratorBase(service->name(), std::move(out))
+ServerGenerator::ServerGenerator(const ServiceDescriptor *service, std::unique_ptr<io::ZeroCopyOutputStream> out) :
+    ClassGeneratorBase(service->full_name(), std::move(out))
   , mService(service)
-  , mPackage(package)
 {
 }
 

+ 9 - 11
src/generator/servergenerator.h

@@ -31,34 +31,32 @@
 #include <google/protobuf/io/printer.h>
 
 namespace google { namespace protobuf {
-class FieldDescriptor;
-class Descriptor;
 class ServiceDescriptor;
 class Message;
-namespace io {
-class ZeroCopyOutputStream;
-}}}
+}}
 
 namespace qtprotobuf {
+namespace generator {
 
 class ServerGenerator : public ClassGeneratorBase
 {
     const google::protobuf::ServiceDescriptor *mService;
-    std::string mPackage;
 public:
-    ServerGenerator(const std::string &package, const google::protobuf::ServiceDescriptor *service, std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> out);
+    ServerGenerator(const google::protobuf::ServiceDescriptor *service, std::unique_ptr<google::protobuf::io::ZeroCopyOutputStream> out);
+    virtual ~ServerGenerator() = default;
 
     void run() {
         printPreamble();
         printIncludes(mService);
-        printNamespaces(mPackage);
+        printNamespaces();
         mPrinter.Print({{"classname", mClassName}}, NonProtoClassDefinitionTemplate);
         encloseClass();
-        enclose();
+        encloseNamespaces();
     }
 
-protected:
+private:
     void printIncludes(const google::protobuf::ServiceDescriptor *service);
 };
 
-}
+} //namespace generator
+} //namespace qtprotobuf

+ 4 - 2
src/generator/templates.h

@@ -30,6 +30,7 @@
 #include <google/protobuf/descriptor.h>
 
 namespace qtprotobuf {
+namespace generator {
 
 static const char *PreambleTemplate = "/* This file is autogenerated. DO NOT CHANGE. All changes will be lost */\n\n"
                                       "#pragma once\n\n"
@@ -47,7 +48,7 @@ static const char *NamespaceTemplate = "\nnamespace $namespace$ {\n";
 static const char *NonProtoClassDefinitionTemplate = "\nclass $classname$ : public QObject\n"
                                                      "{\n"
                                                      "    Q_OBJECT\n";
-static const char *ClassDefinitionTemplate = "\nclass $classname$ : public qtprotobuf::ProtobufObject<$classname$>\n"
+static const char *ClassDefinitionTemplate = "\nclass $classname$ final : public qtprotobuf::ProtobufObject<$classname$>\n"
                                              "{\n"
                                              "    Q_OBJECT\n";
 
@@ -132,4 +133,5 @@ static const std::unordered_map<::google::protobuf::FieldDescriptor::Type, std::
     //        {FieldDescriptor::TYPE_SINT64, "int"},//Not supported see https://doc.qt.io/qt-5/qtqml-typesystem-basictypes.html
 };
 
-}
+} //namespace generator
+} //namespace qtprotobuf

+ 14 - 2
src/generator/utils.h

@@ -28,12 +28,20 @@
 #include <string>
 #include <vector>
 #include <sstream>
+#include <unordered_map>
+#include <list>
+
+namespace google { namespace protobuf {
+class FileDescriptor;
+}}
 
 namespace qtprotobuf {
+namespace generator {
 namespace utils {
 
 static void split(const std::string &str, std::vector<std::string> &container, char delim)
 {
+    container.clear();
     std::stringstream stream(str);
     std::string token;
     while (std::getline(stream, token, delim)) {
@@ -53,5 +61,9 @@ static void tolower(std::string& str) {
     std::transform(std::begin(str), std::end(str), std::begin(str), ::tolower);
 }
 
-}
-}
+} //namespace utils
+
+using PackagesList = std::unordered_map<std::string/*package*/, std::list<const ::google::protobuf::FileDescriptor *>>;
+
+} //namespace generator
+} //namespace qtprotobuf