Skip to content

Commit 2978ae8

Browse files
author
machibuse
committed
Fist test with lists
1 parent 897a1af commit 2978ae8

5 files changed

Lines changed: 178 additions & 27 deletions

File tree

Source/.idea/.idea.Porticle.Grpc/.idea/vcs.xml

Lines changed: 6 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,50 @@
1+
using Microsoft.CodeAnalysis;
2+
using Microsoft.CodeAnalysis.CSharp;
3+
using Microsoft.CodeAnalysis.CSharp.Syntax;
4+
5+
namespace Porticle.Grpc.GuidMapper;
6+
7+
public class ClassVisitor : CSharpSyntaxRewriter
8+
{
9+
public override SyntaxNode? VisitClassDeclaration(ClassDeclarationSyntax node)
10+
{
11+
Console.WriteLine("Visit Class "+node.Identifier.ValueText);
12+
var marker = "[Porticle.Grpc.GuidMapper]";
13+
14+
// Skip if marker exists
15+
if (node.GetLeadingTrivia().ToFullString().Contains(marker))
16+
{
17+
Console.WriteLine("Class Already Patched");
18+
return node;
19+
}
20+
21+
// Add marker
22+
var trivia = SyntaxFactory.TriviaList(SyntaxFactory.Comment("/// <remark>" + marker + "</remark>"), SyntaxFactory.LineFeed).AddRange(node.GetLeadingTrivia());
23+
node = node.WithLeadingTrivia(trivia);
24+
25+
var propertyVisitor = new PropertyVisitor();
26+
node = (ClassDeclarationSyntax)propertyVisitor.Visit(node);
27+
28+
node = node.AddMembers(ClassFromSource(ListWrappers.RepeatedFieldGuidWrapper));
29+
node = node.AddMembers(ClassFromSource(ListWrappers.RepeatedFieldNullableGuidWrapper));
30+
node = node.AddMembers(ClassFromSource(ListWrappers.RepeatedFieldNullableStringWrapper));
31+
32+
Console.WriteLine("Visit Methods for "+propertyVisitor.ReplaceProps.Count+" props");
33+
var methodVisitor = new MethodVisitor(propertyVisitor.ReplaceProps);
34+
node = (ClassDeclarationSyntax)methodVisitor.Visit(node);
35+
36+
return node;
37+
}
38+
39+
private static ClassDeclarationSyntax ClassFromSource(string classCode)
40+
{
41+
var syntaxTree = CSharpSyntaxTree.ParseText(classCode);
42+
var root = syntaxTree.GetRoot();
43+
var nestedClass = root.DescendantNodes()
44+
.OfType<ClassDeclarationSyntax>()
45+
.Single();
46+
return nestedClass
47+
.WithLeadingTrivia(SyntaxFactory.CarriageReturnLineFeed)
48+
.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed);
49+
}
50+
}
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
namespace Porticle.Grpc.GuidMapper;
2+
3+
public static class ListWrappers
4+
{
5+
public static string RepeatedFieldGuidWrapper = "class RepeatedFieldGuidWrapper : System.Collections.Generic.IList<System.Guid>\n{\n private readonly Google.Protobuf.Collections.RepeatedField<string> _internList;\n\n public RepeatedFieldGuidWrapper(Google.Protobuf.Collections.RepeatedField<string> internList)\n {\n this._internList = internList;\n }\n\n public System.Collections.Generic.IEnumerator<System.Guid> GetEnumerator()\n {\n using var enumerator = _internList.GetEnumerator();\n while (enumerator.MoveNext())\n {\n yield return System.Guid.Parse(enumerator.Current);\n }\n }\n\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n {\n return GetEnumerator();\n }\n\n public void Add(System.Guid item)\n {\n _internList.Add(item.ToString(\"D\"));\n }\n\n public void Clear()\n {\n _internList.Clear();\n }\n\n public bool Contains(System.Guid item)\n {\n return _internList.Contains(item.ToString(\"D\"));\n }\n\n public void CopyTo(System.Guid[] array, int arrayIndex)\n {\n System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Select(_internList, System.Guid.Parse)).CopyTo(array, arrayIndex);\n }\n\n public bool Remove(System.Guid item)\n {\n return _internList.Remove(item.ToString(\"D\"));\n }\n\n public int Count => _internList.Count;\n \n public bool IsReadOnly => _internList.IsReadOnly;\n \n public int IndexOf(System.Guid item)\n {\n return _internList.IndexOf(item.ToString(\"D\"));\n }\n\n public void Insert(int index, System.Guid item)\n {\n _internList.Insert(index, item.ToString(\"D\"));\n }\n\n public void RemoveAt(int index)\n {\n _internList.RemoveAt(index);\n }\n\n public System.Guid this[int index]\n {\n get => System.Guid.Parse(_internList[index]);\n set => _internList[index] = value.ToString(\"D\");\n }\n}";
6+
public static string RepeatedFieldNullableGuidWrapper = "class RepeatedFieldNullableGuidWrapper : System.Collections.Generic.IList<System.Guid?>\n{\n private readonly Google.Protobuf.Collections.RepeatedField<string> _internList;\n\n public RepeatedFieldNullableGuidWrapper(Google.Protobuf.Collections.RepeatedField<string> internList)\n {\n this._internList = internList;\n }\n\n public System.Collections.Generic.IEnumerator<System.Guid?> GetEnumerator()\n {\n using var enumerator = _internList.GetEnumerator();\n while (enumerator.MoveNext())\n {\n yield return string.IsNullOrWhiteSpace(enumerator.Current) ? null : System.Guid.Parse(enumerator.Current);\n }\n }\n\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n {\n return GetEnumerator();\n }\n\n public void Add(System.Guid? item)\n {\n _internList.Add(item?.ToString(\"D\")!);\n }\n\n public void Clear()\n {\n _internList.Clear();\n }\n\n public bool Contains(System.Guid? item)\n {\n return _internList.Contains(item?.ToString(\"D\")!);\n }\n\n public void CopyTo(System.Guid?[] array, int arrayIndex)\n {\n System.Linq.Enumerable.ToArray(System.Linq.Enumerable.Select(_internList, s => string.IsNullOrWhiteSpace(s) ? null : (System.Guid?)System.Guid.Parse(s!))).CopyTo(array, arrayIndex);\n }\n\n public bool Remove(System.Guid? item)\n {\n return _internList.Remove(item?.ToString(\"D\")!);\n }\n\n public int Count => _internList.Count;\n \n public bool IsReadOnly => _internList.IsReadOnly;\n \n public int IndexOf(System.Guid? item)\n {\n return _internList.IndexOf(item?.ToString(\"D\")!);\n }\n\n public void Insert(int index, System.Guid? item)\n {\n _internList.Insert(index, item?.ToString(\"D\")!);\n }\n\n public void RemoveAt(int index)\n {\n _internList.RemoveAt(index);\n }\n\n public System.Guid? this[int index]\n {\n get => string.IsNullOrWhiteSpace(_internList[index])?null : System.Guid.Parse(_internList[index]);\n set => _internList[index] = value?.ToString(\"D\")!;\n }\n}";
7+
public static string RepeatedFieldNullableStringWrapper = "class RepeatedFieldNullableStringWrapper : System.Collections.Generic.IList<string?>\n{\n private readonly Google.Protobuf.Collections.RepeatedField<string> _internList;\n\n public RepeatedFieldNullableStringWrapper(Google.Protobuf.Collections.RepeatedField<string> internList)\n {\n this._internList = internList;\n }\n\n public System.Collections.Generic.IEnumerator<string?> GetEnumerator()\n {\n using var enumerator = _internList.GetEnumerator();\n while (enumerator.MoveNext())\n {\n yield return enumerator.Current;\n }\n }\n\n System.Collections.IEnumerator System.Collections.IEnumerable.GetEnumerator()\n {\n return GetEnumerator();\n }\n\n public void Add(string? item)\n {\n _internList.Add(item!);\n }\n\n public void Clear()\n {\n _internList.Clear();\n }\n\n public bool Contains(string? item)\n {\n return _internList.Contains(item!);\n }\n\n public void CopyTo(string?[] array, int arrayIndex)\n {\n System.Linq.Enumerable.ToArray(_internList).CopyTo(array, arrayIndex);\n }\n\n public bool Remove(string? item)\n {\n return _internList.Remove(item!);\n }\n\n public int Count => _internList.Count;\n \n public bool IsReadOnly => _internList.IsReadOnly;\n \n public int IndexOf(string? item)\n {\n return _internList.IndexOf(item!);\n }\n\n public void Insert(int index, string? item)\n {\n _internList.Insert(index, item!);\n }\n\n public void RemoveAt(int index)\n {\n _internList.RemoveAt(index);\n }\n\n public string? this[int index]\n {\n get => _internList[index];\n set => _internList[index] = value!;\n }\n}";
8+
}

