From 6ad3395f34a20366ec0dc99b9cff755a3479a161 Mon Sep 17 00:00:00 2001
From: =?UTF-8?q?R=C3=A9mi=20Bernon?= <rbernon@codeweavers.com>
Date: Fri, 22 Sep 2023 00:09:46 +0200
Subject: [PATCH] vrclient: Split C++/C method generation helpers.

CW-Bug-Id: #22729
---
 vrclient_x64/gen_wrapper.py | 252 ++++++++++++++++++++----------------
 1 file changed, 142 insertions(+), 110 deletions(-)

diff --git a/vrclient_x64/gen_wrapper.py b/vrclient_x64/gen_wrapper.py
index 6f272e28..8e72cce1 100755
--- a/vrclient_x64/gen_wrapper.py
+++ b/vrclient_x64/gen_wrapper.py
@@ -470,35 +470,19 @@ def handle_method_hpp(method_name, cppname, method, cpp_h):
     cpp_h.write(f'extern {ret}{cppname}_{method_name}({", ".join(params)});\n')
 
 
-def handle_method(used_name, cfile, classname, winclassname, cppname, method, cpp, iface_version):
-    returns_record = method.result_type.get_canonical().kind == TypeKind.RECORD
-    if returns_record:
-        parambytes = 8 #_this + return pointer
-    else:
-        parambytes = 4 #_this
-    for param in get_params(method):
-        parambytes += param.type.get_size()
-    cfile.write("DEFINE_THISCALL_WRAPPER(%s_%s, %s)\n" % (winclassname, used_name, parambytes))
+def handle_method_cpp(method_name, classname, cppname, method, cpp):
     if strip_ns(method.result_type.spelling).startswith("IVR"):
-        cfile.write("win%s " % (strip_ns(method.result_type.spelling)))
         cpp.write("void *")
-    elif returns_record:
-        cfile.write("%s *" % strip_ns(method.result_type.spelling))
-        cpp.write("%s " % method.result_type.spelling)
     else:
-        cfile.write("%s " % strip_ns(method.result_type.spelling))
         cpp.write("%s " % method.result_type.spelling)
-    cfile.write('__thiscall %s_%s(%s *_this' % (winclassname, used_name, winclassname))
-    cpp.write("%s_%s(void *linux_side" % (cppname, used_name))
-    if returns_record:
-        cfile.write(", %s *_r" % strip_ns(method.result_type.spelling))
+    cpp.write("%s_%s(void *linux_side" % (cppname, method_name))
     unnamed = 'a'
     do_lin_to_win = None
     do_win_to_lin = None
     do_size_fixup = None
     do_wrap = None
     do_unwrap = None
-    for param in get_params(method):
+    for param in method.get_arguments():
         if param.type.kind == TypeKind.POINTER and \
                 param.type.get_pointee().kind == TypeKind.UNEXPOSED:
             #unspecified function pointer
