Skip to content

Commit f55fb02

Browse files
release v3.3.9
- [fix] compilation error when a derived class uses members from base class for a custom constructor #145 - [fix] fix private field access error for polymorphic types - [fix] fix code generation error for polymorphic generic types
1 parent c3636a8 commit f55fb02

10 files changed

+219
-67
lines changed

src/Nino.Generator/Common/DeserializerGenerator.cs

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -288,14 +288,33 @@ void WriteMembersWithCustomConstructor(NinoType nt, string valName, string[] con
288288
}
289289
else
290290
{
291+
List<string> ctorArgs = new List<string>();
292+
string? missingArg = null;
293+
foreach (var m in constructorMember)
294+
{
295+
var k = args.Keys.FirstOrDefault(k =>
296+
k.ToLower().Equals(m.ToLower()));
297+
if (k != null)
298+
{
299+
ctorArgs.Add(args[k]);
300+
}
301+
else
302+
{
303+
sb.AppendLine($" // missing constructor member {m}");
304+
missingArg = m;
305+
break;
306+
}
307+
}
308+
309+
if (missingArg != null)
310+
{
311+
sb.AppendLine(
312+
$" throw new InvalidOperationException(\"Missing constructor member {missingArg}\");");
313+
return;
314+
}
315+
291316
sb.AppendLine(
292-
$" {valName} = new {nt.TypeSymbol.ToDisplayString()}({string.Join(", ",
293-
constructorMember.Select(m =>
294-
args[args.Keys
295-
.FirstOrDefault(k =>
296-
k.ToLower()
297-
.Equals(m.ToLower()))]
298-
))}){(vars.Count > 0 ? "" : ";")}");
317+
$" {valName} = new {nt.TypeSymbol.ToDisplayString()}({string.Join(", ", ctorArgs)}){(vars.Count > 0 ? "" : ";")}");
299318
}
300319

