XFE Git
XFE Studio Git
Git 首页 全局搜索
XFE 主站 文档 NuGet

XFEExtension.NetCore.AutoConfig

【DLL】自动实现配置文件的存储

公开
关注 0 Fork 0 Star 0
返回提交历史

XFEstudio/XFEExtension.NetCore.AutoConfig

更改分析器的语言版本为13.0

64ac962
XFE工作室室长 <mail@xfegzs.com>
提交于

代码差异

2 个文件 +236 -236
Modified XFEExtension.NetCore.AutoConfig.Analyzer/Generator/ProfilePropertyAutoGenerator.cs +235 -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 }
Modified XFEExtension.NetCore.AutoConfig.Analyzer/XFEExtension.NetCore.AutoConfig.Analyzer.csproj +1 -0
@@ -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>