Source/Porticle.Grpc.GuidMapper/Porticle.Grpc.GuidMapper.csproj

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
<PackageReleaseNotes>First test version</PackageReleaseNotes>
1717
<IncludeBuildOutput>false</IncludeBuildOutput>
1818
<DevelopmentDependency>true</DevelopmentDependency>
19-
<Version>1.0.13</Version>
19+
<Version>1.0.25</Version>
2020
<SuppressDependenciesWhenPacking>true</SuppressDependenciesWhenPacking>
2121
<TargetFrameworks>net9.0;net8.0</TargetFrameworks>
2222
</PropertyGroup>

Source/Porticle.Grpc.GuidMapper/PropertyVisitor.cs

Lines changed: 113 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -4,28 +4,15 @@
44

55
namespace Porticle.Grpc.GuidMapper;
66

7-
8-
public class ClassVisitor : CSharpSyntaxRewriter
9-
{
10-
public override SyntaxNode? VisitClassDeclaration(ClassDeclarationSyntax node)
11-
{
12-
Console.WriteLine("Visit Class "+node.Identifier.ValueText);
13-
var propertyVisitor = new PropertyVisitor();
14-
node = (ClassDeclarationSyntax)propertyVisitor.Visit(node);
15-
16-
17-
Console.WriteLine("Visit Methods for "+propertyVisitor.ReplaceProps.Count+" props");
18-
var methodVisitor = new MethodVisitor(propertyVisitor.ReplaceProps);
19-
node = (ClassDeclarationSyntax)methodVisitor.Visit(node);
20-
21-
return node;
22-
}
23-
}
24-
257
public class PropertyVisitor : CSharpSyntaxRewriter
268
{
279
public HashSet<PropertyToField> ReplaceProps = new();
2810

11+
public bool NeedNullableStringConverter { get; set; }
12+
public bool NeedNullableGuidConverter { get; set; }
13+
public bool NeedGuidConverter { get; set; }
14+
15+
2916
public override SyntaxNode? VisitPropertyDeclaration(PropertyDeclarationSyntax node)
3017
{
3118
var newProperty = CheckProperty(node);
@@ -35,20 +22,120 @@ public class PropertyVisitor : CSharpSyntaxRewriter
3522

3623
private PropertyDeclarationSyntax? CheckProperty(PropertyDeclarationSyntax property)
3724
{
38-
if (property.Type.ToString() != "string")
39-
// dont change anything
40-
return null;
25+
if (property.Type.ToString() == "string")
26+
{
27+
if (property.GetLeadingTrivia().ToFullString().Contains("[GrpcGuid]"))
28+
{
29+
return ConvertToGuidProperty(property);
30+
}
31+
32+
if (property.GetLeadingTrivia().ToFullString().Contains("[NullableString]"))
33+
{
34+
return ConvertToNullableStringProperty(property);
35+
}
4136

42-
if (property.GetLeadingTrivia().ToFullString().Contains("[GrpcGuid]"))
37+
return null;
38+
}
39+
40+
if (property.Type.ToString() == "pbc::RepeatedField<string>")
4341
{
44-
return ConvertToGuidProperty(property);
42+
43+
// Manipulate getter
44+
var getter = property.AccessorList?.Accessors.FirstOrDefault(a => a.IsKind(SyntaxKind.GetAccessorDeclaration));
45+
46+
if (getter?.Body == null)
47+
{
48+
Console.WriteLine($"[Error] No getter found in property {property.Identifier}");
49+
return null;
50+
}
51+
52+
var returnStatement = getter.Body?.Statements.OfType<ReturnStatementSyntax>().FirstOrDefault();
53+
54+
if (returnStatement?.Expression == null)
55+
{
56+
Console.WriteLine($"[Error] Getter has no valid return statement in property {property.Identifier}");
57+
return null;
58+
}
59+
60+
var originalReturnExpression = returnStatement.Expression;
61+
62+
var containingClass = property.Ancestors()
63+
.OfType<ClassDeclarationSyntax>()
64+
.FirstOrDefault();
65+
66+
var matchingField = containingClass.Members
67+
.OfType<FieldDeclarationSyntax>()
68+
.FirstOrDefault(field =>
69+
field.Declaration.Variables.Any(v => v.Identifier.Text == "_repeated_"+originalReturnExpression.ToFullString()+"codec")
70+
);
71+
72+
73+
bool isNullable = matchingField.ToFullString().Contains("ForClassWrapper<string>");
74+
75+
Console.WriteLine("isNullable "+isNullable+" "+property.Identifier.ToFullString());
76+
77+
if (property.GetLeadingTrivia().ToFullString().Contains("[GrpcGuid]"))
78+
{
79+
if (isNullable)
80+
{
81+
var newReturnExpression = SyntaxFactory.InvocationExpression(
82+
SyntaxFactory.ParseExpression("new RepeatedFieldNullableGuidWrapper"), // Die Methode
83+
SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(originalReturnExpression))));
84+
var newReturnStatement = returnStatement.WithExpression(newReturnExpression).WithTrailingTrivia(SyntaxFactory.Space);
85+
var newGetterBody = SyntaxFactory.Block(newReturnStatement);
86+
var newGetter = getter.WithBody(newGetterBody.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed));
87+
property = property.ReplaceNode(getter, newGetter);
88+
return property.WithType(SyntaxFactory.ParseTypeName("System.Collections.Generic.IList<Guid?>").WithTrailingTrivia(SyntaxFactory.ElasticSpace));
89+
}
90+
else
91+
{
92+
var newReturnExpression = SyntaxFactory.InvocationExpression(
93+
SyntaxFactory.ParseExpression("new RepeatedFieldGuidWrapper"), // Die Methode
94+
SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(originalReturnExpression))));
95+
var newReturnStatement = returnStatement.WithExpression(newReturnExpression).WithTrailingTrivia(SyntaxFactory.Space);
96+
var newGetterBody = SyntaxFactory.Block(newReturnStatement);
97+
var newGetter = getter.WithBody(newGetterBody.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed));
98+
property = property.ReplaceNode(getter, newGetter);
99+
return property.WithType(SyntaxFactory.ParseTypeName("System.Collections.Generic.IList<Guid>").WithTrailingTrivia(SyntaxFactory.ElasticSpace));
100+
}
101+
}
102+
103+
if (property.GetLeadingTrivia().ToFullString().Contains("[NullableString]"))
104+
{
105+
if (isNullable)
106+
{
107+
var newReturnExpression = SyntaxFactory.InvocationExpression(
108+
SyntaxFactory.ParseExpression("new RepeatedFieldNullableStringWrapper"), // Die Methode
109+
SyntaxFactory.ArgumentList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Argument(originalReturnExpression))));
110+
var newReturnStatement = returnStatement.WithExpression(newReturnExpression).WithTrailingTrivia(SyntaxFactory.Space);
111+
var newGetterBody = SyntaxFactory.Block(newReturnStatement);
112+
var newGetter = getter.WithBody(newGetterBody.WithTrailingTrivia(SyntaxFactory.CarriageReturnLineFeed));
113+
property = property.ReplaceNode(getter, newGetter);
114+
return property.WithType(SyntaxFactory.ParseTypeName("System.Collections.Generic.IList<string?>").WithTrailingTrivia(SyntaxFactory.ElasticSpace));
115+
}
116+
}
117+
118+
119+
return null;
45120
}
121+
46122

47-
if (property.GetLeadingTrivia().ToFullString().Contains("[NullableString]"))
123+
if (property.Type.ToString() == "string")
48124
{
49-
return ConvertToNullableStringProperty(property);
50-
}
125+
if (property.GetLeadingTrivia().ToFullString().Contains("[GrpcGuid]"))
126+
{
127+
return ConvertToGuidProperty(property);
128+
}
51129

130+
if (property.GetLeadingTrivia().ToFullString().Contains("[NullableString]"))
131+
{
132+
return ConvertToNullableStringProperty(property);
133+
}
134+
135+
return null;
136+
}
137+
138+
// dont change anything
52139
return null;
53140
}
54141

0 commit comments

Comments
 (0)