Add constructor

The printConstructor function is added for generating Constructor. So
setter functions are removed and all getter functions are changed to
const functions.

Bug: 157957506
Test: m -j && ./xsdc-cpp-tests
Change-Id: I57f33badf6b37d6ec140a59084f37829fa89d365
diff --git a/src/com/android/xsdc/cpp/CppCodeGenerator.java b/src/com/android/xsdc/cpp/CppCodeGenerator.java
index 4553cad..4dd3c57 100644
--- a/src/com/android/xsdc/cpp/CppCodeGenerator.java
+++ b/src/com/android/xsdc/cpp/CppCodeGenerator.java
@@ -277,35 +277,35 @@
             CppType type = elementTypes.get(i);
             XsdElement element = elements.get(i);
             XsdElement elementValue = resolveElement(element);
-            String typeName = element.isMultiple() || type instanceof CppComplexType ?
-                    String.format("std::vector<%s>", type.getName()) :
-                    String.format("std::optional<%s>", type.getName());
-            headerFile.printf("%s %s_;\n", typeName,
+            String typeName = Utils.elementTypeName(type.getName(),
+                    element.isMultiple() || type instanceof CppComplexType);
+            headerFile.printf("const %s %s_;\n", typeName,
                     Utils.toVariableName(getElementName(elementValue)));
         }
         for (int i = 0; i < attributeTypes.size(); ++i) {
             CppType type = attributeTypes.get(i);
             XsdAttribute attribute = resolveAttribute(attributes.get(i));
+            String variableName = Utils.toVariableName(attribute.getName());
             if (attribute.isRequired()) {
-                headerFile.printf("%s %s_;\n", type.getName(),
-                        Utils.toVariableName(attribute.getName()));
+                headerFile.printf("const %s %s_;\n", type.getName(), variableName);
             } else {
-                headerFile.printf("std::optional<%s> %s_;\n", type.getName(),
-                        Utils.toVariableName(attribute.getName()));
+                headerFile.printf("const std::optional<%s> %s_;\n", type.getName(), variableName);
             }
         }
         if (valueType != null) {
-            headerFile.printf("std::optional<%s> _value;\n", valueType.getName());
+            headerFile.printf("const std::optional<%s> _value;\n", valueType.getName());
         }
 
-        // print getters and setters
-
         headerFile.printf("public:\n");
