Преглед изворни кода

Fix cycling dependency issues in multi-file generation

- Add class definition to reslove cycling dependency issue
- Implement tests
Alexey Edelev пре 5 година
родитељ
комит
260913354c

+ 56 - 0
src/generator/classgeneratorbase.cpp

@@ -342,3 +342,59 @@ bool ClassGeneratorBase::isComplexType(const FieldDescriptor *field)
             || field->type() == FieldDescriptor::TYPE_BYTES;
 }
 
+
+void ClassGeneratorBase::printInclude(const google::protobuf::Descriptor *message, const FieldDescriptor *field, std::set<std::string> &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(message, field->message_type()->field(0), existingIncludes);
+            printInclude(message, field->message_type()->field(1), existingIncludes);
+            includeTemplate = Templates::ExternalIncludeTemplate;
+        } else {
+            std::string typeName = field->message_type()->name();
+            utils::tolower(typeName);
+            newInclude = 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: {
+        EnumVisibility enumVisibily = getEnumVisibility(field, message);
+        if (enumVisibily == GLOBAL_ENUM) {
+            includeTemplate = Templates::GlobalEnumIncludeTemplate;
+        } else if (enumVisibily == NEIGHBOUR_ENUM) {
+            includeTemplate = Templates::InternalIncludeTemplate;
+            std::string fullEnumName = field->enum_type()->full_name();
+            std::vector<std::string> fullEnumNameParts;
+            utils::split(fullEnumName, fullEnumNameParts, '.');
+            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)) {
+        mPrinter->Print({{"include", newInclude}}, includeTemplate);
+        existingIncludes.insert(newInclude);
+    }
+}

+ 1 - 0
src/generator/classgeneratorbase.h

@@ -76,6 +76,7 @@ public:
     void printMetaTypeDeclaration();
     void encloseNamespaces();
     void encloseNamespaces(int count);
+    void printInclude(const google::protobuf::Descriptor *message, const google::protobuf::FieldDescriptor *field, std::set<std::string> &existingIncludes);
     bool hasGlobalEnum(const std::list<const ::google::protobuf::FileDescriptor *> &list);
     void printField(const google::protobuf::Descriptor *message, const ::google::protobuf::FieldDescriptor *field, const char *fieldTemplate);
     bool producePropertyMap(const google::protobuf::Descriptor *message, const ::google::protobuf::FieldDescriptor *field, PropertyMap &propertyMap);

+ 16 - 60
src/generator/protobufclassgenerator.cpp

@@ -89,63 +89,7 @@ void ProtobufClassGenerator::printIncludes()
 
     std::set<std::string> existingIncludes;
     for (int i = 0; i < mMessage->field_count(); i++) {
-        printInclude(mMessage->field(i), existingIncludes);
-    }
-}
-
-void ProtobufClassGenerator::printInclude(const FieldDescriptor *field, std::set<std::string> &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(field->message_type()->field(0), existingIncludes);
-            printInclude(field->message_type()->field(1), existingIncludes);
-            includeTemplate = Templates::ExternalIncludeTemplate;
-        } else {
-            std::string typeName = field->message_type()->name();
-            utils::tolower(typeName);
-            newInclude = 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: {
-        EnumVisibility enumVisibily = getEnumVisibility(field, mMessage);
-        if (enumVisibily == GLOBAL_ENUM) {
-            includeTemplate = Templates::GlobalEnumIncludeTemplate;
-        } else if (enumVisibily == NEIGHBOUR_ENUM) {
-            includeTemplate = Templates::InternalIncludeTemplate;
-            std::string fullEnumName = field->enum_type()->full_name();
-            std::vector<std::string> fullEnumNameParts;
-            utils::split(fullEnumName, fullEnumNameParts, '.');
-            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)) {
-        mPrinter->Print({{"include", newInclude}}, includeTemplate);
-        existingIncludes.insert(newInclude);
+        printInclude(mMessage, mMessage->field(i), existingIncludes);
     }
 }
 
@@ -231,7 +175,7 @@ void ProtobufClassGenerator::printMaps()
     Outdent();
 }
 
