diff --git a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs index edca381..94dfac7 100644 --- a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs +++ b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp.Tests/CSharpToCppTransformerTests.cs @@ -35,5 +35,34 @@ public static void Main(string[] args) var actualResult = transformer.Transform(helloWorldCode); Assert.Equal(expectedResult, actualResult); } + + [Fact] + public void SafeHashSpecializationTest() + { + const string inputCode = @" +namespace Platform.Ranges +{ + template struct Range + { + T Minimum; + T Maximum; + + public: override std::int32_t GetHashCode() + { + return {Minimum, Maximum}.GetHashCode(); + } + }; +}"; + var transformer = new CSharpToCppTransformer(); + var actualResult = transformer.Transform(inputCode); + + // Should generate safe specialization syntax + Assert.Contains("template ", actualResult); + Assert.Contains("struct std::hash>", actualResult); + + // Should NOT contain unsafe namespace std opening + Assert.DoesNotContain("namespace std\n{", actualResult); + Assert.DoesNotContain("namespace std {", actualResult); + } } } diff --git a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs index 2f5dceb..a2b2c39 100644 --- a/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs +++ b/csharp/Platform.RegularExpressions.Transformer.CSharpToCpp/CSharpToCppTransformer.cs @@ -578,8 +578,8 @@ public class CSharpToCppTransformer : TextTransformer (new Regex(@"(?\r?\n(?[\t ]*)template [^\n]+)> (struct|class) (?[a-zA-Z0-9]+<\k>)(\s*:\s*[^{\n]+)?[\t ]*(\r?\n)?[\t ]*{)(?(.|\n)*)(?(?<=\r?\n)\k)(?};)"), "${classDeclarationBegin}/*~start~type~${type}~${typeParameter}~*/${middle}${endIndent}/*~end~type~${type}~${typeParameter}~*/${end}", 0), // Inside the scope replace: // /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range~T~*/ ... public: override std::int32_t GetHashCode() { return {Minimum, Maximum}.GetHashCode(); } ... /*~end~type~Range~T~*/ ... /*~end~namespace~Platform::Ranges~*/ - // /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range~T~*/ ... /*~end~type~Range~T~*/ ... /*~end~namespace~Platform::Ranges~*/ namespace std { template struct hash> { std::size_t operator()(const Platform::Ranges::Range &obj) const { return {Minimum, Maximum}.GetHashCode(); } }; } - (new Regex(@"(?/\*~start~namespace~(?[^~\n\*]+)~\*/)(?(.|\n)+)(?/\*~start~type~(?[^~\n\*]+)~(?[^~\n\*]+)~\*/)(?(.|\n)+?)(?\r?\n[ \t]*(?(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?[^\s][^\n]+[^\s])\s*}\s*)(?(.|\n)+?)(?/\*~end~type~\k~\k~\*/)(?(.|\n)+)(?/\*~end~namespace~\k~\*/)}\r?\n"), "${namespaceScopeStart}${betweenStartScopes}${typeScopeStart}${before}${after}${typeScopeEnd}${betweenEndScopes}${namespaceScopeEnd}}" + Environment.NewLine + Environment.NewLine + "namespace std" + Environment.NewLine + "{" + Environment.NewLine + " template " + Environment.NewLine + " struct hash<${namespace}::${type}>" + Environment.NewLine + " {" + Environment.NewLine + " std::size_t operator()(const ${namespace}::${type} &obj) const" + Environment.NewLine + " {" + Environment.NewLine + " /*~start~method~*/${methodBody}/*~end~method~*/" + Environment.NewLine + " }" + Environment.NewLine + " };" + Environment.NewLine + "}" + Environment.NewLine, 10), + // /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range~T~*/ ... /*~end~type~Range~T~*/ ... /*~end~namespace~Platform::Ranges~*/ template struct std::hash> { std::size_t operator()(const Platform::Ranges::Range &obj) const { return {Minimum, Maximum}.GetHashCode(); } }; + (new Regex(@"(?/\*~start~namespace~(?[^~\n\*]+)~\*/)(?(.|\n)+)(?/\*~start~type~(?[^~\n\*]+)~(?[^~\n\*]+)~\*/)(?(.|\n)+?)(?\r?\n[ \t]*(?(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?[^\s][^\n]+[^\s])\s*}\s*)(?(.|\n)+?)(?/\*~end~type~\k~\k~\*/)(?(.|\n)+)(?/\*~end~namespace~\k~\*/)}\r?\n"), "${namespaceScopeStart}${betweenStartScopes}${typeScopeStart}${before}${after}${typeScopeEnd}${betweenEndScopes}${namespaceScopeEnd}}" + Environment.NewLine + Environment.NewLine + "template " + Environment.NewLine + "struct std::hash<${namespace}::${type}>" + Environment.NewLine + "{" + Environment.NewLine + " std::size_t operator()(const ${namespace}::${type} &obj) const" + Environment.NewLine + " {" + Environment.NewLine + " /*~start~method~*/${methodBody}/*~end~method~*/" + Environment.NewLine + " }" + Environment.NewLine + "};" + Environment.NewLine, 10), // Inside scope of /*~start~method~*/ replace: // /*~start~method~*/ ... Minimum ... /*~end~method~*/ // /*~start~method~*/ ... obj.Minimum ... /*~end~method~*/ diff --git a/examples/test_hash_specialization.cs b/examples/test_hash_specialization.cs new file mode 100644 index 0000000..0c610d2 --- /dev/null +++ b/examples/test_hash_specialization.cs @@ -0,0 +1,13 @@ +namespace Platform.Ranges +{ + public struct Range + { + public T Minimum; + public T Maximum; + + public override int GetHashCode() + { + return {Minimum, Maximum}.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/examples/test_program.cs b/examples/test_program.cs new file mode 100644 index 0000000..11e8629 --- /dev/null +++ b/examples/test_program.cs @@ -0,0 +1,43 @@ +using System; +using Platform.RegularExpressions.Transformer.CSharpToCpp; + +class Program +{ + static void Main() + { + var transformer = new CSharpToCppTransformer(); + + string input = @" +namespace Platform.Ranges +{ + public struct Range + { + public T Minimum; + public T Maximum; + + public override int GetHashCode() + { + return {Minimum, Maximum}.GetHashCode(); + } + } +}"; + + string result = transformer.Transform(input); + Console.WriteLine("===== TRANSFORMED OUTPUT ====="); + Console.WriteLine(result); + + // Check if we have the new safe specialization syntax + if (result.Contains("template ") && result.Contains("struct std::hash<")) + { + Console.WriteLine("\nāœ… SUCCESS: Safe specialization pattern detected!"); + if (!result.Contains("namespace std\n{")) + { + Console.WriteLine("āœ… SUCCESS: No unsafe namespace std usage detected!"); + } + } + else + { + Console.WriteLine("\nāŒ FAILURE: Safe specialization pattern not found!"); + } + } +} \ No newline at end of file diff --git a/examples/test_transformation.cs b/examples/test_transformation.cs new file mode 100644 index 0000000..0186434 --- /dev/null +++ b/examples/test_transformation.cs @@ -0,0 +1,13 @@ +namespace Platform.Ranges +{ + public struct Range + { + public T Minimum { get; set; } + public T Maximum { get; set; } + + public override int GetHashCode() + { + return {Minimum, Maximum}.GetHashCode(); + } + } +} \ No newline at end of file diff --git a/python/cs2cpp/cs2cpp.py b/python/cs2cpp/cs2cpp.py index 44ab7bb..64a4466 100644 --- a/python/cs2cpp/cs2cpp.py +++ b/python/cs2cpp/cs2cpp.py @@ -577,8 +577,8 @@ def __init__( SubRule(r"(?P\r?\n(?P[\t ]*)template [^\n]+)> (struct|class) (?P[a-zA-Z0-9]+<\k>)(\s*:\s*[^{\n]+)?[\t ]*(\r?\n)?[\t ]*{)(?P(.|\n)*)(?P(?<=\r?\n)\k)(?P};)", r"\g/*~start~type~\g~\g~*/\g\g/*~end~type~\g~\g~*/\g", max_repeat=0), # Inside the scope replace: # /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range~T~*/ ... public: override std::int32_t GetHashCode() { return {Minimum, Maximum}.GetHashCode(); } ... /*~end~type~Range~T~*/ ... /*~end~namespace~Platform::Ranges~*/ - # /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range~T~*/ ... /*~end~type~Range~T~*/ ... /*~end~namespace~Platform::Ranges~*/ namespace std { template struct hash> { std::size_t operator()(const Platform::Ranges::Range &obj) const { return {Minimum, Maximum}.GetHashCode(); } }; } - SubRule(r"(?P/\*~start~namespace~(?P[^~\n\*]+)~\*/)(?P(.|\n)+)(?P/\*~start~type~(?P[^~\n\*]+)~(?P[^~\n\*]+)~\*/)(?P(.|\n)+?)(?P\r?\n[ \t]*(?P(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?P[^\s][^\n]+[^\s])\s*}\s*)(?P(.|\n)+?)(?P/\*~end~type~\k~\k~\*/)(?P(.|\n)+)(?P/\*~end~namespace~\k~\*/)}\r?\n", r"\g\g\g\g\g\g\g\g}\n" + "\nnamespace std\n" + "{\n" + " template >\n" + " struct hash<\g::\g>\n" + " {\n" + " std::size_t operator()(const \g::\g &obj) const\n" + " {\n" + " /*~start~method~*/\g/*~end~method~*/\n" + " }\n" + " };\n" + "}\n", max_repeat=10), + # /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range~T~*/ ... /*~end~type~Range~T~*/ ... /*~end~namespace~Platform::Ranges~*/ template struct std::hash> { std::size_t operator()(const Platform::Ranges::Range &obj) const { return {Minimum, Maximum}.GetHashCode(); } }; + SubRule(r"(?P/\*~start~namespace~(?P[^~\n\*]+)~\*/)(?P(.|\n)+)(?P/\*~start~type~(?P[^~\n\*]+)~(?P[^~\n\*]+)~\*/)(?P(.|\n)+?)(?P\r?\n[ \t]*(?P(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?P[^\s][^\n]+[^\s])\s*}\s*)(?P(.|\n)+?)(?P/\*~end~type~\k~\k~\*/)(?P(.|\n)+)(?P/\*~end~namespace~\k~\*/)}\r?\n", r"\g\g\g\g\g\g\g\g}\n" + "\ntemplate >\n" + "struct std::hash<\g::\g>\n" + "{\n" + " std::size_t operator()(const \g::\g &obj) const\n" + " {\n" + " /*~start~method~*/\g/*~end~method~*/\n" + " }\n" + "};\n", max_repeat=10), # Inside scope of /*~start~method~*/ replace: # /*~start~method~*/ ... Minimum ... /*~end~method~*/ # /*~start~method~*/ ... obj.Minimum ... /*~end~method~*/