@@ -531,15 +515,146 @@ def handle_method(used_name, cfile, classname, winclassname, cppname, method, cp
                     do_size_fixup = (strip_ns(real_name), param.spelling)
 
         if param.spelling == "":
-            cfile.write(", %s _%s" % (typename, unnamed))
             cpp.write(", %s _%s" % (typename, unnamed))
             unnamed = chr(ord(unnamed) + 1)
         else:
-            cfile.write(", %s %s" % (typename, param.spelling))
             cpp.write(", %s %s" % (typename, param.spelling))
-    cfile.write(")\n{\n")
     cpp.write(")\n{\n")
 
+    if do_lin_to_win or do_win_to_lin:
+        if do_lin_to_win:
+            cpp.write("    %s lin;\n" % do_lin_to_win[0])
+        else:
+            cpp.write("    %s lin;\n" % do_win_to_lin[0])
+        if not method.result_type.kind == TypeKind.VOID:
+            cpp.write("    %s _ret;\n" % method.result_type.spelling)
+
+    if do_wrap:
+        cpp.write("    %s *lin;\n" % do_wrap[0])
+        if not method.result_type.kind == TypeKind.VOID:
+            cpp.write("    %s _ret;\n" % method.result_type.spelling)
+
+    if do_win_to_lin:
+        #XXX we should pass the struct size here
+        cpp.write("    if(%s)\n" % do_win_to_lin[1])
+        cpp.write("        struct_%s_%s_win_to_lin(%s, &lin);\n" % (strip_ns(do_win_to_lin[0]), display_sdkver(sdkver), do_win_to_lin[1]))
+
+    if method.result_type.kind == TypeKind.VOID:
+        cpp.write("    ")
+    elif do_lin_to_win or do_win_to_lin or do_wrap:
+        cpp.write("    _ret = ")
+    else:
+        cpp.write("    return ")
+
+    cpp.write("((%s*)linux_side)->%s(" % (classname, method.spelling))
+    unnamed = 'a'
+    first = True
+    next_is_size = False
+    next_is_size_no_conv = False
+    convert_size_param = ""
+    for param in method.get_arguments():
+        if not first:
+            cpp.write(", ")
+        else:
+            first = False
+        if param.spelling == "":
+            cpp.write("(%s)_%s" % (param.type.spelling, unnamed))
+            unnamed = chr(ord(unnamed) + 1)
+        else:
+            if do_lin_to_win and do_lin_to_win[1] == param.spelling or \
+                    do_win_to_lin and do_win_to_lin[1] == param.spelling or \
+                    do_wrap and do_wrap[1] == param.spelling:
+                cpp.write("%s ? &lin : nullptr" % param.spelling)
+                if do_win_to_lin:
+                    assert(not do_win_to_lin[0] in STRUCTS_NEXT_IS_SIZE_UNHANDLED)
+                    if do_win_to_lin[0] in STRUCTS_NEXT_IS_SIZE:
+                        next_is_size = True
+            elif do_unwrap and do_unwrap[1] == param.spelling:
+                cpp.write("struct_%s_%s_unwrap(%s)" % (strip_ns(do_unwrap[0]), display_sdkver(sdkver), do_unwrap[1]))
+            elif do_size_fixup and do_size_fixup[1] == param.spelling:
+                next_is_size = True
+                next_is_size_no_conv = True
+                cpp.write("(%s)%s" % (param.type.spelling, param.spelling))
+            elif next_is_size:
+                next_is_size = False
+                if next_is_size_no_conv and param.type.spelling == "uint32_t":
+                    cpp.write("std::min(%s, (uint32_t)sizeof(vr::%s))" % (param.spelling, do_size_fixup[0]))
+                    convert_size_param = ", " + param.spelling
+                elif param.type.spelling == "uint32_t":
+                    cpp.write("%s ? sizeof(lin) : 0" % param.spelling)
+                    convert_size_param = ", " + param.spelling
+                else:
+                    cpp.write("(%s)%s" % (param.type.spelling, param.spelling))
+                    convert_size_param = ", -1"
+                next_is_size_no_conv = False
+            elif "&" in param.type.spelling:
+                cpp.write("*%s" % param.spelling)
+            else:
+                cpp.write("(%s)%s" % (param.type.spelling, param.spelling))
+    cpp.write(");\n")
+    if do_lin_to_win:
+        if next_is_size and not convert_size_param:
+            convert_size_param = ", -1"
+        cpp.write("    if(%s)\n" % do_lin_to_win[1])
+        cpp.write("        struct_%s_%s_lin_to_win(&lin, %s%s);\n" % (strip_ns(do_lin_to_win[0]), display_sdkver(sdkver), do_lin_to_win[1], convert_size_param))
+    if do_lin_to_win or do_win_to_lin:
+        if not method.result_type.kind == TypeKind.VOID:
+            cpp.write("    return _ret;\n")
+    if do_wrap and not method.result_type.kind == TypeKind.VOID:
+            cpp.write("    if(_ret == 0)\n")
+            cpp.write("        *%s = struct_%s_%s_wrap(lin);\n" % (do_wrap[1], strip_ns(do_wrap[0]), display_sdkver(sdkver)))
+            cpp.write("    return _ret;\n")
+    cpp.write("}\n\n")
+
+
+def handle_method_c(used_name, classname, winclassname, cppname, method, iface_version, cfile):
+    returns_record = method.result_type.get_canonical().kind == TypeKind.RECORD
+    if returns_record:
+        parambytes = 8 #_this + return pointer
+    else:
+        parambytes = 4 #_this
+    for param in method.get_arguments():
+        parambytes += param.type.get_size()
+    cfile.write("DEFINE_THISCALL_WRAPPER(%s_%s, %s)\n" % (winclassname, used_name, parambytes))
+    if strip_ns(method.result_type.spelling).startswith("IVR"):
+        cfile.write("win%s " % (strip_ns(method.result_type.spelling)))
+    elif returns_record:
+        cfile.write("%s *" % strip_ns(method.result_type.spelling))
+    else:
+        cfile.write("%s " % strip_ns(method.result_type.spelling))
+    cfile.write('__thiscall %s_%s(%s *_this' % (winclassname, used_name, winclassname))
+    if returns_record:
+        cfile.write(", %s *_r" % strip_ns(method.result_type.spelling))
+    unnamed = 'a'
+    for param in method.get_arguments():
+        if param.type.kind == TypeKind.POINTER and \
+                param.type.get_pointee().kind == TypeKind.UNEXPOSED:
+            #unspecified function pointer
+            typename = "void *"
+        else:
+            typename = param.type.spelling.split("::")[-1].replace("&", "*")
+            real_type = param.type;
+            while real_type.kind == TypeKind.POINTER:
+                real_type = real_type.get_pointee()
+            if param.type.kind == TypeKind.POINTER:
+                if strip_ns(param.type.get_pointee().get_canonical().spelling) in SDK_STRUCTS:
+                    do_unwrap = (strip_ns(param.type.get_pointee().get_canonical().spelling), param.spelling)
+                    typename = "win" + do_unwrap[0] + "_" + display_sdkver(sdkver) + " *"
+                elif param.type.get_pointee().get_canonical().kind == TypeKind.POINTER and \
+                        strip_ns(param.type.get_pointee().get_pointee().get_canonical().spelling) in SDK_STRUCTS:
+                    do_wrap = (strip_ns(param.type.get_pointee().get_pointee().get_canonical().spelling), param.spelling)
+                    typename = "win" + do_wrap[0] + "_" + display_sdkver(sdkver) + " **"
+                elif real_type.get_canonical().kind == TypeKind.RECORD and \
+                        struct_needs_conversion(real_type.get_canonical()):
+                    typename = typename.replace(strip_ns(real_type.spelling), "win%s_%s" % (strip_ns(real_type.get_canonical().spelling), display_sdkver(sdkver)))
+
+        if param.spelling == "":
+            cfile.write(", %s _%s" % (typename, unnamed))
+            unnamed = chr(ord(unnamed) + 1)
+        else:
+            cfile.write(", %s %s" % (typename, param.spelling))
+    cfile.write(")\n{\n")
+
     path_conv = get_path_converter(method)
 
     if path_conv:
@@ -558,44 +673,16 @@ def handle_method(used_name, cfile, classname, winclassname, cppname, method, cp
         elif len(path_conv["l2w_names"]) > 0:
             cfile.write("    %s path_result;\n" % method.result_type.spelling)
 
-    if do_lin_to_win or do_win_to_lin:
-        if do_lin_to_win:
-            cpp.write("    %s lin;\n" % do_lin_to_win[0])
-        else:
-            cpp.write("    %s lin;\n" % do_win_to_lin[0])
-        if not method.result_type.kind == TypeKind.VOID:
-            cpp.write("    %s _ret;\n" % method.result_type.spelling)
-
-    if do_wrap:
-        cpp.write("    %s *lin;\n" % do_wrap[0])
-        if not method.result_type.kind == TypeKind.VOID:
-            cpp.write("    %s _ret;\n" % method.result_type.spelling)
-
     cfile.write("    TRACE(\"%p\\n\", _this);\n")
 
-    if do_win_to_lin:
-        #XXX we should pass the struct size here
-        cpp.write("    if(%s)\n" % do_win_to_lin[1])
-        cpp.write("        struct_%s_%s_win_to_lin(%s, &lin);\n" % (strip_ns(do_win_to_lin[0]), display_sdkver(sdkver), do_win_to_lin[1]))
-
     if method.result_type.kind == TypeKind.VOID:
         cfile.write("    ")
-        cpp.write("    ")
     elif path_conv and (len(path_conv["l2w_names"]) > 0 or path_conv["return_is_size"]):
         cfile.write("    path_result = ")
-        cpp.write("    return ")
     elif returns_record:
         cfile.write("    *_r = ")
-        cpp.write("    return ")
-    elif do_lin_to_win or do_win_to_lin:
-        cfile.write("    return ")
-        cpp.write("    _ret = ")
-    elif do_wrap:
-        cfile.write("    return ")
-        cpp.write("    _ret = ")
     else:
         cfile.write("    return ")
-        cpp.write("    return ")
 
     should_gen_wrapper = strip_ns(method.result_type.spelling).startswith("IVR")
     if should_gen_wrapper:
@@ -612,61 +699,19 @@ def handle_method(used_name, cfile, classname, winclassname, cppname, method, cp
     else:
         cfile.write("%s_%s(_this->linux_side" % (cppname, used_name))
 
-    cpp.write("((%s*)linux_side)->%s(" % (classname, method.spelling))
     unnamed = 'a'
     first = True
-    next_is_size = False
-    next_is_size_no_conv = False
-    convert_size_param = ""
-    for param in get_params(method):
-        if not first:
-            cpp.write(", ")
-        else:
+    for param in method.get_arguments():
+        if first:
             first = False
         if param.spelling == "":
             cfile.write(", _%s" % unnamed)
-            cpp.write("(%s)_%s" % (param.type.spelling, unnamed))
             unnamed = chr(ord(unnamed) + 1)
         else:
-            if do_lin_to_win and do_lin_to_win[1] == param.spelling or \
-                    do_win_to_lin and do_win_to_lin[1] == param.spelling or \
-                    do_wrap and do_wrap[1] == param.spelling:
-                cfile.write(", %s" % param.spelling)
-                cpp.write("%s ? &lin : nullptr" % param.spelling)
-                if do_win_to_lin:
-                    assert(not do_win_to_lin[0] in STRUCTS_NEXT_IS_SIZE_UNHANDLED)
-                    if do_win_to_lin[0] in STRUCTS_NEXT_IS_SIZE:
-                        next_is_size = True
-            elif do_unwrap and do_unwrap[1] == param.spelling:
-                cfile.write(", %s" % param.spelling)
-                cpp.write("struct_%s_%s_unwrap(%s)" % (strip_ns(do_unwrap[0]), display_sdkver(sdkver), do_unwrap[1]))
-            elif path_conv and param.spelling in path_conv["w2l_names"]:
+            if path_conv and param.spelling in path_conv["w2l_names"]:
                 cfile.write(", %s ? lin_%s : NULL" % (param.spelling, param.spelling))
-                cpp.write("(%s)%s" % (param.type.spelling, param.spelling))
-            elif do_size_fixup and do_size_fixup[1] == param.spelling:
-                next_is_size = True
-                next_is_size_no_conv = True
-                cfile.write(", %s" % param.spelling)
-                cpp.write("(%s)%s" % (param.type.spelling, param.spelling))
-            elif next_is_size:
-                cfile.write(", %s" % param.spelling)
-                next_is_size = False
-                if next_is_size_no_conv and param.type.spelling == "uint32_t":
-                    cpp.write("std::min(%s, (uint32_t)sizeof(vr::%s))" % (param.spelling, do_size_fixup[0]))
-                    convert_size_param = ", " + param.spelling
-                elif param.type.spelling == "uint32_t":
-                    cpp.write("%s ? sizeof(lin) : 0" % param.spelling)
-                    convert_size_param = ", " + param.spelling
-                else:
-                    cpp.write("(%s)%s" % (param.type.spelling, param.spelling))
-                    convert_size_param = ", -1"
-                next_is_size_no_conv = False
-            elif "&" in param.type.spelling:
-                cfile.write(", %s" % param.spelling)
-                cpp.write("*%s" % param.spelling)
             else:
                 cfile.write(", %s" % param.spelling)
-                cpp.write("(%s)%s" % (param.type.spelling, param.spelling))
     if should_gen_wrapper:
         cfile.write(")")
     if is_method_overridden:
@@ -676,7 +721,6 @@ def handle_method(used_name, cfile, classname, winclassname, cppname, method, cp
                 cfile.write(", &_this->user_data")
                 break
     cfile.write(");\n")
-    cpp.write(");\n")
     if returns_record:
         cfile.write("    return _r;\n")
     if path_conv and len(path_conv["l2w_names"]) > 0:
@@ -691,20 +735,7 @@ def handle_method(used_name, cfile, classname, winclassname, cppname, method, cp
         for i in range(len(path_conv["w2l_names"])):
             if path_conv["w2l_arrays"][i]:
                 cfile.write("    vrclient_free_stringlist(lin_%s);\n" % path_conv["w2l_names"][i])
-    if do_lin_to_win:
-        if next_is_size and not convert_size_param:
-            convert_size_param = ", -1"
-        cpp.write("    if(%s)\n" % do_lin_to_win[1])
-        cpp.write("        struct_%s_%s_lin_to_win(&lin, %s%s);\n" % (strip_ns(do_lin_to_win[0]), display_sdkver(sdkver), do_lin_to_win[1], convert_size_param))
-    if do_lin_to_win or do_win_to_lin:
-        if not method.result_type.kind == TypeKind.VOID:
-            cpp.write("    return _ret;\n")
-    if do_wrap and not method.result_type.kind == TypeKind.VOID:
-            cpp.write("    if(_ret == 0)\n")
-            cpp.write("        *%s = struct_%s_%s_wrap(lin);\n" % (do_wrap[1], strip_ns(do_wrap[0]), display_sdkver(sdkver)))
-            cpp.write("    return _ret;\n")
     cfile.write("}\n\n")
-    cpp.write("}\n\n")
 
 
 max_c_api_param_count = 0
@@ -784,7 +815,8 @@ WINE_DEFAULT_DEBUG_CHANNEL(vrclient);
         if child.kind == CursorKind.CXX_METHOD:
             method_name = method_unique_name(child, method_names)
             handle_method_hpp(method_name, cppname, child, cpp_h)
-            handle_method(method_name, cfile, klass.spelling, winclassname, cppname, child, cpp, version)
+            handle_method_cpp(method_name, klass.spelling, cppname, child, cpp)
+            handle_method_c(method_name, klass.spelling, winclassname, cppname, child, version, cfile)
             methods.append(child)
 
     cfile.write("extern vtable_ptr %s_vtable;\n\n" % winclassname)