-void ProtobufClassGenerator::printLocalEmumsMetaTypesDeclaration()
+void ProtobufClassGenerator::printLocalEnumsMetaTypesDeclaration()
 {
     for (int i = 0; i < mMessage->field_count(); i++) {
         const FieldDescriptor *field = mMessage->field(i);
@@ -388,6 +332,7 @@ void ProtobufClassGenerator::run()
     printPreamble();
     printIncludes();
     printNamespaces();
+    printFieldClassDeclaration();
     printClassDeclaration();
     printProperties();
     printPrivate();
@@ -399,10 +344,21 @@ void ProtobufClassGenerator::run()
     encloseNamespaces();
     printMetaTypeDeclaration();
     printMapsMetaTypesDeclaration();
-    printLocalEmumsMetaTypesDeclaration();
+    printLocalEnumsMetaTypesDeclaration();
 }
 
 void ProtobufClassGenerator::printDestructor()
 {
-    mPrinter->Print({{"classname", mClassName}}, "virtual ~$classname$();");
+    mPrinter->Print({{"classname", mClassName}}, "virtual ~$classname$();\n");
+}
+
+void ProtobufClassGenerator::printFieldClassDeclaration()
+{
+    for(int i = 0; i < mMessage->field_count(); i++) {
+        auto field = mMessage->field(i);
+        if (field->type() == FieldDescriptor::TYPE_MESSAGE
+                && !field->is_map() && !field->is_repeated()) {
+            mPrinter->Print({{"classname", field->message_type()->name()}}, Templates::ProtoClassDeclarationTemplate);
+        }
+    }
 }

+ 2 - 2
src/generator/protobufclassgenerator.h

@@ -62,10 +62,10 @@ public:
     void printConstructor();
     void printDestructor();
     void printListType();
-    void printInclude(const google::protobuf::FieldDescriptor *field, std::set<std::string> &existingIncludes);
     void printMaps();
     void printMapsMetaTypesDeclaration();
-    void printLocalEmumsMetaTypesDeclaration();
+    void printLocalEnumsMetaTypesDeclaration();
+    void printFieldClassDeclaration();
 
     std::set<std::string> extractModels() const;
 

+ 8 - 0
src/generator/protobufsourcegenerator.cpp

@@ -408,3 +408,11 @@ void ProtobufSourceGenerator::printDestructor()
     mPrinter->Print({{"classname", mClassName}}, "$classname$::~$classname$()\n"
                                                  "{}\n\n");
 }
+
+void ProtobufSourceGenerator::printIncludes()
+{
+    std::set<std::string> existingIncludes;
+    for (int i = 0; i < mMessage->field_count(); i++) {
+        printInclude(mMessage, mMessage->field(i), existingIncludes);
+    }
+}

+ 2 - 0
src/generator/protobufsourcegenerator.h

@@ -45,10 +45,12 @@ public:
     void printComparisonOperators();
     void printGetters();
     void printDestructor();
+    void printIncludes();
 
     void run() override {
         printDisclaimer();
         printClassHeaderInclude();
+        printIncludes();
         printNamespaces();
         printDestructor();
         printFieldsOrdering();

+ 1 - 1
src/generator/singlefilegenerator.cpp

@@ -159,7 +159,7 @@ bool SingleFileGenerator::GenerateMessages(const ::google::protobuf::FileDescrip
         classGen.encloseNamespaces();
         classGen.printMetaTypeDeclaration();
         classGen.printMapsMetaTypesDeclaration();
-        classGen.printLocalEmumsMetaTypesDeclaration();
+        classGen.printLocalEnumsMetaTypesDeclaration();
 
         ProtobufSourceGenerator srcGen(message,
                                        outSourcePrinter);

+ 7 - 0
tests/test_protobuf/proto/sequencetest.proto

@@ -10,3 +10,10 @@ message TestMessageSequence2 {
     bool testField = 1;
 }
 
+message CyclingSecondDependency {
+    CyclingFirstDependency testField = 1;
+}
+
+message CyclingFirstDependency {
+    CyclingSecondDependency testField = 1;
+}

+ 6 - 0
tests/test_protobuf/simpletest.cpp.inc

@@ -773,5 +773,11 @@ TEST_F(SimpleTest, SequenceTest)
     assertMessagePropertyRegistered<sequence::TestMessageSequence2, bool>(1, "bool", "testField");
 }
 
+TEST_F(SimpleTest, CyclingTest)
+{
+    assertMessagePropertyRegistered<sequence::CyclingFirstDependency, sequence::CyclingSecondDependency*>(1, "CyclingSecondDependency*", "testField");
+    assertMessagePropertyRegistered<sequence::CyclingSecondDependency, sequence::CyclingFirstDependency*>(1, "CyclingFirstDependency*", "testField");
+}
+
 } // tests
 } // qtprotobuf

+ 2 - 0
tests/test_protobuf_multifile/simpletest.cpp

@@ -72,6 +72,8 @@
 #include "combinedmessageunderscorefield.h"
 #include "testmessagesequence.h"
 #include "testmessagesequence2.h"
+#include "cyclingseconddependency.h"
+#include "cyclingfirstdependency.h"
 
 #include "globalenums.h"