301320
if (vars.Count > 0)
@@ -499,8 +518,7 @@ void CreateInstance(NinoType nt, string valName)
499518
{
500519
if (subType.TypeSymbol.IsInstanceType())
501520
{
502-
string valName = subType.TypeSymbol.ToDisplayString().Replace("global::", "").Replace(".", "_")
503-
.ToLower();
521+
string valName = subType.TypeSymbol.GetTypeInstanceName();
504522
sb.AppendLine(
505523
$" case NinoTypeConst.{subType.TypeSymbol.GetTypeFullName().GetTypeConstName()}:");
506524
sb.AppendLine(" {");

src/Nino.Generator/Common/PartialClassGenerator.cs

Lines changed: 46 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -41,13 +41,44 @@ void WriteMembers(NinoType type)
4141

4242
var sb = new StringBuilder();
4343
bool hasPrivateMembers = false;
44+
var ts = type.TypeSymbol;
45+
Dictionary<string, ITypeSymbol> memberToDeclaringType = new();
46+
if (ts is INamedTypeSymbol nts)
47+
{
48+
ts = nts.ConstructedFrom;
49+
var members = new List<ISymbol>();
50+
var curType = ts;
51+
while (curType != null && curType.IsNinoType())
52+
{
53+
members.AddRange(curType.GetMembers());
54+
curType = curType.BaseType;
55+
}
56+
57+
foreach (var member in type.Members)
58+
{
59+
var m = members.FirstOrDefault(m => m.Name == member.Name);
60+
if (m != null)
61+
{
62+
memberToDeclaringType[member.Name] = m switch
63+
{
64+
IFieldSymbol fieldSymbol => fieldSymbol.Type,
65+
IPropertySymbol propertySymbol => propertySymbol.Type,
66+
_ => member.Type
67+
};
68+
}
69+
else
70+
{
71+
memberToDeclaringType[member.Name] = member.Type;
72+
}
73+
}
74+
}
4475

4576
try
4677
{
4778
foreach (var typeMember in type.Members)
4879
{
4980
var name = typeMember.Name;
50-
var declaredType = typeMember.Type;
81+
var declaredType = memberToDeclaringType[name];
5182
var isPrivate = typeMember.IsPrivate;
5283
var isProperty = typeMember.IsProperty;
5384

@@ -57,24 +88,16 @@ void WriteMembers(NinoType type)
5788
}
5889

5990
var declaringType = declaredType.ToDisplayString();
60-
61-
if (type.TypeSymbol is INamedTypeSymbol nts)
91+
var member = ts.GetMembers().FirstOrDefault(m => m.Name == name);
92+
if (member != null)
6293
{
63-
if (nts.TypeParameters.Length > 0)
94+
if (member is IFieldSymbol fieldSymbol)
95+
{
96+
declaringType = fieldSymbol.Type.ToDisplayString();
97+
}
98+
else if (member is IPropertySymbol propertySymbol)
6499
{
65-
var member = nts.ConstructedFrom
66-
.GetMembers().FirstOrDefault(m => m.Name == name);
67-
if (member != null)
68-
{
69-
if (member is IFieldSymbol fieldSymbol)
70-
{
71-
declaringType = fieldSymbol.Type.ToDisplayString();
72-
}
73-
else if (member is IPropertySymbol propertySymbol)
74-
{
75-
declaringType = propertySymbol.Type.ToDisplayString();
76-
}
77-
}
100+
declaringType = propertySymbol.Type.ToDisplayString();
78101
}
79102
}
80103

@@ -110,14 +133,14 @@ void WriteMembers(NinoType type)
110133
return;
111134
}
112135

113-
var hasNamespace = !type.TypeSymbol.ContainingNamespace.IsGlobalNamespace &&
114-
!string.IsNullOrEmpty(type.TypeSymbol.ContainingNamespace.ToDisplayString());
115-
var typeNamespace = type.TypeSymbol.ContainingNamespace.ToDisplayString();
116-
var modifer = type.TypeSymbol.GetTypeModifiers();
136+
var hasNamespace = !ts.ContainingNamespace.IsGlobalNamespace &&
137+
!string.IsNullOrEmpty(ts.ContainingNamespace.ToDisplayString());
138+
var typeNamespace = ts.ContainingNamespace.ToDisplayString();
139+
var modifer = ts.GetTypeModifiers();
117140
//get typename, including type parameters if any
118-
var typeSimpleName = type.TypeSymbol.Name;
141+
var typeSimpleName = ts.Name;
119142
//type arguments to type parameters
120-
if (type.TypeSymbol is INamedTypeSymbol namedTypeSymbol)
143+
if (ts is INamedTypeSymbol namedTypeSymbol)
121144
{
122145
var typeParameters = namedTypeSymbol.TypeParameters;
123146
if (typeParameters.Length > 0)

src/Nino.Generator/Common/SerializerGenerator.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -188,8 +188,7 @@ void WriteMembers(NinoType type, string valName)
188188
continue;
189189
}
190190

191-
string valName = subType.TypeSymbol.ToDisplayString().Replace("global::", "")
192-
.Replace(".", "_").ToLower();
191+
string valName = subType.TypeSymbol.GetTypeInstanceName();
193192
sb.AppendLine($" case {subType.TypeSymbol.ToDisplayString()} {valName}:");
194193
sb.AppendLine(
195194
$" writer.Write(NinoTypeConst.{subType.TypeSymbol.GetTypeFullName().GetTypeConstName()});");

src/Nino.Generator/Common/UnsafeAccessorGenerator.cs

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
using System;
22
using System.Collections.Generic;
3+
using System.Linq;
34
using System.Text;
45
using Microsoft.CodeAnalysis;
56
using Nino.Generator.Metadata;
@@ -20,6 +21,7 @@ protected override void Generate(SourceProductionContext spc)
2021

2122
var sb = new StringBuilder();
2223
var generatedTypes = new HashSet<NinoType>();
24+
var generatedMembers = new HashSet<(string, string)>();
2325

2426
foreach (var ninoType in NinoTypes)
2527
{
@@ -47,9 +49,32 @@ void WriteMembers(NinoType type)
4749
continue;
4850
}
4951

50-
string typeName = type.TypeSymbol.ToDisplayString();
52+
var declaringType = type.TypeSymbol;
53+
while (declaringType != null && declaringType.IsNinoType())
54+
{
55+
var m = declaringType.GetMembers().FirstOrDefault(m => m.Name == member.Name);
56+
if (m != null)
57+
{
58+
declaringType = m.ContainingType;
59+
break;
60+
}
61+
62+
declaringType = declaringType.BaseType;
63+
}
64+
65+
if (declaringType == null)
66+
{
67+
continue;
68+
}
69+
70+
string typeName = declaringType.ToDisplayString();
71+
72+
if (!generatedMembers.Add((typeName, member.Name)))
73+
{
74+
continue;
75+
}
5176

52-
if (type.TypeSymbol.IsValueType)
77+
if (declaringType.IsValueType)
5378
{
5479
typeName = $"ref {typeName}";
5580
}

src/Nino.Generator/NinoAnalyzer.cs

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -50,6 +50,15 @@ public override void Initialize(AnalysisContext context)
5050
a.AttributeClass.ToDisplayString().EndsWith("NinoTypeAttribute"));
5151
bool autoCollect = attr == null || (bool)(attr.ConstructorArguments[0].Value ?? false);
5252
bool containNonPublic = attr != null && (bool)(attr.ConstructorArguments[1].Value ?? false);
53+
54+
// check if the type is nested
55+
if (typeDeclarationSyntax.Parent is TypeDeclarationSyntax && containNonPublic)
56+
{
57+
syntaxContext.ReportDiagnostic(Diagnostic.Create(
58+
SupportedDiagnostics[7],
59+
typeDeclarationSyntax.Identifier.GetLocation(),
60+
typeDeclarationSyntax.Identifier.Text));
61+
}
5362

5463
foreach (var member in typeSymbol.GetMembers())
5564
{
@@ -175,6 +184,11 @@ public override void Initialize(AnalysisContext context)
175184
"Suspicious member",
176185
"Member '{0}' of NinoType '{1}' is private but this type is not marked as containing non-public members",
177186
"Nino",
187+
DiagnosticSeverity.Error, true),
188+
new DiagnosticDescriptor("NINO008",
189+
"Nested type that may contain non-public members",
190+
"NinoType '{0}' is allowed to contain non-public members so it cannot be nested",
191+
"Nino",
178192
DiagnosticSeverity.Error, true)
179193
);
180194
}

