Skip to content

Commit f2387a5

Browse files
SourceGen: A ton of progress on source generation. Multiple errors are now reported instead of breaking out 1 error per method, resolver, or object. Simplified some code. Deleted unused code.
1 parent e1391d3 commit f2387a5

17 files changed

+553
-505
lines changed

EppNet-SourceGen/RegisterObjectsGenerator.cs

Lines changed: 44 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,11 @@
66
using EppNet.SourceGen.Models;
77

88
using Microsoft.CodeAnalysis;
9+
using Microsoft.CodeAnalysis.CSharp;
910
using Microsoft.CodeAnalysis.CSharp.Syntax;
1011

12+
using System.Collections.Concurrent;
13+
using System.Collections.Generic;
1114
using System.Linq;
1215
using System.Text;
1316

@@ -24,57 +27,70 @@ public class RegisterObjectsGenerator : IIncrementalGenerator
2427
public void Initialize(IncrementalGeneratorInitializationContext context)
2528
{
2629

30+
ConcurrentDictionary<string, string> resolverDict = new();
31+
2732
// Let's locate our resolvers
28-
IncrementalValuesProvider<ResolverModel?> resolverProvider = context.SyntaxProvider
33+
var resolvers = context.SyntaxProvider
2934
.ForAttributeWithMetadataName(
3035
NetTypeResolverAttrFullName,
3136
predicate: static (node, _) => node is ClassDeclarationSyntax,
32-
transform: static (ctx, ct) => LocateResolver(ctx.TargetNode, ctx.SemanticModel, ct).Item1
33-
);
34-
35-
var resolvers = resolverProvider
37+
transform: static (ctx, ct) => TryCreateResolver(ctx.TargetNode as CSharpSyntaxNode, ctx.SemanticModel, ct).Item1
38+
)
3639
.Where(static r => r is not null)
3740
.Collect()
38-
.Select(static (list, _) => list.ToDictionary(r => r.Value.ResolvedTypeFullName, r => r.Value.Name));
41+
.Select(static (list, _) => list.ToDictionary(r => r!.Value.ResolvedTypeFullName, r => r!.Value.Name));
3942

4043
var netObjects = context.SyntaxProvider
4144
.ForAttributeWithMetadataName(
4245
NetObjectAttrFullName,
4346
predicate: static (node, _) => node is ClassDeclarationSyntax,
44-
transform: static (ctx, ct) => LocateNetObject(ctx.TargetNode, ctx.SemanticModel, ct)
47+
transform: (ctx, ct) => TryCreateNetObject(ctx.TargetNode as CSharpSyntaxNode, ctx.SemanticModel, null, ct)
4548
)
46-
//.Combine(resolvers)
4749
.Where(static o => o.Item1 is not null)
4850
.Collect()
49-
.Select(static (list, _) => list.ToDictionary(o => o.Item1.Value.FullyQualifiedName, o => o.Item1));
51+
.Select(static (list, _) => list.ToDictionary(o => o!.Item1.Value.FullyQualifiedName, o => o!.Item1.Value));
5052