+        String constructorArgs = printConstructor(name, nameScope, complexType, elements,
+                attributes, baseName);
+
+        // print getters and setters
         for (int i = 0; i < elementTypes.size(); ++i) {
             CppType type = elementTypes.get(i);
             XsdElement element = elements.get(i);
             XsdElement elementValue = resolveElement(element);
-            printGetterAndSetter(nameScope + name, type,
+            printGetter(nameScope + name, type,
                     Utils.toVariableName(getElementName(elementValue)),
                     type instanceof CppComplexType ? true : element.isMultiple(),
                     type instanceof CppComplexType ? false : ((CppSimpleType)type).isList(),
@@ -314,14 +314,14 @@
         for (int i = 0; i < attributeTypes.size(); ++i) {
             CppType type = attributeTypes.get(i);
             XsdAttribute attribute = resolveAttribute(attributes.get(i));
-            printGetterAndSetter(nameScope + name, type, Utils.toVariableName(attribute.getName()),
+            printGetter(nameScope + name, type, Utils.toVariableName(attribute.getName()),
                     false, false, attribute.isRequired());
         }
         if (valueType != null) {
-            printGetterAndSetter(nameScope + name, valueType, "value", false, false, false);
+            printGetter(nameScope + name, valueType, "value", false, false, false);
         }
 
-        printParser(name, nameScope, complexType);
+        printParser(name, nameScope, complexType, constructorArgs);
 
         if (writer) {
             printWriter(name, nameScope, complexType);
@@ -330,7 +330,7 @@
         headerFile.println("};\n");
     }
 
-    private void printParser(String name, String nameScope, XsdComplexType complexType)
+    private void printParser(String name, String nameScope, XsdComplexType complexType, String args)
             throws CppCodeGeneratorException {
         CppSimpleType baseValueType = (complexType instanceof XsdSimpleContent) ?
                 getValueType((XsdSimpleContent) complexType, true) : null;
@@ -355,16 +355,28 @@
         headerFile.printf("static %s read(xmlNode *root);\n", fullName, Utils.lowerize(name));
         cppFile.printf("\n%s %s::read(xmlNode *root) {\n", fullName, fullName);
 
-        cppFile.printf("%s instance;\n std::string raw;\n", fullName, fullName);
+        cppFile.print("std::string raw;\n");
 
         for (int i = 0; i < allAttributes.size(); ++i) {
             CppType type = allAttributeTypes.get(i);
             XsdAttribute attribute = resolveAttribute(allAttributes.get(i));
             String variableName = Utils.toVariableName(attribute.getName());
             cppFile.printf("raw = getXmlAttribute(root, \"%s\");\n", attribute.getName());
+            if (attribute.isRequired()) {
+                if (type.getName().equals("bool")) {
+                    cppFile.printf("%s %s = false;\n", type.getName(), variableName);
+                } else if (type.getName().equals("std::string")) {
+                    cppFile.printf("%s %s;\n", type.getName(), variableName);
+                } else {
+                    cppFile.printf("%s %s = 0;\n", type.getName(), variableName);
+                }
+            } else {
+                cppFile.printf("std::optional<%s> %s = std::nullopt;\n", type.getName(),
+                        variableName);
+            }
             cppFile.printf("if (raw != \"\") {\n");
             cppFile.print(type.getParsingExpression());
-            cppFile.printf("instance.set%s(value);\n}\n", Utils.capitalize(variableName));
+            cppFile.printf("%s = value;\n}\n", variableName);
         }
 
         if (baseValueType != null) {
@@ -377,6 +389,14 @@
             cppFile.printf("instance.setValue(value);\n");
             cppFile.printf("}\n");
         } else if (!allElements.isEmpty()) {
+            for (int i = 0; i < allElements.size(); ++i) {
+                CppType type = allElementTypes.get(i);
+                XsdElement element = allElements.get(i);
+                XsdElement elementValue = resolveElement(element);
+                String variableName = Utils.toVariableName(getElementName(elementValue));
+                cppFile.printf("%s %s;\n", Utils.elementTypeName(type.getName(),
+                        element.isMultiple() || type instanceof CppComplexType), variableName);
+            }
             cppFile.print("for (xmlNode *child = root->xmlChildrenNode; child != nullptr;"
                     + " child = child->next) {\n");
             for (int i = 0; i < allElements.size(); ++i) {
@@ -384,30 +404,30 @@
                 XsdElement element = allElements.get(i);
                 XsdElement elementValue = resolveElement(element);
                 String variableName = Utils.toVariableName(getElementName(elementValue));
+
                 if (i != 0) cppFile.printf("} else ");
-                cppFile.printf("if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>");
+                cppFile.print("if (!xmlStrcmp(child->name, reinterpret_cast<const xmlChar*>");
                 cppFile.printf("(\"%s\"))) {\n", elementValue.getName());
 
                 if (type instanceof CppSimpleType) {
-                    cppFile.printf("auto xmlValue = make_xmlUnique(xmlNodeListGetString(");
-                    cppFile.printf("child->doc, child->xmlChildrenNode, 1));\n");
-                    cppFile.printf("if (xmlValue == nullptr) {\nraw = \"\";\n} else {\n");
-                    cppFile.printf("raw = reinterpret_cast<const char*>(xmlValue.get());\n}\n");
+                    cppFile.print("auto xmlValue = make_xmlUnique(xmlNodeListGetString(");
+                    cppFile.print("child->doc, child->xmlChildrenNode, 1));\n");
+                    cppFile.print("if (xmlValue == nullptr) {\nraw = \"\";\n} else {\n");
+                    cppFile.print("raw = reinterpret_cast<const char*>(xmlValue.get());\n}\n");
                 }
 
                 cppFile.print(type.getParsingExpression());
 
                 if (element.isMultiple() || type instanceof CppComplexType) {
-                    cppFile.printf("instance.get%s().push_back(std::move(value));\n",
-                            Utils.capitalize(variableName));
+                    cppFile.printf("%s.push_back(std::move(value));\n", variableName);
                 } else {
-                    cppFile.printf("instance.set%s(value);\n", Utils.capitalize(variableName));
+                    cppFile.printf("%s = std::move(value);\n", variableName);
                 }
             }
             cppFile.printf("}\n}\n");
         }
-        cppFile.printf("return instance;\n"
-                + "}\n");
+        cppFile.printf("%s instance%s;\n", fullName, args.length() > 0 ? "(" + args + ")" : "");
+        cppFile.print("return instance;\n}\n");
     }
 
     private void printWriter(String name, String nameScope, XsdComplexType complexType)
@@ -432,8 +452,9 @@
         }
 
         String fullName = nameScope + name;
-        headerFile.printf("void write(std::ostream& out, const std::string& name);\n");
-        cppFile.printf("\nvoid %s::write(std::ostream& out, const std::string& name) {\n", fullName);
+        headerFile.printf("void write(std::ostream& out, const std::string& name) const;\n");
+        cppFile.printf("\nvoid %s::write(std::ostream& out, const std::string& name) const {\n",
+                fullName);
 
         cppFile.printf("out << printIndent() << \"<\" << name;\n");
         for (int i = 0; i < allAttributes.size(); ++i) {
@@ -491,15 +512,15 @@
         cppFile.printf("}\n");
     }
 
-    private void printGetterAndSetter(String name, CppType type, String variableName,
+    private void printGetter(String name, CppType type, String variableName,
             boolean isMultiple, boolean isMultipleType, boolean isRequired) {
         String typeName = isMultiple ? String.format("std::vector<%s>",
                 type.getName()) : type.getName();
 
-        headerFile.printf("%s& get%s();\n", typeName, Utils.capitalize(variableName));
+        headerFile.printf("const %s& get%s() const;\n", typeName, Utils.capitalize(variableName));
 
         cppFile.println();
-        cppFile.printf("%s& %s::get%s() {\n"
+        cppFile.printf("const %s& %s::get%s() const {\n"
                 + "return %s;\n}\n\n",
                 typeName, name, Utils.capitalize(variableName), isMultiple || isRequired ?
                 variableName + "_" : String.format("%s_.value()", variableName));
@@ -518,10 +539,10 @@
             String elementTypeName = type instanceof CppComplexType ? type.getName() :
                     ((CppSimpleType)type).getTypeName();
             if (elementTypeName.equals("bool")) {
-                headerFile.printf("%s getFirst%s();\n",
+                headerFile.printf("%s getFirst%s() const;\n",
                         elementTypeName, Utils.capitalize(variableName));
                 cppFile.println();
-                cppFile.printf("%s %s::getFirst%s() {\n"
+                cppFile.printf("%s %s::getFirst%s() const {\n"
                         + "if (%s_%sempty()) {\n"
                         + "return false;\n"
                         + "}\n"
@@ -532,10 +553,10 @@
                         isMultiple ? String.format("%s_[0]", variableName) :
                         String.format("%s_.value()[0]", variableName));
             } else {
-                headerFile.printf("%s* getFirst%s();\n",
+                headerFile.printf("const %s* getFirst%s() const;\n",
                         elementTypeName, Utils.capitalize(variableName));
                 cppFile.println();
-                cppFile.printf("%s* %s::getFirst%s() {\n"
+                cppFile.printf("const %s* %s::getFirst%s() const {\n"
                         + "if (%s_%sempty()) {\n"
                         + "return nullptr;\n"
                         + "}\n"
@@ -547,15 +568,87 @@
                         String.format("%s_.value()[0]", variableName));
             }
         }
+    }
 
-        if (isMultiple) return;
-        headerFile.printf("void set%s(%s);\n", Utils.capitalize(variableName), typeName);
-        cppFile.println();
-        cppFile.printf("void %s::set%s(%s %s) {\n"
-                + "%s_ = %s;\n"
-                + "}\n",
-                name, Utils.capitalize(variableName), typeName, variableName,
-                variableName, Utils.toAssignmentName(typeName, variableName, isMultipleType));
+    private String printConstructor(String name, String nameScope, XsdComplexType complexType,
+            List<XsdElement> elements, List<XsdAttribute> attributes, String baseName)
+            throws CppCodeGeneratorException {
+        String fullName = nameScope + name;
+        StringBuilder constructorArgs = new StringBuilder();
+        StringBuilder parentArgs = new StringBuilder();
+        StringBuilder constructor = new StringBuilder();
+        StringBuilder args = new StringBuilder();
+
+        List<XsdElement> allElements = new ArrayList<>();
+        List<XsdAttribute> allAttributes = new ArrayList<>();
+        stackComponents(complexType, allElements, allAttributes);
+
+        List<CppType> allElementTypes = new ArrayList<>();
+        for (XsdElement element : allElements) {
+            XsdElement elementValue = resolveElement(element);
+            CppType type = parseType(elementValue.getType(), elementValue.getName());
+            String variableName = Utils.toVariableName(getElementName(elementValue));
+            constructorArgs.append(String.format(", %s %s", Utils.elementTypeName(type.getName(),
+                    element.isMultiple() || type instanceof CppComplexType), variableName));
+            args.append(String.format(", %s", variableName));
+            boolean isMultipleType;
+            if (type instanceof CppComplexType) {
+                isMultipleType = true;
+            } else if (((CppSimpleType)type).isList()) {
+                isMultipleType = true;
+            } else {
+                isMultipleType = false;
+            }
+
+            if (elements.contains(element)) {
+                constructor.append(String.format(", %s_(%s)", variableName,
+                        Utils.toAssignmentName(type.getName(), variableName, isMultipleType)));
+            } else {
+                parentArgs.append(String.format(", %s", variableName));
+            }
+        }
+        List<CppSimpleType> allAttributeTypes = new ArrayList<>();
+        for (XsdAttribute attribute : allAttributes) {
+            CppType type = parseSimpleType(resolveAttribute(attribute).getType(), false);
+            String variableName = Utils.toVariableName(resolveAttribute(attribute).getName());
+            if (attribute.isRequired()) {
+                constructorArgs.append(String.format(", %s %s", type.getName(), variableName));
+            } else {
+                constructorArgs.append(String.format(", std::optional<%s> %s", type.getName(),
+                        variableName));
+            }
+            args.append(String.format(", %s", variableName));
+            boolean isMultipleType = ((CppSimpleType)type).isList() ? true : false;
+            if (attributes.contains(attribute)) {
+                constructor.append(String.format(", %s_(%s)", variableName,
+                        Utils.toAssignmentName(type.getName(), variableName, isMultipleType)));
+            } else {
+                parentArgs.append(String.format(", %s", variableName));
+            }
+        }
+
+        String constructorArgsString = constructorArgs.toString();
+        String constructorString = constructor.toString();
+        if (constructorArgsString.length() > 0) {
+            constructorArgsString = constructorArgsString.substring(2);
+        }
+        headerFile.printf("%s(%s);\n", name, constructorArgsString);
+        cppFile.printf("\n%s::%s(%s) : ", fullName, name, constructorArgsString);
+
+        String parentArgsString = parentArgs.toString();
+        if (parentArgsString.length() > 0) {
+            parentArgsString = parentArgsString.substring(2);
+            cppFile.printf("%s(%s)", baseName, parentArgsString);
+        } else {
+            constructorString = constructorString.substring(2);
+        }
+        cppFile.printf("%s {\n}\n", constructorString);
+
+        String argsString = args.toString();
+        if (argsString.length() > 0) {
+            argsString = argsString.substring(2);
+        }
+        return argsString;
     }
 
     private void printXmlParser() throws CppCodeGeneratorException {
diff --git a/src/com/android/xsdc/cpp/Utils.java b/src/com/android/xsdc/cpp/Utils.java
index 2f29e80..3f21ac4 100644
--- a/src/com/android/xsdc/cpp/Utils.java
+++ b/src/com/android/xsdc/cpp/Utils.java
@@ -90,4 +90,14 @@
         }
         return variableName;
     }
+
+    static String elementTypeName(String name, boolean isMultipleType) {
+        String res;
+        if (isMultipleType) {
+            res = "std::vector<" + name + ">";
+        } else {
+            res = "std::optional<" + name + ">";
+        }
+        return res;
+    }
 }