src/Nino.Generator/NinoTypeHelper.cs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,17 @@ namespace Nino.Generator;
1515
public static class NinoTypeHelper
1616
{
1717
public const string WeakVersionToleranceSymbol = "WEAK_VERSION_TOLERANCE";
18+
19+
public static string GetTypeInstanceName(this ITypeSymbol typeSymbol)
20+
{
21+
var ret = typeSymbol.ToDisplayString()
22+
.Replace("global::", "")
23+
.Replace("<", "_")
24+
.Replace(">", "_")
25+
.Replace(".", "_").ToLower();
26+
27+
return $"@{ret}";
28+
}
1829

1930
public static List<ITypeSymbol> MergeTypes(this List<ITypeSymbol?> types, List<ITypeSymbol?> otherTypes)
2031
{

src/Nino.Generator/Parser/CSharpParser.cs

Lines changed: 13 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,16 +33,27 @@ NinoType GetNinoType(ITypeSymbol typeSymbol)
3333

3434
ninoType = new NinoType(typeSymbol, null, null);
3535

36+
bool IsNinoType(ITypeSymbol ts)
37+
{
38+
if (!ts.IsNinoType())
39+
return false;
40+
41+
if(!types.Contains(ts))
42+
GetNinoType(ts);
43+
44+
return true;
45+
}
46+
3647
// collect base type
37-
if (typeSymbol.BaseType != null && types.Contains(typeSymbol.BaseType))
48+
if (typeSymbol.BaseType != null && IsNinoType(typeSymbol.BaseType))
3849
{
3950
ninoType.AddParent(GetNinoType(typeSymbol.BaseType));
4051
}
4152

4253
// collect base interfaces
4354
foreach (var interfaceType in typeSymbol.AllInterfaces)
4455
{
45-
if (types.Contains(interfaceType))
56+
if (IsNinoType(interfaceType))
4657
{
4758
ninoType.AddParent(GetNinoType(interfaceType));
4859
}

src/Nino.UnitTests/AnalyzerTest.cs

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -316,4 +316,26 @@ await SetUpAnalyzerTest(code, Verify.Diagnostic("NINO007")
316316
.WithSpan(8, 17, 8, 18)
317317
.WithArguments("A", "TestClass")).RunAsync();
318318
}
319+
320+
[TestMethod]
321+
public async Task TestNino008()
322+
{
323+
var code = @"
324+
using Nino.Core;
325+
326+
public class TestNested
327+
{
328+
[NinoType(false, true)]
329+
public class TestClass
330+
{
331+
[NinoMember(1)]
332+
private int A;
333+
}
334+
}
335+
";
336+
337+
await SetUpAnalyzerTest(code, Verify.Diagnostic("NINO008")
338+
.WithSpan(7, 18, 7, 27)
339+
.WithArguments("TestClass")).RunAsync();
340+
}
319341
}

0 commit comments

Comments
 (0)