51-
var combined = netObjects.Combine(resolvers);
53+
context.RegisterSourceOutput(netObjects.Combine(resolvers), static (SourceProductionContext spc, (Dictionary<string, NetworkObjectModel>, Dictionary<string, string>) b) =>
54+
{
5255

53-
var netMethods = context.SyntaxProvider
54-
.ForAttributeWithMetadataName(
55-
NetMethodAttrFullName,
56-
predicate: static (node, _) => node is MethodDeclarationSyntax,
57-
transform: static (ctx, ct) => (ctx, ct)
58-
)
59-
.Combine(combined)
60-
.Select(static (pair, _) =>
56+
(Dictionary<string, NetworkObjectModel> objs, Dictionary<string, string> resolverDict) = b;
57+
58+
foreach (KeyValuePair<string, NetworkObjectModel> kvp in objs)
6159
{
62-
var ((ctx, ct), (netObjects, resolvers)) = pair;
63-
return LocateNetMethod(ctx.TargetNode, ctx.SemanticModel, resolvers, netObjects, ct);
64-
});
60+
string fqn = kvp.Key;
61+
NetworkObjectModel model = kvp.Value;
6562

66-
context.RegisterSourceOutput(netObjects, static (spc, objs) =>
67-
{
63+
StringBuilder availableMethods = new();
6864

69-
foreach (NetworkObjectModel? obj in objs.Values)
70-
{
71-
if (!obj.HasValue)
72-
return;
65+
foreach (KeyValuePair<string, EquatableList<NetworkMethodModel>> kvp2 in model.Methods)
66+
{
67+
EquatableList<NetworkMethodModel> methods = kvp2.Value;
68+
69+
foreach (NetworkMethodModel method in methods)
70+
availableMethods.AppendLine($"// - {method.ToString()}");
71+
}
72+
73+
if (availableMethods.Length == 0)
74+
availableMethods.Append($"// no methods found?!?! HELLO!? Methods.Count: {model.Methods.Count}");
75+
76+
StringBuilder hierarchy = new();
77+
78+
if (model.NetObjectHierarchy == null)
79+
hierarchy.AppendLine("// - System.Object");
80+
else
81+
{
82+
foreach (string bFQN in model.NetObjectHierarchy)
83+
hierarchy.AppendLine($"// - {bFQN}");
84+
}
7385

74-
NetworkObjectModel model = obj.Value;
7586
StringBuilder builder = new($$"""
7687
// <auto-generated/>
7788
// full {{model.FullNamespace}}
89+
// hierarchy:
90+
{{hierarchy.ToString()}}
91+
// available methods:
92+
{{availableMethods.ToString()}}
93+
// dist: {{model.Distribution}}
7894
7995
using EppNet.Logging;
8096
using EppNet.Node;

EppNet-SourceGen/ResolverGenerator.cs

Lines changed: 0 additions & 71 deletions
This file was deleted.

EppNet-SourceGen/Source/Analysis/NetworkObjectAnalysis.cs

Lines changed: 23 additions & 98 deletions
Original file line numberDiff line numberDiff line change
@@ -5,17 +5,17 @@
55
//////////////////////////////////////////////
66

77
using EppNet.SourceGen;
8+
using EppNet.SourceGen.Errors;
89
using EppNet.SourceGen.Models;
910

1011
using Microsoft.CodeAnalysis;
1112
using Microsoft.CodeAnalysis.CSharp;
1213
using Microsoft.CodeAnalysis.CSharp.Syntax;
1314
using Microsoft.CodeAnalysis.Diagnostics;
1415

15-
using System;
1616
using System.Collections.Concurrent;
17+
using System.Collections.Generic;
1718
using System.Collections.Immutable;
18-
using System.Reflection;
1919

2020
namespace EppNet.Source.Analysis
2121
{
@@ -24,14 +24,13 @@ public class NetworkObjectAnalysis : DiagnosticAnalyzer
2424
{
2525

2626
public static ConcurrentDictionary<string, string> Resolvers = new();
27-
public static ConcurrentDictionary<string, NetworkObjectModel?> Objects = new();
27+
public static ConcurrentDictionary<string, NetworkObjectModel> Objects = new();
2828

2929
public override void Initialize(AnalysisContext context)
3030
{
3131
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.None);
3232
context.EnableConcurrentExecution();
3333

34-
3534
context.RegisterCompilationStartAction(compContext =>
3635
{
3736

@@ -43,32 +42,13 @@ public override void Initialize(AnalysisContext context)
4342
if (!Globals.HasAttribute(classNode, Globals.NetTypeResolverAttr))
4443
return;
4544

46-
(ResolverModel?, ResolverAnalysisError) data = Globals.LocateResolver(snac.Node, snac.SemanticModel, snac.CancellationToken);
47-
ResolverAnalysisError results = data.Item2;
48-
49-
foreach (ResolverAnalysisError error in Enum.GetValues(typeof(ResolverAnalysisError)))
50-
{
51-
if (error == ResolverAnalysisError.None)
52-
continue;
53-
54-
if (results.HasFlag(error))
55-
{
56-
string message = error switch
57-
{
58-
ResolverAnalysisError.LacksSingleton => $"{classNode.Identifier.Text}: Resolvers must define a public static singleton field or property \"Instance\"",
59-
ResolverAnalysisError.LacksInheritance => $"{classNode.Identifier.Text}: Resolvers must inherit from {Globals.TypeResolverFullGenericName}",
60-
ResolverAnalysisError.NotClass => $"{classNode.Identifier.Text}: Resolvers must be a class!",
61-
_ => ToString(),
62-
};
63-
snac.ReportDiagnostic(Diagnostic.Create(Globals.DescTypeResolverError,
64-
classNode.Identifier.GetLocation(), message));
65-
}
66-
}
67-
68-
if (results == ResolverAnalysisError.None && data.Item1.HasValue)
69-
{
70-
Resolvers[data.Item1.Value.ResolvedTypeFullName] = data.Item1.Value.Name;
71-
}
45+
(ResolverModel? model, List<AnalysisError> errors) = Globals.TryCreateResolver(snac.Node as CSharpSyntaxNode, snac.SemanticModel, snac.CancellationToken);
46+
47+
foreach (AnalysisError error in errors)
48+
snac.ReportDiagnostic(error.CreateDiagnostic());
49+
50+
if (model.HasValue && errors.Count == 0)
51+
Resolvers[model.Value.ResolvedTypeFullName] = model.Value.Name;
7252

7353
}, SyntaxKind.ClassDeclaration);
7454

@@ -79,36 +59,14 @@ public override void Initialize(AnalysisContext context)
7959
if (!Globals.HasAttribute(classNode, Globals.NetObjectAttr))
8060
return;
8161

82-
var data = Globals.LocateNetObject(
83-
classNode, snac.SemanticModel, snac.CancellationToken);
84-
85-
NetworkObjectModel? netModel = data.Item1;
86-
NetworkObjectAnalysisError results = data.Item2;
87-
88-
foreach (NetworkObjectAnalysisError error in Enum.GetValues(typeof(NetworkObjectAnalysisError)))
89-
{
90-
if (error == NetworkObjectAnalysisError.None)
91-
continue;
92-
93-
if (results.HasFlag(error))
94-
{
95-
string message = error switch
96-
{
97-
NetworkObjectAnalysisError.NotPartial => $"{classNode.Identifier.Text}: Network Object definitions must be partial! Num Resolvers: {Resolvers.Count}",
98-
NetworkObjectAnalysisError.LacksInheritance => $"{classNode.Identifier.Text}: Network Object definitions must inherit from {Globals.NetworkObjectInterfaceName}",
99-
NetworkObjectAnalysisError.NotClass => $"{classNode.Identifier.Text}: Network Object definitions must be a class!",
100-
_ => ToString(),
101-
};
102-
103-
snac.ReportDiagnostic(Diagnostic.Create(Globals.DescNetObjError,
104-
classNode.Identifier.GetLocation(), message));
105-
}
106-
}
107-
108-
if (results == NetworkObjectAnalysisError.None && data.Item1.HasValue)
109-
{
110-
Objects[data.Item1.Value.FullyQualifiedName] = data.Item1;
111-
}
62+
(NetworkObjectModel? netModel, List<AnalysisError> errors) = Globals.TryCreateNetObject(
63+
classNode, snac.SemanticModel, Resolvers, snac.CancellationToken);
64+
65+
foreach (AnalysisError error in errors)
66+
snac.ReportDiagnostic(error.CreateDiagnostic());
67+
68+
if (netModel.HasValue && errors.Count == 0)
69+
Objects[netModel.Value.FullyQualifiedName] = netModel.Value;
11270

11371
}, SyntaxKind.ClassDeclaration);
11472

@@ -117,51 +75,18 @@ public override void Initialize(AnalysisContext context)
11775

11876
MethodDeclarationSyntax methodNode = snac.Node as MethodDeclarationSyntax;
11977

120-
if (!Globals.HasAttribute(methodNode, Globals.NetMethodAttr))
78+
if (methodNode is not null && !Globals.HasAttribute(methodNode, Globals.NetMethodAttr))
12179
return;
12280

123-
var data = Globals.LocateNetMethod(methodNode, snac.SemanticModel, Resolvers, Objects);
124-
NetworkMethodAnalysisError results = data.Item2;
125-
126-
foreach (NetworkMethodAnalysisError error in Enum.GetValues(typeof(NetworkMethodAnalysisError)))
127-
{
128-
if (error == NetworkMethodAnalysisError.None)
129-
continue;
130-
131-
if (results.HasFlag(error))
132-
{
81+
(NetworkMethodModel? model, List<AnalysisError> errors)
82+
= Globals.TryCreateNetMethod(methodNode, snac.SemanticModel, Resolvers, snac.CancellationToken);
13383

134-
if (error == NetworkMethodAnalysisError.MissingResolver)
135-
{
136-
ITypeSymbol typeSymbol = snac.SemanticModel.GetTypeInfo(data.Item4).Type;
137-
138-
if (typeSymbol == null)
139-
continue;
140-
141-
string fullTypeName = $"{typeSymbol.ContainingNamespace.ToDisplayString()}.{typeSymbol.Name}";
142-
143-
snac.ReportDiagnostic(Diagnostic.Create(Globals.DescNetMethodError,
144-
data.Item3.GetLocation(), [data.Item4.GetLocation()], $"{methodNode.Identifier.Text}: Type {fullTypeName} does not have a registered Resolver!"));
145-
146-
continue;
147-
}
148-
149-
string message = error switch
150-
{
151-
NetworkMethodAnalysisError.NotNetworkObjectClass => $"{methodNode.Identifier.Text}: Network method must be within a class decorated with the NetworkObject attribute!",
152-
NetworkMethodAnalysisError.Inaccessible => $"{methodNode.Identifier.Text}: Network method must be public!",
153-
_ => $"{ToString()}",
154-
};
155-
156-
snac.ReportDiagnostic(Diagnostic.Create(Globals.DescNetMethodError,
157-
methodNode.Identifier.GetLocation(), message));
158-
}
159-
}
84+
foreach (AnalysisError error in errors)
85+
snac.ReportDiagnostic(error.CreateDiagnostic());
16086

16187
}, SyntaxKind.MethodDeclaration);
16288
});
16389

164-
16590
}
16691

16792
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics =>

0 commit comments

Comments
 (0)