-
Notifications
You must be signed in to change notification settings - Fork 0
/
StaticExtensionGenerator.cs
141 lines (134 loc) · 6.23 KB
/
StaticExtensionGenerator.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.ComponentModel;
using System.IO;
using System.Linq;
using System.Text;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Rop.Generators.Shared;
namespace Rop.Winforms7.StaticExtensionGenerator
{
[Generator]
public class StaticExtensionGenerator : ISourceGenerator
{
public void Initialize(GeneratorInitializationContext context)
{
context.RegisterForSyntaxNotifications(() => new ClassesToAugmentReceiver());
}
public void Execute(GeneratorExecutionContext context)
{
var collector = context.SyntaxReceiver as ClassesToAugmentReceiver;
if (collector == null || collector.ClassesToAugment.Count == 0) return;
foreach (var classtoaugment in collector.ClassesToAugment)
{
generateCode(context, classtoaugment,collector);
}
collector.Clear();
}
private void generateCode(GeneratorExecutionContext context, PartialClassToAugment classtoaugment,ClassesToAugmentReceiver receiver)
{
var formname=classtoaugment.Identifier;
var file = classtoaugment.FileName +".StaticExtensions_.g.cs";
var model = context.Compilation.GetSemanticModel(classtoaugment.Original.SyntaxTree);
var classmodel = (INamedTypeSymbol)model.GetDeclaredSymbol(classtoaugment.Original);
if (classmodel is null) return;
var baseclase=classmodel.BaseType;
if (baseclase is null||baseclase.Name=="Object")
{
var iderived=classmodel.Interfaces.FirstOrDefault(i=>i.Name=="IDerivedFrom" || i.Name=="IFormDerivedFrom");
if (iderived != null)
{
baseclase= iderived.TypeArguments[0] as INamedTypeSymbol;
}
}
var (staticMethods,path)=GetStaticMethods(baseclase,classmodel,model,receiver);
var sb = new StringBuilder();
sb.AppendLine("// Autogenerated code for StaticMethods");
sb.AppendLine("// Object Path: " + path);
if (staticMethods.Count == 0)
{
// ERROR NO EXTENSIONS
sb.AppendLines("// ERROR NO EXTENSIONS",$"// Looking for:{classtoaugment.Identifier}");
var finalerror = sb.ToString();
context.AddSource(file, finalerror);
return;
}
sb.AppendLines(classtoaugment.GetHeader(new string []{}));
foreach (var symbol in staticMethods)
{
var prename = symbol.Name;
var name = prename;
if (name.StartsWith("_")) name = name.Substring(1);
if (char.IsLower(name[0])) name = char.ToUpper(name[0]) + name.Substring(1);
var returntype = symbol.ReturnType.ToString();
var par=symbol.Parameters;
var pardef=string.Join(",",par.Select(p=>p.ToString()));
var parnames =string.Join(",",par.Select(p => p.Name));
var clasebelongs=symbol.ContainingType;
sb.AppendLines($"\t\tpublic static {returntype} {name}({pardef})=>{clasebelongs.ToDisplayString()}.{prename}<{formname}>({parnames});");
}
sb.AppendLines(classtoaugment.GetFooter());
var final = sb.ToString();
context.AddSource(file, final);
}
private (List<IMethodSymbol>,string) GetStaticMethods(INamedTypeSymbol baseclase, INamedTypeSymbol classmodel, SemanticModel model, ClassesToAugmentReceiver receiver)
{
var res=new List<IMethodSymbol>();
var path = "";
if (receiver.DictionaryOfMethods.TryGetValue(baseclase.ToDisplayString(), out var tmethods))
{
return tmethods;
}
try
{
var bc = baseclase.BaseType;
path = bc?.ToDisplayString()??"";
if (bc != null && bc.Name != "Object")
{
var preres = GetStaticMethods(bc, classmodel, model, receiver);
res.AddRange(preres.Item1);
path = path+"-->"+preres.Item2;
}
var staticMethods = baseclase.GetMembers()
.Where(m => m.Kind == SymbolKind.Method && m.IsStatic && m.IsDecoratedWith("StaticExtension"))
.OfType<IMethodSymbol>().ToList();
foreach (var method in staticMethods)
{
if (!method.IsGenericMethod) continue;
var a = method.TypeParameters[0];
var constraints = a.ConstraintTypes[0].Name;
if (constraints!=baseclase.Name) continue;
res.Add(method);
}
receiver.DictionaryOfMethods.Add(baseclase.ToDisplayString(), (res,path));
return (res,path);
}
catch (System.Exception ex)
{
return (new List<IMethodSymbol>(),"*Error:"+ex.Message);
}
}
class ClassesToAugmentReceiver : ISyntaxReceiver
{
public ConcurrentBag<PartialClassToAugment> ClassesToAugment { get; private set; } = new ConcurrentBag<PartialClassToAugment>();
public Dictionary<string,(List<IMethodSymbol>,string)> DictionaryOfMethods { get; private set; } = new Dictionary<string, (List<IMethodSymbol>, string)>();
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
{
if (!(syntaxNode is ClassDeclarationSyntax cds)) return;
// Business logic to decide what we're interested in goes here
var att=cds.GetDecoratedWith("InsertStaticExtensions");
if (att!=null)
{
var ac = new PartialClassToAugment(cds);
ClassesToAugment.Add(ac);
}
}
public void Clear()
{
ClassesToAugment = new ConcurrentBag<PartialClassToAugment>();
DictionaryOfMethods = new Dictionary<string, (List<IMethodSymbol>, string)>();
}
}
}
}