[mapguide-commits] r10197 - branches/4.0/MgDev/Bindings/src/IMake

svn_mapguide at osgeo.org svn_mapguide at osgeo.org
Sun Sep 28 08:44:55 PDT 2025


Author: jng
Date: 2025-09-28 08:44:55 -0700 (Sun, 28 Sep 2025)
New Revision: 10197

Modified:
   branches/4.0/MgDev/Bindings/src/IMake/IMake.cpp
Log:
IMake update:
 - When linkifying Mg class names, if we're linkifying an exception and it is not MgException, transform to MgException with MgExceptionCodes.the_name_of_specific_exception
 - Transplant getter method documentation to any .net properties
 - Fix truncated exception descriptions due to not following until end of comments or next directive.
 - Insert pragmas to generated .net constants file to suppress certain distracting warnings.
 - Fix vector overshoot when trying to process trailing trivia.
 - Add stub to make testing/debugging future problems easier.

Modified: branches/4.0/MgDev/Bindings/src/IMake/IMake.cpp
===================================================================
--- branches/4.0/MgDev/Bindings/src/IMake/IMake.cpp	2025-09-28 15:39:32 UTC (rev 10196)
+++ branches/4.0/MgDev/Bindings/src/IMake/IMake.cpp	2025-09-28 15:44:55 UTC (rev 10197)
@@ -14,7 +14,7 @@
     java
 };
 
-static char version[] = "1.6.2";
+static char version[] = "1.6.3";
 static char EXTERNAL_API_DOCUMENTATION[] = "(NOTE: This API is not officially supported and may be subject to removal in a future release without warning. Use with caution.)";
 
 static string module;
@@ -607,6 +607,29 @@
     stringReplace(str, ">", ">");
 }
 
+bool startsWith(const std::string& str, const std::string& prefix)
+{
+    if (prefix.length() > str.length()) {
+        return false;
+    }
+    return str.compare(0, prefix.length(), prefix) == 0;
+}
+
+bool endsWith(const std::string& str, const std::string& suffix)
+{
+    // Handle empty suffix
+    if (suffix.empty()) {
+        return true; // Empty string is a suffix of any string
+    }
+
+    // Handle suffix longer than string
+    if (suffix.length() > str.length()) {
+        return false;
+    }
+
+    return str.compare(str.length() - suffix.length(), suffix.length(), suffix) == 0;
+}
+
 string linkifyCSharpDocFragment(const string& str)
 {
     // Explode the fragment into a space delimited list.
@@ -671,11 +694,26 @@
                 suffix += elems[i][j];
             }
             output.append(prefix);
-            output.append("<see cref=\"");
-            output.append(nspace);
-            output.append(".");
-            output.append(mgClassName);
-            output.append("\" />");
+            
+            if (startsWith(mgClassName, "Mg") && endsWith(mgClassName, "Exception") && mgClassName != "MgException")
+            {
+                output.append("<see cref=\"");
+                output.append(nspace);
+                output.append(".MgException");
+                output.append("\" /> with code <see cref=\"");
+                output.append(nspace);
+                output.append("MgExceptionCodes.");
+                output.append(mgClassName);
+                output.append("\" />");
+            }
+            else
+            {
+                output.append("<see cref=\"");
+                output.append(nspace);
+                output.append(".");
+                output.append(mgClassName);
+                output.append("\" />");
+            }
             output.append(suffix);
         } else {
             output.append(elems[i]);
@@ -947,7 +985,7 @@
     return javaDoc;
 }
 
-string doxygenToCsharpDoc(const string& commentStr, bool isPublished)
+string doxygenToCsharpDoc(const string& commentStr, bool isPublished, bool onlyBrief)
 {
     //See doxygenToJavaDoc for how we do this sorcery
 
@@ -995,7 +1033,6 @@
                     descriptionParts.push_back(token);
                 i++;
             }
