Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T> 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 <typename T>", actualResult);
Assert.Contains("struct std::hash<Platform::Ranges::Range<T>>", actualResult);

// Should NOT contain unsafe namespace std opening
Assert.DoesNotContain("namespace std\n{", actualResult);
Assert.DoesNotContain("namespace std {", actualResult);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -578,8 +578,8 @@ public class CSharpToCppTransformer : TextTransformer
(new Regex(@"(?<classDeclarationBegin>\r?\n(?<indent>[\t ]*)template <typename (?<typeParameter>[^\n]+)> (struct|class) (?<type>[a-zA-Z0-9]+<\k<typeParameter>>)(\s*:\s*[^{\n]+)?[\t ]*(\r?\n)?[\t ]*{)(?<middle>(.|\n)*)(?<endIndent>(?<=\r?\n)\k<indent>)(?<end>};)"), "${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>~T~*/ ... public: override std::int32_t GetHashCode() { return {Minimum, Maximum}.GetHashCode(); } ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/
// /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/ namespace std { template <typename T> struct hash<Platform::Ranges::Range<T>> { std::size_t operator()(const Platform::Ranges::Range<T> &obj) const { return {Minimum, Maximum}.GetHashCode(); } }; }
(new Regex(@"(?<namespaceScopeStart>/\*~start~namespace~(?<namespace>[^~\n\*]+)~\*/)(?<betweenStartScopes>(.|\n)+)(?<typeScopeStart>/\*~start~type~(?<type>[^~\n\*]+)~(?<typeParameter>[^~\n\*]+)~\*/)(?<before>(.|\n)+?)(?<hashMethodDeclaration>\r?\n[ \t]*(?<access>(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?<methodBody>[^\s][^\n]+[^\s])\s*}\s*)(?<after>(.|\n)+?)(?<typeScopeEnd>/\*~end~type~\k<type>~\k<typeParameter>~\*/)(?<betweenEndScopes>(.|\n)+)(?<namespaceScopeEnd>/\*~end~namespace~\k<namespace>~\*/)}\r?\n"), "${namespaceScopeStart}${betweenStartScopes}${typeScopeStart}${before}${after}${typeScopeEnd}${betweenEndScopes}${namespaceScopeEnd}}" + Environment.NewLine + Environment.NewLine + "namespace std" + Environment.NewLine + "{" + Environment.NewLine + " template <typename ${typeParameter}>" + 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>~T~*/ ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/ template <typename T> struct std::hash<Platform::Ranges::Range<T>> { std::size_t operator()(const Platform::Ranges::Range<T> &obj) const { return {Minimum, Maximum}.GetHashCode(); } };
(new Regex(@"(?<namespaceScopeStart>/\*~start~namespace~(?<namespace>[^~\n\*]+)~\*/)(?<betweenStartScopes>(.|\n)+)(?<typeScopeStart>/\*~start~type~(?<type>[^~\n\*]+)~(?<typeParameter>[^~\n\*]+)~\*/)(?<before>(.|\n)+?)(?<hashMethodDeclaration>\r?\n[ \t]*(?<access>(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?<methodBody>[^\s][^\n]+[^\s])\s*}\s*)(?<after>(.|\n)+?)(?<typeScopeEnd>/\*~end~type~\k<type>~\k<typeParameter>~\*/)(?<betweenEndScopes>(.|\n)+)(?<namespaceScopeEnd>/\*~end~namespace~\k<namespace>~\*/)}\r?\n"), "${namespaceScopeStart}${betweenStartScopes}${typeScopeStart}${before}${after}${typeScopeEnd}${betweenEndScopes}${namespaceScopeEnd}}" + Environment.NewLine + Environment.NewLine + "template <typename ${typeParameter}>" + 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~*/
Expand Down
13 changes: 13 additions & 0 deletions examples/test_hash_specialization.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Platform.Ranges
{
public struct Range<T>
{
public T Minimum;
public T Maximum;

public override int GetHashCode()
{
return {Minimum, Maximum}.GetHashCode();
}
}
}
43 changes: 43 additions & 0 deletions examples/test_program.cs
Original file line number Diff line number Diff line change
@@ -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<T>
{
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 <typename T>") && 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!");
}
}
}
13 changes: 13 additions & 0 deletions examples/test_transformation.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
namespace Platform.Ranges
{
public struct Range<T>
{
public T Minimum { get; set; }
public T Maximum { get; set; }

public override int GetHashCode()
{
return {Minimum, Maximum}.GetHashCode();
}
}
}
4 changes: 2 additions & 2 deletions python/cs2cpp/cs2cpp.py
Original file line number Diff line number Diff line change
Expand Up @@ -577,8 +577,8 @@ def __init__(
SubRule(r"(?P<classDeclarationBegin>\r?\n(?P<indent>[\t ]*)template <typename (?P<typeParameter>[^\n]+)> (struct|class) (?P<type>[a-zA-Z0-9]+<\k<typeParameter>>)(\s*:\s*[^{\n]+)?[\t ]*(\r?\n)?[\t ]*{)(?P<middle>(.|\n)*)(?P<endIndent>(?<=\r?\n)\k<indent>)(?P<end>};)", r"\g<classDeclarationBegin>/*~start~type~\g<type>~\g<typeParameter>~*/\g<middle>\g<endIndent>/*~end~type~\g<type>~\g<typeParameter>~*/\g<end>", max_repeat=0),
# Inside the scope replace:
# /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... public: override std::int32_t GetHashCode() { return {Minimum, Maximum}.GetHashCode(); } ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/
# /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/ namespace std { template <typename T> struct hash<Platform::Ranges::Range<T>> { std::size_t operator()(const Platform::Ranges::Range<T> &obj) const { return {Minimum, Maximum}.GetHashCode(); } }; }
SubRule(r"(?P<namespaceScopeStart>/\*~start~namespace~(?P<namespace>[^~\n\*]+)~\*/)(?P<betweenStartScopes>(.|\n)+)(?P<typeScopeStart>/\*~start~type~(?P<type>[^~\n\*]+)~(?P<typeParameter>[^~\n\*]+)~\*/)(?P<before>(.|\n)+?)(?P<hashMethodDeclaration>\r?\n[ \t]*(?P<access>(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?P<methodBody>[^\s][^\n]+[^\s])\s*}\s*)(?P<after>(.|\n)+?)(?P<typeScopeEnd>/\*~end~type~\k<type>~\k<typeParameter>~\*/)(?P<betweenEndScopes>(.|\n)+)(?P<namespaceScopeEnd>/\*~end~namespace~\k<namespace>~\*/)}\r?\n", r"\g<namespaceScopeStart>\g<betweenStartScopes>\g<typeScopeStart>\g<before>\g<after>\g<typeScopeEnd>\g<betweenEndScopes>\g<namespaceScopeEnd>}\n" + "\nnamespace std\n" + "{\n" + " template <typename \g<typeParameter>>\n" + " struct hash<\g<namespace>::\g<type>>\n" + " {\n" + " std::size_t operator()(const \g<namespace>::\g<type> &obj) const\n" + " {\n" + " /*~start~method~*/\g<methodBody>/*~end~method~*/\n" + " }\n" + " };\n" + "}\n", max_repeat=10),
# /*~start~namespace~Platform::Ranges~*/ ... /*~start~type~Range<T>~T~*/ ... /*~end~type~Range<T>~T~*/ ... /*~end~namespace~Platform::Ranges~*/ template <typename T> struct std::hash<Platform::Ranges::Range<T>> { std::size_t operator()(const Platform::Ranges::Range<T> &obj) const { return {Minimum, Maximum}.GetHashCode(); } };
SubRule(r"(?P<namespaceScopeStart>/\*~start~namespace~(?P<namespace>[^~\n\*]+)~\*/)(?P<betweenStartScopes>(.|\n)+)(?P<typeScopeStart>/\*~start~type~(?P<type>[^~\n\*]+)~(?P<typeParameter>[^~\n\*]+)~\*/)(?P<before>(.|\n)+?)(?P<hashMethodDeclaration>\r?\n[ \t]*(?P<access>(private|protected|public): )override std::int32_t GetHashCode\(\)(\s|\n)*{\s*(?P<methodBody>[^\s][^\n]+[^\s])\s*}\s*)(?P<after>(.|\n)+?)(?P<typeScopeEnd>/\*~end~type~\k<type>~\k<typeParameter>~\*/)(?P<betweenEndScopes>(.|\n)+)(?P<namespaceScopeEnd>/\*~end~namespace~\k<namespace>~\*/)}\r?\n", r"\g<namespaceScopeStart>\g<betweenStartScopes>\g<typeScopeStart>\g<before>\g<after>\g<typeScopeEnd>\g<betweenEndScopes>\g<namespaceScopeEnd>}\n" + "\ntemplate <typename \g<typeParameter>>\n" + "struct std::hash<\g<namespace>::\g<type>>\n" + "{\n" + " std::size_t operator()(const \g<namespace>::\g<type> &obj) const\n" + " {\n" + " /*~start~method~*/\g<methodBody>/*~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~*/
Expand Down
Loading