返回提交历史
Modified
XFEExtension.NetCore.AutoConfig.Analyzer/Generator/ProfilePropertyAutoGenerator.cs
+235
-236
Modified
XFEExtension.NetCore.AutoConfig.Analyzer/XFEExtension.NetCore.AutoConfig.Analyzer.csproj
+1
-0
XFEstudio/XFEExtension.NetCore.AutoConfig
更改分析器的语言版本为13.0
64ac962
代码差异
2 个文件
+236
-236
@@ -4,275 +4,270 @@ using Microsoft.CodeAnalysis.CSharp.Syntax;
4
4
using System.Collections.Generic;
5
5
using System.Linq;
6
6
7
namespace XFEExtension.NetCore.AutoConfig.Generator
7
namespace XFEExtension.NetCore.AutoConfig.Generator;
8
9
[Generator]
10
public class ProfilePropertyAutoGenerator : ISourceGenerator
8
11
{
9
[Generator]
10
public class ProfilePropertyAutoGenerator : ISourceGenerator
12
public void Initialize(GeneratorInitializationContext context)
11
13
{
12
public void Initialize(GeneratorInitializationContext context)
13
{
14
context.RegisterForSyntaxNotifications(() => new ProfilePropertySyntaxReceiver());
15
}
14
context.RegisterForSyntaxNotifications(() => new ProfilePropertySyntaxReceiver());
15
}
16
16
17
public void Execute(GeneratorExecutionContext context)
17
public void Execute(GeneratorExecutionContext context)
18
{
19
var syntaxTrees = context.Compilation.SyntaxTrees;
20
foreach (var syntaxTree in syntaxTrees)
18
21
{
19
var syntaxTrees = context.Compilation.SyntaxTrees;
20
foreach (var syntaxTree in syntaxTrees)
22
var root = syntaxTree.GetRoot();
23
var classDeclarations = GetClassDeclarations(root);
24
var usingDirectives = root.DescendantNodes().OfType<UsingDirectiveSyntax>().ToArray();
25
var fileScopedNamespaceDeclarationSyntax = GetFileScopedNamespaceDeclaration(root);
26
foreach (var classDeclaration in classDeclarations)
21
27
{
22
var root = syntaxTree.GetRoot();
23
var classDeclarations = GetClassDeclarations(root);
24
var usingDirectives = root.DescendantNodes().OfType<UsingDirectiveSyntax>().ToArray();
25
var fileScopedNamespaceDeclarationSyntax = GetFileScopedNamespaceDeclaration(root);
26
foreach (var classDeclaration in classDeclarations)
28
var fieldDeclarationSyntaxes = GetFieldDeclarations(classDeclaration);
29
if (fieldDeclarationSyntaxes is null || !fieldDeclarationSyntaxes.Any())
27
30
{
28
var fieldDeclarationSyntaxes = GetFieldDeclarations(classDeclaration);
29
if (fieldDeclarationSyntaxes is null || !fieldDeclarationSyntaxes.Any())
31
continue;
32
}
33
var className = classDeclaration.Identifier.ValueText;
34
var attributeSyntax = SyntaxFactory.AttributeList(
35
SyntaxFactory.SingletonSeparatedList(
36
SyntaxFactory.Attribute(SyntaxFactory.ParseName("global::XFEExtension.NetCore.AutoConfig.ProfileFieldAutoGenerateAttribute"))));
37
var properties = new List<PropertyDeclarationSyntax>();
38
var methods = new List<MethodDeclarationSyntax>();
39
foreach (var fieldDeclarationSyntax in fieldDeclarationSyntaxes)
40
{
41
var variableDeclaration = fieldDeclarationSyntax.Declaration.Variables.First();
42
var fieldName = variableDeclaration.Identifier.Text;
43
var propertyName = fieldName[0] == '_' ? fieldName[1].ToString().ToUpper() + fieldName.Substring(2) : fieldName[0].ToString().ToUpper() + fieldName.Substring(1);
44
var getMethodName = $"Get{propertyName}Property";
45
var setMethodName = $"Set{propertyName}Property";
46
GetProfilePropertyAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
30
47
{
31
continue;
32
}
33
var className = classDeclaration.Identifier.ValueText;
34
var attributeSyntax = SyntaxFactory.AttributeList(
35
SyntaxFactory.SingletonSeparatedList(
36
SyntaxFactory.Attribute(SyntaxFactory.ParseName("global::XFEExtension.NetCore.AutoConfig.ProfileFieldAutoGenerateAttribute"))));
37
var properties = new List<PropertyDeclarationSyntax>();
38
var methods = new List<MethodDeclarationSyntax>();
39
foreach (var fieldDeclarationSyntax in fieldDeclarationSyntaxes)
48
if (attribute.ArgumentList is null)
49
{
50
return;
51
}
52
var argument = attribute.ArgumentList.Arguments.First();
53
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
54
{
55
propertyName = literalExpressionSyntax.Token.ValueText;
56
}
57
});
58
var propertyType = fieldDeclarationSyntax.Declaration.Type;
59
#region Trivia头
60
var triviaText = $@"/// <inheritdoc cref=""{fieldName}""/>
61
/// <remarks>
62
/// <seealso cref=""{propertyName}""/> 是根据 <seealso cref=""{fieldName}""/> 自动生成的属性<br/><br/>
63
/// <code><seealso langword=""get""/>方法已生成以下代码: ○ <seealso cref=""{className}.{getMethodName}()""/>;<br/>";
64
#endregion
65
var getExpressionStatements = new List<StatementSyntax>()
66
{
67
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{getMethodName}()")).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
68
};
69
if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddGetAttribute))
40
70
{
41
var variableDeclaration = fieldDeclarationSyntax.Declaration.Variables.First();
42
var fieldName = variableDeclaration.Identifier.Text;
43
var propertyName = fieldName[0] == '_' ? fieldName[1].ToString().ToUpper() + fieldName.Substring(2) : fieldName[0].ToString().ToUpper() + fieldName.Substring(1);
44
var getMethodName = $"Get{propertyName}Property";
45
var setMethodName = $"Set{propertyName}Property";
46
GetProfilePropertyAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
71
GetProfilePropertyAddGetAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
47
72
{
48
73
if (attribute.ArgumentList is null)
49
74
{
50
75
return;
51
76
}
52
77
var argument = attribute.ArgumentList.Arguments.First();
78
var funcText = string.Empty;
53
79
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
54
{
55
propertyName = literalExpressionSyntax.Token.ValueText;
56
}
57
});
58
var propertyType = fieldDeclarationSyntax.Declaration.Type;
59
#region Trivia头
60
var triviaText = $@"/// <inheritdoc cref=""{fieldName}""/>
61
/// <remarks>
62
/// <seealso cref=""{propertyName}""/> 是根据 <seealso cref=""{fieldName}""/> 自动生成的属性<br/><br/>
63
/// <code><seealso langword=""get""/>方法已生成以下代码: ○ <seealso cref=""{className}.{getMethodName}()""/>;<br/>";
64
#endregion
65
var getExpressionStatements = new List<StatementSyntax>()
66
{
67
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{getMethodName}()")).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
68
};
69
if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddGetAttribute))
70
{
71
GetProfilePropertyAddGetAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
72
{
73
if (attribute.ArgumentList is null)
74
{
75
return;
76
}
77
var argument = attribute.ArgumentList.Arguments.First();
78
var funcText = string.Empty;
79
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
80
funcText = literalExpressionSyntax.Token.ValueText;
81
if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax)
82
funcText = interpolatedStringExpressionSyntax.Contents.ToString();
83
if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax)
84
funcText = invocationExpressionSyntax.GetText().ToString();
85
getExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
86
#region Get方法注释
87
triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "<br/>").Replace("return", "<seealso langword=\"return\"/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>")};<br/>";
88
#endregion
89
});
90
}
91
else
92
{
93
getExpressionStatements.Add(SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression($"Current.{fieldName}")));
94
#region Get方默认注释
95
triviaText += $@"
96
/// ○ <seealso langword=""return""/> <seealso langword=""{fieldName}""/>;";
80
funcText = literalExpressionSyntax.Token.ValueText;
81
if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax)
82
funcText = interpolatedStringExpressionSyntax.Contents.ToString();
83
if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax)
84
funcText = invocationExpressionSyntax.GetText().ToString();
85
getExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
86
#region Get方法注释
87
triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "<br/>").Replace("return", "<seealso langword=\"return\"/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>")};<br/>";
97
88
#endregion
98
}
99
#region Get方法尾及Set方法头注释
89
});
90
}
91
else
92
{
93
getExpressionStatements.Add(SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression($"Current.{fieldName}")));
94
#region Get方默认注释
100
95
triviaText += $@"
96
/// ○ <seealso langword=""return""/> <seealso langword=""{fieldName}""/>;";
97
#endregion
98
}
99
#region Get方法尾及Set方法头注释
100
triviaText += $@"
101
101
/// </code>
102
102
/// <br/>
103
103
/// <code><seealso langword=""set""/>方法已生成以下代码: ○ <seealso cref=""{className}.{setMethodName}({propertyType})""/>;<br/>";
104
#endregion
105
var setExpressionStatements = new List<StatementSyntax>()
106
{
107
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{setMethodName}(value)")).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
108
};
109
if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddSetAttribute))
104
#endregion
105
var setExpressionStatements = new List<StatementSyntax>()
106
{
107
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{setMethodName}(value)")).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
108
};
109
if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddSetAttribute))
110
{
111
GetProfilePropertyAddSetAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
110
112
{
111
GetProfilePropertyAddSetAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
113
if (attribute.ArgumentList is null)
112
114
{
113
if (attribute.ArgumentList is null)
114
{
115
return;
116
}
117
var argument = attribute.ArgumentList.Arguments.First();
118
var funcText = string.Empty;
119
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
120
funcText = literalExpressionSyntax.Token.ValueText;
121
else if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax)
122
funcText = interpolatedStringExpressionSyntax.Contents.ToString();
123
else if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax)
124
funcText = invocationExpressionSyntax.GetText().ToString();
125
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
126
#region Set方法注释
127
triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "<br/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>").Replace("value", "<seealso langword=\"value\"/>")};<br/>";
128
#endregion
129
});
130
}
131
else
132
{
133
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"Current.{fieldName} = value")));
134
#region Set方法默认注释
135
triviaText += $@"
136
/// ○ <seealso langword=""{fieldName}""/> = <seealso langword=""value""/>;<br/>";
115
return;
116
}
117
var argument = attribute.ArgumentList.Arguments.First();
118
var funcText = string.Empty;
119
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
120
funcText = literalExpressionSyntax.Token.ValueText;
121
else if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax)
122
funcText = interpolatedStringExpressionSyntax.Contents.ToString();
123
else if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax)
124
funcText = invocationExpressionSyntax.GetText().ToString();
125
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
126
#region Set方法注释
127
triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "<br/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>").Replace("value", "<seealso langword=\"value\"/>")};<br/>";
137
128
#endregion
138
}
139
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"global::XFEExtension.NetCore.AutoConfig.XFEProfile.SaveProfile(new(typeof({className}), ProfilePath))")));
140
#region Set方法中的保存方法的注释
129
});
130
}
131
else
132
{
133
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"Current.{fieldName} = value")));
134
#region Set方法默认注释
141
135
triviaText += $@"
142
/// ○ <seealso cref=""global::XFEExtension.NetCore.AutoConfig.XFEProfile.SaveProfile(ProfileInfo)""/>";
136
/// ○ <seealso langword=""{fieldName}""/> = <seealso langword=""value""/>;<br/>";
143
137
#endregion
144
#region Trivia尾
145
triviaText += @"
138
}
139
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"global::XFEExtension.NetCore.AutoConfig.XFEProfile.SaveProfile(new(typeof({className}), ProfilePath))")));
140
#region Set方法中的保存方法的注释
141
triviaText += $@"
142
/// ○ <seealso cref=""global::XFEExtension.NetCore.AutoConfig.XFEProfile.SaveProfile(ProfileInfo)""/>";
143
#endregion
144
#region Trivia尾
145
triviaText += @"
146
146
/// </code>
147
147
/// </remarks>
148
148
";
149
#endregion
150
var property = SyntaxFactory.PropertyDeclaration(propertyType, propertyName)
151
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
152
.AddAttributeLists(attributeSyntax)
153
.WithAccessorList(SyntaxFactory.AccessorList(
154
SyntaxFactory.List(new[]
155
{
156
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
157
.WithBody(SyntaxFactory.Block(getExpressionStatements)),
158
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
159
.WithBody(SyntaxFactory.Block(setExpressionStatements))
160
})))
161
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText));
162
var getMethod = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), getMethodName)
163
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)))
164
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
165
var setMethod = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), setMethodName)
166
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)))
167
.AddParameterListParameters(SyntaxFactory.Parameter(SyntaxFactory.Identifier("value")).WithType(propertyType))
168
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
169
methods.Add(getMethod);
170
methods.Add(setMethod);
171
properties.Add(property.NormalizeWhitespace());
172
}
173
var profileClassSyntaxTree = GenerateProfileClassSyntaxTree(classDeclaration, usingDirectives, properties, methods, fileScopedNamespaceDeclarationSyntax);
174
context.AddSource($"{className}.g.cs", profileClassSyntaxTree.ToString());
149
#endregion
150
var property = SyntaxFactory.PropertyDeclaration(propertyType, propertyName)
151
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
152
.AddAttributeLists(attributeSyntax)
153
.WithAccessorList(SyntaxFactory.AccessorList(
154
SyntaxFactory.List(new[]
155
{
156
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
157
.WithBody(SyntaxFactory.Block(getExpressionStatements)),
158
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
159
.WithBody(SyntaxFactory.Block(setExpressionStatements))
160
})))
161
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText));
162
var getMethod = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), getMethodName)
163
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)))
164
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
165
var setMethod = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), setMethodName)
166
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)))
167
.AddParameterListParameters(SyntaxFactory.Parameter(SyntaxFactory.Identifier("value")).WithType(propertyType).WithModifiers([SyntaxFactory.Token(SyntaxKind.RefKeyword)]))
168
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
169
methods.Add(getMethod);
170
methods.Add(setMethod);
171
properties.Add(property.NormalizeWhitespace());
175
172
}
173
var profileClassSyntaxTree = GenerateProfileClassSyntaxTree(classDeclaration, usingDirectives, properties, methods, fileScopedNamespaceDeclarationSyntax);
174
context.AddSource($"{className}.g.cs", profileClassSyntaxTree.ToString());
176
175
}
177
176
}
177
}
178
178
179
public static bool IsProfilePropertyAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfileProperty");
179
public static bool IsProfilePropertyAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfileProperty");
180
180
181
public static List<AttributeSyntax> GetProfilePropertyAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsProfilePropertyAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
181
public static List<AttributeSyntax> GetProfilePropertyAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsProfilePropertyAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
182
182
183
public static bool IsAutoLoadProfileAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "AutoLoadProfile");
183
public static bool IsAutoLoadProfileAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "AutoLoadProfile");
184
184
185
public static List<AttributeSyntax> GetAutoLoadProfileAttribute(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsAutoLoadProfileAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
185
public static List<AttributeSyntax> GetAutoLoadProfileAttribute(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsAutoLoadProfileAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
186
186
187
public static bool IsProfilePropertyAddGetAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfilePropertyAddGet");
187
public static bool IsProfilePropertyAddGetAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfilePropertyAddGet");
188
188
189
public static List<AttributeSyntax> GetProfilePropertyAddGetAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsProfilePropertyAddGetAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
189
public static List<AttributeSyntax> GetProfilePropertyAddGetAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsProfilePropertyAddGetAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
190
190
191
public static bool IsProfilePropertyAddSetAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfilePropertyAddSet");
191
public static bool IsProfilePropertyAddSetAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfilePropertyAddSet");
192
192
193
public static List<AttributeSyntax> GetProfilePropertyAddSetAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsProfilePropertyAddSetAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
193
public static List<AttributeSyntax> GetProfilePropertyAddSetAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsProfilePropertyAddSetAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
194
194
195
public static FileScopedNamespaceDeclarationSyntax GetFileScopedNamespaceDeclaration(SyntaxNode rootNode)
196
{
197
var namespaceResults = rootNode.DescendantNodes().OfType<FileScopedNamespaceDeclarationSyntax>();
198
if (namespaceResults != null && namespaceResults.Count() > 0)
199
return namespaceResults.First();
200
return null;
201
}
195
public static FileScopedNamespaceDeclarationSyntax GetFileScopedNamespaceDeclaration(SyntaxNode rootNode)
196
{
197
var namespaceResults = rootNode.DescendantNodes().OfType<FileScopedNamespaceDeclarationSyntax>();
198
if (namespaceResults != null && namespaceResults.Count() > 0)
199
return namespaceResults.First();
200
return null;
201
}
202
202
203
public static IEnumerable<FieldDeclarationSyntax> GetFieldDeclarations(ClassDeclarationSyntax classDeclaration) => classDeclaration.DescendantNodes()
204
.OfType<FieldDeclarationSyntax>()
205
.Where(fieldDeclarationSyntax => fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAttribute) && !fieldDeclarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword));
203
public static IEnumerable<FieldDeclarationSyntax> GetFieldDeclarations(ClassDeclarationSyntax classDeclaration) => classDeclaration.DescendantNodes()
204
.OfType<FieldDeclarationSyntax>()
205
.Where(fieldDeclarationSyntax => fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAttribute) && !fieldDeclarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword));
206
206
207
public static IEnumerable<ClassDeclarationSyntax> GetClassDeclarations(SyntaxNode rootNode) => rootNode.DescendantNodes()
208
.OfType<ClassDeclarationSyntax>()
209
.Where(classDeclaration => classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword) && !classDeclaration.Modifiers.Any(SyntaxKind.StaticKeyword));
207
public static IEnumerable<ClassDeclarationSyntax> GetClassDeclarations(SyntaxNode rootNode) => rootNode.DescendantNodes()
208
.OfType<ClassDeclarationSyntax>()
209
.Where(classDeclaration => classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword) && !classDeclaration.Modifiers.Any(SyntaxKind.StaticKeyword));
210
210
211
private static SyntaxTree GenerateProfileClassSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, List<PropertyDeclarationSyntax> propertyDeclarationSyntaxes, List<MethodDeclarationSyntax> methodDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax)
212
{
213
var className = classDeclaration.Identifier.ValueText;
214
var triviaText = $@"/// <remarks>
211
private static SyntaxTree GenerateProfileClassSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, List<PropertyDeclarationSyntax> propertyDeclarationSyntaxes, List<MethodDeclarationSyntax> methodDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax)
212
{
213
var className = classDeclaration.Identifier.ValueText;
214
var triviaText = $@"/// <remarks>
215
215
/// <code><seealso cref=""{className}""/> 已自动实现以下属性:</code><br/>
216
216
/// <code>
217
217
";
218
triviaText += string.Join("<br/>\n", propertyDeclarationSyntaxes.Select(propertyDeclarationSyntax => $"/// ○ <seealso cref=\"{propertyDeclarationSyntax.Identifier}\"/>")) + "\n/// </code><br/>\n/// <code>来自<seealso cref=\"global::XFEExtension.NetCore.AutoConfig.XFEProfile\"/></code>\n/// </remarks>\n";
219
var memberDeclarations = new List<MemberDeclarationSyntax>
220
{
221
SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName("string"), "ProfilePath")
222
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
223
.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(
224
new[]
225
{
226
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
227
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
228
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
229
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
230
})))
231
.WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression(@"""""")))
232
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
233
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
218
triviaText += string.Join("<br/>\n", propertyDeclarationSyntaxes.Select(propertyDeclarationSyntax => $"/// ○ <seealso cref=\"{propertyDeclarationSyntax.Identifier}\"/>")) + "\n/// </code><br/>\n/// <code>来自<seealso cref=\"global::XFEExtension.NetCore.AutoConfig.XFEProfile\"/></code>\n/// </remarks>\n";
219
var memberDeclarations = new List<MemberDeclarationSyntax>
220
{
221
SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName("string"), "ProfilePath")
222
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
223
.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(
224
new[]
225
{
226
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
227
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
228
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
229
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
230
})))
231
.WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression(@"""""")))
232
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
233
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
234
234
/// 该配置文件的自动存储和读取路径<br/>
235
235
/// 设置的时候记得带上文件名和后缀<br/>
236
236
/// <seealso cref=""ProfilePath""/> 是 <seealso cref=""{className}""/> 配置文件类的自动存储读取路径
237
237
/// </summary>
238
238
")),
239
SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(className), "Current")
240
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
241
.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Attribute(SyntaxFactory.ParseName("global::XFEExtension.NetCore.AutoConfig.ProfileInstanceAttribute")))))
242
.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(
243
new[]
244
{
245
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
246
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
247
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
248
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
249
})))
250
.WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression($"new {className}()")))
251
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
252
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
239
SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(className), "Current")
240
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
241
.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Attribute(SyntaxFactory.ParseName("global::XFEExtension.NetCore.AutoConfig.ProfileInstanceAttribute")))))
242
.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(
243
new[]
244
{
245
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
246
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
247
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
248
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
249
})))
250
.WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression($"new {className}()")))
251
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
252
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
253
253
/// 该配置文件的实例<br/>
254
254
/// <seealso cref=""Current""/> 是 <seealso cref=""{className}""/> 配置文件类的实例数据
255
255
/// </summary>
256
256
"))
257
};
258
memberDeclarations.AddRange(propertyDeclarationSyntaxes);
259
memberDeclarations.AddRange(methodDeclarationSyntaxes);
260
var staticConstructorSyntax = SyntaxFactory.ConstructorDeclaration(className)
261
.AddModifiers(SyntaxFactory.Token(SyntaxKind.StaticKeyword))
262
.WithBody(SyntaxFactory.Block(
263
SyntaxFactory.ParseStatement($"global::XFEExtension.NetCore.AutoConfig.XFEProfile.LoadProfiles([new(typeof({className}), ProfilePath)]);")));
264
if (classDeclaration.AttributeLists.Any(IsAutoLoadProfileAttribute))
257
};
258
memberDeclarations.AddRange(propertyDeclarationSyntaxes);
259
memberDeclarations.AddRange(methodDeclarationSyntaxes);
260
var staticConstructorSyntax = SyntaxFactory.ConstructorDeclaration(className)
261
.AddModifiers(SyntaxFactory.Token(SyntaxKind.StaticKeyword))
262
.WithBody(SyntaxFactory.Block(
263
SyntaxFactory.ParseStatement($"global::XFEExtension.NetCore.AutoConfig.XFEProfile.LoadProfiles([new(typeof({className}), ProfilePath)]);")));
264
if (classDeclaration.AttributeLists.Any(IsAutoLoadProfileAttribute))
265
{
266
var autoLoadProfileAttribute = classDeclaration.AttributeLists.First(attributeList => IsAutoLoadProfileAttribute(attributeList)).Attributes.First();
267
if (autoLoadProfileAttribute.ArgumentList != null)
265
268
{
266
var autoLoadProfileAttribute = classDeclaration.AttributeLists.First(attributeList => IsAutoLoadProfileAttribute(attributeList)).Attributes.First();
267
if (autoLoadProfileAttribute.ArgumentList != null)
268
{
269
var argument = autoLoadProfileAttribute.ArgumentList.Arguments.First();
270
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax && literalExpressionSyntax.Token.ValueText == "true")
271
{
272
memberDeclarations.Add(staticConstructorSyntax);
273
}
274
}
275
else
269
var argument = autoLoadProfileAttribute.ArgumentList.Arguments.First();
270
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax && literalExpressionSyntax.Token.ValueText == "true")
276
271
{
277
272
memberDeclarations.Add(staticConstructorSyntax);
278
273
}
@@ -281,31 +276,35 @@ namespace XFEExtension.NetCore.AutoConfig.Generator
281
276
{
282
277
memberDeclarations.Add(staticConstructorSyntax);
283
278
}
284
var profileClass = SyntaxFactory.ClassDeclaration(className)
285
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword))
286
.AddMembers(memberDeclarations.ToArray())
287
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText))
288
.NormalizeWhitespace();
289
MemberDeclarationSyntax memberDeclaration;
290
if (fileScopedNamespaceDeclarationSyntax is null)
291
{
292
var namespaceDeclaration = classDeclaration.FirstAncestorOrSelf<NamespaceDeclarationSyntax>();
293
if (namespaceDeclaration is null)
294
memberDeclaration = profileClass;
295
else
296
memberDeclaration = SyntaxFactory.NamespaceDeclaration(namespaceDeclaration.Name)
297
.AddMembers(profileClass);
298
}
279
}
280
else
281
{
282
memberDeclarations.Add(staticConstructorSyntax);
283
}
284
var profileClass = SyntaxFactory.ClassDeclaration(className)
285
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword))
286
.AddMembers(memberDeclarations.ToArray())
287
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText))
288
.NormalizeWhitespace();
289
MemberDeclarationSyntax memberDeclaration;
290
if (fileScopedNamespaceDeclarationSyntax is null)
291
{
292
var namespaceDeclaration = classDeclaration.FirstAncestorOrSelf<NamespaceDeclarationSyntax>();
293
if (namespaceDeclaration is null)
294
memberDeclaration = profileClass;
299
295
else
300
{
301
memberDeclaration = SyntaxFactory.FileScopedNamespaceDeclaration(fileScopedNamespaceDeclarationSyntax.Name)
296
memberDeclaration = SyntaxFactory.NamespaceDeclaration(namespaceDeclaration.Name)
302
297
.AddMembers(profileClass);
303
}
304
var profileClassCompilationUnit = SyntaxFactory.CompilationUnit()
305
.AddUsings(usingDirectiveSyntaxes)
306
.AddMembers(memberDeclaration)
307
.NormalizeWhitespace();
308
return SyntaxFactory.SyntaxTree(profileClassCompilationUnit);
309
298
}
299
else
300
{
301
memberDeclaration = SyntaxFactory.FileScopedNamespaceDeclaration(fileScopedNamespaceDeclarationSyntax.Name)
302
.AddMembers(profileClass);
303
}
304
var profileClassCompilationUnit = SyntaxFactory.CompilationUnit()
305
.AddUsings(usingDirectiveSyntaxes)
306
.AddMembers(memberDeclaration)
307
.NormalizeWhitespace();
308
return SyntaxFactory.SyntaxTree(profileClassCompilationUnit);
310
309
}
311
310
}
@@ -2,6 +2,7 @@
2
2
3
3
<PropertyGroup>
4
4
<TargetFramework>netstandard2.0</TargetFramework>
5
<LangVersion>13.0</LangVersion>
5
6
</PropertyGroup>
6
7
7
8
<PropertyGroup>