-            
             continue;
         }
         else if (elems[i].find("\\param") != std::string::npos) {
@@ -1039,8 +1076,22 @@
         }
         else if (elems[i].find("\\exception") != std::string::npos) {
             std::string except = elems[i].substr(elems[i].find("\\exception") + 10);
+            i++;
+            //Keep going until we find the next doxygen directive or end of comments
+            while (i < elems.size() && elems[i].find("\\") == std::string::npos) {
+                if (elems[i].find("<!-- Syntax in .Net, Java, and PHP -->") != std::string::npos ||
+                    elems[i].find("<!-- Example (PHP) -->") != std::string::npos ||
+                    elems[i].find("<!-- Example (Java) -->") != std::string::npos ||
+                    elems[i].find("<!-- Example (C#) -->") != std::string::npos) {
+                    i++;
+                    continue;
+                }
+                std::string token = elems[i].substr(3);
+                if (!token.empty())
+                    except += token;
+                i++;
+            }
             exceptionParts.push_back(except);
-            i++;
             continue;
         }
         i++;
@@ -1048,8 +1099,8 @@
 
     // ---------------------- csharpDoc START ------------------------ //
     std::string csharpDoc = "\n///<summary>\n";
-
-    if (descriptionParts.size() > 0) {
+    if (onlyBrief)
+    {
         if (!isPublished) {
             csharpDoc.append("/// ");
             csharpDoc.append(EXTERNAL_API_DOCUMENTATION);
@@ -1057,105 +1108,136 @@
         }
         for (size_t i = 0; i < descriptionParts.size(); i++) {
             csharpDoc.append("///");
-            csharpDoc.append(linkifyCSharpDocFragment(descriptionParts[i]));    
+            csharpDoc.append(linkifyCSharpDocFragment(descriptionParts[i]));
             csharpDoc.append("\n");
         }
         csharpDoc.append("///</summary>\n");
-    } else {
-        if (!isPublished) {
-            csharpDoc.append("/// ");
-            csharpDoc.append(EXTERNAL_API_DOCUMENTATION);
-            csharpDoc.append("\n");
-        } else {
-            csharpDoc.append("///TODO: API Documentation is missing or failed to translate doxygen brief directive (message inserted by IMake.exe)\n");
+    }
+    else
+    {
+        if (descriptionParts.size() > 0) {
+            if (!isPublished) {
+                csharpDoc.append("/// ");
+                csharpDoc.append(EXTERNAL_API_DOCUMENTATION);
+                csharpDoc.append("\n");
+            }
+            for (size_t i = 0; i < descriptionParts.size(); i++) {
+                csharpDoc.append("///");
+                csharpDoc.append(linkifyCSharpDocFragment(descriptionParts[i]));
+                csharpDoc.append("\n");
+            }
+            csharpDoc.append("///</summary>\n");
         }
-        csharpDoc.append("///</summary>\n");
-    }
+        else {
+            if (!isPublished) {
+                csharpDoc.append("/// ");
+                csharpDoc.append(EXTERNAL_API_DOCUMENTATION);
+                csharpDoc.append("\n");
+            }
+            else {
+                csharpDoc.append("///TODO: API Documentation is missing or failed to translate doxygen brief directive (message inserted by IMake.exe)\n");
+            }
+            csharpDoc.append("///</summary>\n");
+        }
 
-    if (paramParts.size() > 0) {
-        for (size_t i = 0; i < paramParts.size(); i++) {
-            std::string paramPart = paramParts[i];
-            stripHtml(paramPart);
-            xmlEscapeString(paramPart);
+        if (paramParts.size() > 0) {
+            for (size_t i = 0; i < paramParts.size(); i++) {
+                std::string paramPart = paramParts[i];
+                stripHtml(paramPart);
+                xmlEscapeString(paramPart);
 
-            std::vector<std::string> pelems;
-            std::stringstream pss(linkifyCSharpDocFragment(paramPart));
-            std::string pitem;
-            while(std::getline(pss, pitem, ' ')) {
-                if (!pitem.empty())
-                    pelems.push_back(pitem);
-            }
-    
-            if (pelems.size() > 1) { //Should be
-                csharpDoc.append("///<param name=\"");
-                csharpDoc.append(pelems[0]);
-                csharpDoc.append("\">");
-                csharpDoc.append("\n///");
-                for (size_t i = 1; i < pelems.size(); i++) {
-                    csharpDoc.append(" ");
-                    csharpDoc.append(pelems[i]);
+                std::vector<std::string> pelems;
+                std::stringstream pss(linkifyCSharpDocFragment(paramPart));
+                std::string pitem;
+                while (std::getline(pss, pitem, ' ')) {
+                    if (!pitem.empty())
+                        pelems.push_back(pitem);
                 }
-                csharpDoc.append("\n///</param>\n");
+
+                if (pelems.size() > 1) { //Should be
+                    csharpDoc.append("///<param name=\"");
+                    csharpDoc.append(pelems[0]);
+                    csharpDoc.append("\">");
+                    csharpDoc.append("\n///");
+                    for (size_t i = 1; i < pelems.size(); i++) {
+                        csharpDoc.append(" ");
+                        csharpDoc.append(pelems[i]);
+                    }
+                    csharpDoc.append("\n///</param>\n");
+                }
             }
         }
-    }
 
-    if (returnParts.size() > 0) {
-        csharpDoc.append("///<returns>");
-        for (size_t i = 0; i < returnParts.size(); i++) {
-            string retPart = returnParts[i];
-            stripHtml(retPart);
-            csharpDoc.append(linkifyCSharpDocFragment(retPart));
-            if (i < returnParts.size() - 1)
-                csharpDoc.append("\n/// ");
+        if (returnParts.size() > 0) {
+            csharpDoc.append("///<returns>");
+            for (size_t i = 0; i < returnParts.size(); i++) {
+                string retPart = returnParts[i];
+                stripHtml(retPart);
+                csharpDoc.append(linkifyCSharpDocFragment(retPart));
+                if (i < returnParts.size() - 1)
+                    csharpDoc.append("\n/// ");
+            }
+            csharpDoc.append("\n///</returns>\n");
         }
-        csharpDoc.append("\n///</returns>\n");
-    }
 
-    if (exceptionParts.size() > 0) {
-        for (size_t i = 0; i < exceptionParts.size(); i++) {
+        if (exceptionParts.size() > 0) {
+            for (size_t i = 0; i < exceptionParts.size(); i++) {
 
-            std::vector<std::string> eelems;
-            std::stringstream ess(exceptionParts[i]);
-            std::string eitem;
-            while(std::getline(ess, eitem, ' ')) {
-                if (!eitem.empty())
-                    eelems.push_back(eitem);
-            }
+                std::vector<std::string> eelems;
+                std::stringstream ess(exceptionParts[i]);
+                std::string eitem;
+                while (std::getline(ess, eitem, ' ')) {
+                    if (!eitem.empty())
+                        eelems.push_back(eitem);
+                }
 
-            if (eelems.size() > 0)
-            {
-                //Skip anything that is not of the form:
-                //\exception MgExceptionType Description of cases when the exception is thrown
-                //
-                //So the first token must start with "Mg"
-                std::string t("Mg");
-                if (eelems[0].compare(0, t.length(), t) == 0)
+                if (eelems.size() > 0)
                 {
-                    csharpDoc.append("///<exception cref=\"");
-                    csharpDoc.append(nspace);
-                    csharpDoc.append(".MgException\">");
-                    if (eelems.size() > 1) {
-                        csharpDoc.append("with code (<see cref=\"");
-                        csharpDoc.append(nspace);
-                        csharpDoc.append(".MgExceptionCodes.");
-                        csharpDoc.append(eelems[0]);
-                        csharpDoc.append("\" />) ");
-                        for (size_t j = 1; j < eelems.size(); j++) {
-                            csharpDoc.append(" ");
-                            csharpDoc.append(eelems[j]);
+                    //Skip anything that is not of the form:
+                    //\exception MgExceptionType Description of cases when the exception is thrown
+                    //
+                    //So the first token must start with "Mg"
+                    std::string t("Mg");
+                    if (eelems[0].compare(0, t.length(), t) == 0)
+                    {
+                        if (eelems[0] == "MgException")
+                        {
+                            csharpDoc.append("///<exception cref=\"");
+                            csharpDoc.append(nspace);
+                            csharpDoc.append(".MgException\">");
+                            for (size_t j = 1; j < eelems.size(); j++) {
+                                csharpDoc.append(" ");
+                                csharpDoc.append(eelems[j]);
+                            }
+                            csharpDoc.append("</exception>\n");
                         }
-                        csharpDoc.append("</exception>\n");
+                        else
+                        {
+                            csharpDoc.append("///<exception cref=\"");
+                            csharpDoc.append(nspace);
+                            csharpDoc.append(".MgException\">");
+                            if (eelems.size() > 1) {
+                                csharpDoc.append("with code (<see cref=\"");
+                                csharpDoc.append(nspace);
+                                csharpDoc.append(".MgExceptionCodes.");
+                                csharpDoc.append(eelems[0]);
+                                csharpDoc.append("\" />) ");
+                                for (size_t j = 1; j < eelems.size(); j++) {
+                                    csharpDoc.append(" ");
+                                    csharpDoc.append(eelems[j]);
+                                }
+                                csharpDoc.append("</exception>\n");
+                            }
+                            else {
+                                csharpDoc.append(eelems[0]);
+                                csharpDoc.append("\"></exception>\n");
+                            }
+                        }
                     }
-                    else {
-                        csharpDoc.append(eelems[0]);
-                        csharpDoc.append("\"></exception>\n");
-                    }
                 }
             }
         }
     }
-
     // ---------------------- csharpDoc END ------------------------ //
     //csharpDoc.append("///\n");
     if (isDeprecated)
@@ -1177,7 +1259,7 @@
         convertedDoc = doxygenToJavaDoc(commentStr, true); //EXTERNAL_API only applies to class members, so treat this fragment as PUBLISHED_API
         fprintf(docOutFile, "\n%%typemap(javaclassmodifiers) %s %%{%s public %s%%}\n", className.c_str(), convertedDoc.c_str(), classKeyword.c_str());
     } else if(language == csharp) {
-        convertedDoc = doxygenToCsharpDoc(commentStr, true); //EXTERNAL_API only applies to class members, so treat this fragment as PUBLISHED_API
+        convertedDoc = doxygenToCsharpDoc(commentStr, true, false); //EXTERNAL_API only applies to class members, so treat this fragment as PUBLISHED_API
         fprintf(docOutFile, "\n%%typemap(csclassmodifiers) %s %%{%s public partial %s%%}\n", className.c_str(), convertedDoc.c_str(), classKeyword.c_str());
     }
 }
@@ -1221,6 +1303,9 @@
             bool bPastLastParen = false;
             while(j < elems.size()) {
                 j++;
+                if (j >= elems.size())
+                    break;
+
                 if (bPastLastParen)
                 {
                     // We're not appending to methodName at this point. We are only
@@ -1265,7 +1350,7 @@
         convertedDoc = doxygenToJavaDoc(commentStr, isPublished);
         fprintf(docOutFile, "\n%%javamethodmodifiers %s %%{%s public%%}\n", swigMethodDecl.c_str(), convertedDoc.c_str());
     } else if(language == csharp) {
-        convertedDoc = doxygenToCsharpDoc(commentStr, isPublished);
+        convertedDoc = doxygenToCsharpDoc(commentStr, isPublished, false);
         fprintf(docOutFile, "\n%%csmethodmodifiers %s %%{%s public%%}\n", swigMethodDecl.c_str(), convertedDoc.c_str());
     }
 }
@@ -1384,7 +1469,7 @@
                         convertedDoc = doxygenToJavaDoc(commentStr, isPublished);
                         fprintf(outfile, "%s\n   ", convertedDoc.c_str());
                     } else if (language == csharp) {
-                        convertedDoc = doxygenToCsharpDoc(commentStr, isPublished);
+                        convertedDoc = doxygenToCsharpDoc(commentStr, isPublished, false);
                         fprintf(outfile, "%s\n   ", convertedDoc.c_str());
                     }
                     commentStr.clear();
@@ -1559,6 +1644,16 @@
 
                         if (bLegacyDotNetPropGeneration)
                         {
+                            // NOTE: __set if specified is generally specified alongside the __get which
+                            // is normally applied on the *getter* method. What this means is that the property
+                            // doc (which may be both get/set) will assume the commentary of the getter, which
+                            // is undesirable, but is still a net positive over zero commentary!
+                            if (!commentStr.empty())
+                            {
+                                auto csDoc = doxygenToCsharpDoc(commentStr, true, true);
+                                fprintf(propertyFile, "%s\n", csDoc.c_str());
+                            }
+
                             fprintf(propertyFile, "public %s%s %s\n{\n",
                                 inherited ? "new " : "",
                                 propType.c_str(), propName.c_str());
@@ -1755,7 +1850,7 @@
                         convertedDoc = doxygenToJavaDoc(commentStr, true);
                         fprintf(outfile, "%s", convertedDoc.c_str());
                     } else if (language == csharp) {
-                        convertedDoc = doxygenToCsharpDoc(commentStr, true);
+                        convertedDoc = doxygenToCsharpDoc(commentStr, true, false);
                         fprintf(outfile, "%s", convertedDoc.c_str());
                     }
                 }
@@ -1958,8 +2053,15 @@
     {
         if(nameSpace != "")
         {
-            if(language == csharp)
+            if (language == csharp)
+            {
+                fprintf(outfile, "// Generated by IMake. DO NOT MODIFY\n");
+                // There will be /// fragments emitted in places not in expected comment sections
+                fprintf(outfile, "#pragma warning disable CS1587\n");
+                // We may link to classes that exist in a monolithic context, but not in a split context
+                fprintf(outfile, "#pragma warning disable CS1574\n");
                 fprintf(outfile, "namespace %s {\n\n", nameSpace.c_str());
+            }
         }
     }
 
@@ -2021,8 +2123,26 @@
     exit(1);
 }
 
+void testFragmentConversion();
+
 int main(int argc, char** argv)
 {
+    // Uncomment to test/debug specific headers/files
+    /*
+    translateMode = false; // true for constants, false for everything else
+    absPaths = true;
+    language = csharp;
+    typeReplacements["STRING"] = "string";
+    classes["MgResourcePermission"] = true;
+    outfile = fopen("C:\\Workspace\\mg-4.0\\Constants.cs", "w");
+    docOutFile = fopen("C:\\Workspace\\mg-4.0\\doc.i", "w");
+    processHeaderFile("C:\\Workspace\\mg-4.0\\MgDev\\Common\\Geometry\\Coordinate.h", ".");
+    fclose(outfile);
+    fclose(docOutFile);
+    //testFragmentConversion();
+    return 0;
+    */
+
     printf("\nIMake - SWIG Interface generator");
     printf("\nVersion %s\n\n", version);
 
@@ -2182,3 +2302,28 @@
     }
     return 0;
 }
+
+void testFragmentConversion()
+{
+    std::string commentStr = R"(///////////////////////////////////////////////////////////////////////////////////////////////
+/// \brief
+/// Gets the grid scale of the coordinate system at the specified
+/// longitude/latitude point.
+/// Throws an exception MgCoordinateSystemNotReadyException if the
+/// coordinate system has not been successfully initialized;
+/// InvalidArgument of the specified coordinate is not
+/// mathematically valid.
+///
+/// \param dLongitude (double)
+/// The longitude coordinate
+/// \param dLatitude (double)
+/// The latitude coordinate
+///
+/// \return
+/// The grid scale
+///)";
+    auto csharpXml = doxygenToCsharpDoc(commentStr, true, false);
+    auto csharpXml2 = doxygenToCsharpDoc(commentStr, true, true);
+
+    auto javaDoc = doxygenToJavaDoc(commentStr, true);
+}
\ No newline at end of file



More information about the mapguide-commits mailing list