XFEExtension
【DLL】XFE各类拓展是一个C#的DLL库,旨在优化C#代码中常用语句的使用,并提供更简洁的访问方式,同时提供Xunit测试框架,快速搭建服务器/客户端,免费ChatGPTAPI接口,免费通讯服务器,XFE下载器,新增格式等
关注
0
Fork
0
Star
0
返回提交历史
Modified
README.md
+1
-169
Deleted
XFEExtension.NetCore.Analyzer/CodeFix/ProfileExtensionCodeFixProvider.cs
+0
-67
Deleted
XFEExtension.NetCore.Analyzer/Diagnostics/ProfileExtensionDiagnostics.cs
+0
-127
Deleted
XFEExtension.NetCore.Analyzer/Diagnostics/TodoCommentAnalyzerDiagnostics.cs
+0
-84
Deleted
XFEExtension.NetCore.Analyzer/Generator/AutoPathSyntaxReceiver.cs
+0
-23
Deleted
XFEExtension.NetCore.Analyzer/Generator/PathPropertyAutoGenerator.cs
+0
-182
Deleted
XFEExtension.NetCore.Analyzer/Generator/ProfilePropertyAutoGenerator.cs
+0
-296
Deleted
XFEExtension.NetCore.Analyzer/Generator/ProfilePropertySyntaxReceiver.cs
+0
-23
Deleted
XFEExtension.NetCore.Analyzer/GeneratorOptions.cs
+0
-27
Modified
XFEExtension.NetCore.Analyzer/XFEExtension.NetCore.Analyzer.csproj
+3
-6
Deleted
XFEExtension.NetCore/ImplExtension/CreateImpl.cs
+0
-7
Deleted
XFEExtension.NetCore/PathExtension/AutoPathAttribute.cs
+0
-27
Deleted
XFEExtension.NetCore/PathExtension/XFEAutoPath.cs
+0
-18
Deleted
XFEExtension.NetCore/ProfileExtension/AutoLoadProfileAttribute.cs
+0
-14
Deleted
XFEExtension.NetCore/ProfileExtension/ProfileEntryInfo.cs
+0
-20
Deleted
XFEExtension.NetCore/ProfileExtension/ProfileFieldAutoGenerateAttribute.cs
+0
-9
Deleted
XFEExtension.NetCore/ProfileExtension/ProfileInfo.cs
+0
-62
Deleted
XFEExtension.NetCore/ProfileExtension/ProfileInstanceAttribute.cs
+0
-7
Deleted
XFEExtension.NetCore/ProfileExtension/ProfilePropertyAddGetAttribute.cs
+0
-14
Deleted
XFEExtension.NetCore/ProfileExtension/ProfilePropertyAddSetAttribute.cs
+0
-14
Deleted
XFEExtension.NetCore/ProfileExtension/ProfilePropertyAttribute.cs
+0
-25
Deleted
XFEExtension.NetCore/ProfileExtension/XFEProfile.cs
+0
-304
Modified
XFEExtension.NetCore/XFEExtension.NetCore.csproj
+3
-11
XFEstudio/XFEExtension
删除了多个类和文件,更新了项目版本
f79abc6
代码差异
23 个文件
+7
-1536
@@ -2,7 +2,7 @@
2
2
3
3
## 描述
4
4
5
XFEExtension是一个C#的DLL库,旨在优化C#代码中常用语句的使用,并提供更简洁的访问方式,同时提供XUnit测试框架,快速搭建服务器/客户端,免费ChatGPTAPI接口,免费通讯服务器,XFE下载器,新增格式等
5
XFEExtension是一个C#的DLL库,旨在优化C#代码中常用语句的使用,并提供更简洁的访问方式,快速搭建服务器/客户端,免费ChatGPTAPI接口,免费通讯服务器,XFE下载器,新增格式等
6
6
7
7
## 用途
8
8
@@ -14,157 +14,10 @@ XFEExtension库适用于各种C#项目,特别适合在需要提高代码可读
14
14
15
15
- **加速开发:** 通过减少样板代码,XFEExtension可以加速项目的开发过程,同时提高代码的可维护性。
16
16
17
18
## 设置csproj文件配置
19
20
```xml
21
<PropertyGroup>
22
<!--设置是否启用自动配置文件-->
23
<AutoProfile>true</AutoProfile>
24
<!--设置是否启用自动路径-->
25
<AutoPath>true</AutoPath>
26
<!--设置是否启用TODO待办任务提醒-->
27
<TodoList>true</TodoList>
28
<!--设置待办任务的提示级别-->
29
<TodoListWarningLevel>3</TodoListWarningLevel>
30
</PropertyGroup>
31
```
32
33
34
17
# 示例(使用前记得进行相应的引用)
35
18
36
19
---
37
20
38
## TODO待办任务提醒
39
40
```csharp
41
//TODO: 这是一个待办任务,使用默认提示级别
42
43
//TODO:1 这是一个待办任务,使用提示级别
44
45
//TODO:3 这是一个待办任务,使用错误提示级别
46
47
//提示级别:0-隐藏,1-提示,2-警告,3-错误
48
```
49
50
51
## 自动实现配置文件的存储
52
53
#### 基础用法
54
55
```csharp
56
//创建配置文件类
57
partial class SystemProfile
58
{
59
[ProfileProperty]
60
string name;
61
62
[ProfileProperty]
63
int _age;
64
}
65
66
//使用配置文件
67
class Program
68
{
69
static void Main(string[] args)
70
{
71
SystemProfile.Name = "Test";//在设置值的时候会自动记录并储存
72
//SystemProfile.Age = 1;
73
Console.WriteLine(SystemProfile.Name);
74
Console.WriteLine(SystemProfile.Age);//下次打开程序会自动读取上次程序退出时储存的值
75
}
76
}
77
```
78
79
#### 设置get和set方法
80
81
```csharp
82
partial class SystemProfile
83
{
84
[ProfileProperty]
85
[ProfilePropertyAddGet(@"Console.WriteLine(""获取了Name"")")]
86
[ProfilePropertyAddGet("return Current.name")]
87
[ProfilePropertyAddSet(@"Console.WriteLine(""设置了Name"")")]
88
[ProfilePropertyAddSet("Current.name = value")]
89
string name = string.Empty;
90
91
[ProfileProperty]
92
[ProfilePropertyAddGet(@"Console.WriteLine(""获取了Age"")")]
93
[ProfilePropertyAddGet("return Current._age")]
94
[ProfilePropertyAddSet(@"Console.WriteLine(""设置了Age"")")]
95
[ProfilePropertyAddSet("Current._age = value")]
96
int _age;
97
}
98
```
99
100
#### 设置初始值
101
102
```csharp
103
partial class SystemProfile
104
{
105
[ProfileProperty]
106
string name = "John Wick";
107
108
[ProfileProperty]
109
int _age = 59;
110
}
111
```
112
113
#### 为属性添加注释
114
115
```csharp
116
partial class SystemProfile
117
{
118
/// <summary>
119
/// 名称
120
/// 这段注释会自动添加至自动生成的Name属性上
121
/// </summary>
122
[ProfileProperty]
123
string name;
124
125
[ProfileProperty]
126
int _age;
127
}
128
```
129
130
#### 使用部分方法来设置get和set方法
131
132
```csharp
133
partial class SystemProfile
134
{
135
[ProfileProperty]
136
string name;
137
138
[ProfileProperty]
139
int _age;
140
141
static partial void GetNameProperty()
142
{
143
Console.WriteLine("获取了Name");
144
}
145
146
static partial void SetNameProperty(string value)
147
{
148
Console.WriteLine($"设置了Name:从{Name}变为了{value}");
149
}
150
151
static partial void GetAgeProperty()
152
{
153
Console.WriteLine("获取了Age");
154
}
155
156
static partial void SetAgeProperty(int value)
157
{
158
Console.WriteLine($"设置了Age:从{Age}变为了{value}");
159
}
160
}
161
```
162
163
164
21
## 使用LANDeviceDetector来检测本地局域网内的所有设备
165
22
166
23
#### 基础用法
@@ -305,27 +158,6 @@ memorableXFEChatGPT.AskChatGPT("新的对话ID", Guid.NewGuid().ToString(), askC
305
158
306
159
---
307
160
308
## 自动生成实现类
309
310
```csharp
311
[CreateImpl]
312
abstract class TestAbstractClass(int num)
313
{
314
public int Num { get; set; } = num;
315
}
316
317
class Program
318
{
319
static void Main(string[] args)
320
{
321
var testAbstractClass = new TestAbstractClassImpl(123);
322
Console.WriteLine(testAbstractClass.Num);
323
}
324
}
325
```
326
327
328
161
## IO流拓展操作示例
329
162
330
163
```csharp
@@ -1,67 +0,0 @@
1
using Microsoft.CodeAnalysis;
2
using Microsoft.CodeAnalysis.CodeActions;
3
using Microsoft.CodeAnalysis.CodeFixes;
4
using Microsoft.CodeAnalysis.CSharp;
5
using Microsoft.CodeAnalysis.CSharp.Syntax;
6
using Microsoft.CodeAnalysis.Text;
7
using System;
8
using System.Collections.Generic;
9
using System.Collections.Immutable;
10
using System.Linq;
11
using System.Runtime.InteropServices;
12
using System.Text;
13
using System.Threading.Tasks;
14
using XFEExtension.NetCore.Analyzer.Diagnostics;
15
using XFEExtension.NetCore.Analyzer.Generator;
16
17
namespace XFEExtension.NetCore.Analyzer.CodeFix
18
{
19
[ExportCodeFixProvider(LanguageNames.CSharp, Name = nameof(ProfileExtensionCodeFixProvider))]
20
public class ProfileExtensionCodeFixProvider : CodeFixProvider
21
{
22
public override ImmutableArray<string> FixableDiagnosticIds => ImmutableArray.Create(ProfileExtensionDiagnostics.AddGetNoResultErrorId, ProfileExtensionDiagnostics.AddSetNoSetResultWarningId);
23
24
public override FixAllProvider GetFixAllProvider() => WellKnownFixAllProviders.BatchFixer;
25
26
public override Task RegisterCodeFixesAsync(CodeFixContext context)
27
{
28
foreach (var diagnostic in context.Diagnostics)
29
{
30
if (diagnostic.Id == ProfileExtensionDiagnostics.AddGetNoResultErrorId)
31
{
32
context.RegisterCodeFix(CodeAction.Create(title: "添加返回值方法",
33
createChangedDocument: c => AddReturnFuncAsync(context.Document, diagnostic.Location.SourceSpan, c),
34
equivalenceKey: "添加返回值"),
35
diagnostic: diagnostic);
36
}
37
else if (diagnostic.Id == ProfileExtensionDiagnostics.AddSetNoSetResultWarningId)
38
{
39
context.RegisterCodeFix(CodeAction.Create(title: "添加字段的设置方法",
40
createChangedDocument: c => AddSetFuncAsync(context.Document, diagnostic.Location.SourceSpan, c),
41
equivalenceKey: "添加字段的设置方法"),
42
diagnostic: diagnostic);
43
}
44
}
45
return Task.CompletedTask;
46
}
47
private async Task<Document> AddReturnFuncAsync(Document document, TextSpan sourceSpan, System.Threading.CancellationToken c)
48
{
49
var root = await document.GetSyntaxRootAsync(c);
50
var fieldDeclaration = root.FindToken(sourceSpan.Start).Parent.AncestorsAndSelf().OfType<FieldDeclarationSyntax>().First();
51
var fieldName = fieldDeclaration.Declaration.Variables.First().Identifier.ValueText;
52
var newAttribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName("ProfilePropertyAddGet")).AddArgumentListArguments(SyntaxFactory.AttributeArgument(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal($"return Current.{fieldName}"))));
53
var newRoot = root.ReplaceNode(fieldDeclaration, fieldDeclaration.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(newAttribute))));
54
return document.WithSyntaxRoot(newRoot);
55
}
56
57
private async Task<Document> AddSetFuncAsync(Document document, TextSpan sourceSpan, System.Threading.CancellationToken c)
58
{
59
var root = await document.GetSyntaxRootAsync(c);
60
var fieldDeclaration = root.FindToken(sourceSpan.Start).Parent.AncestorsAndSelf().OfType<FieldDeclarationSyntax>().First();
61
var fieldName = fieldDeclaration.Declaration.Variables.First().Identifier.ValueText;
62
var newAttribute = SyntaxFactory.Attribute(SyntaxFactory.ParseName("ProfilePropertyAddSet")).AddArgumentListArguments(SyntaxFactory.AttributeArgument(SyntaxFactory.LiteralExpression(SyntaxKind.StringLiteralExpression, SyntaxFactory.Literal($"Current.{fieldName} = value"))));
63
var newRoot = root.ReplaceNode(fieldDeclaration, fieldDeclaration.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(newAttribute))));
64
return document.WithSyntaxRoot(newRoot);
65
}
66
}
67
}
@@ -1,127 +0,0 @@
1
using Microsoft.CodeAnalysis;
2
using Microsoft.CodeAnalysis.CSharp;
3
using Microsoft.CodeAnalysis.CSharp.Syntax;
4
using Microsoft.CodeAnalysis.Diagnostics;
5
using System.Collections.Immutable;
6
using System.Linq;
7
using System.Text.RegularExpressions;
8
using XFEExtension.NetCore.Analyzer.Generator;
9
namespace XFEExtension.NetCore.Analyzer.Diagnostics
10
{
11
[DiagnosticAnalyzer(LanguageNames.CSharp)]
12
public class ProfileExtensionDiagnostics : DiagnosticAnalyzer
13
{
14
public const string AddGetNoResultErrorId = "XFE0002";
15
public const string AddSetNoSetResultWarningId = "XFW0001";
16
17
public static readonly DiagnosticDescriptor AddGetNoResultError = new DiagnosticDescriptor(AddGetNoResultErrorId,
18
"Get方法没有返回值",
19
"设置了自定义的Get方法但是没有返回值:'{0}'",
20
"XFEExtension.NetCore.Analyzer.Diagnostics",
21
DiagnosticSeverity.Error,
22
true,
23
"设置了自定义的Get方法但是没有返回值.",
24
"https://www.xfegzs.com/codespace/diagnostics/XFE0002.html");
25
26
public static readonly DiagnosticDescriptor AddSetNoSetResultWarning = new DiagnosticDescriptor(AddSetNoSetResultWarningId,
27
"Set方法没有设置值",
28
"设置了自定义的Set方法但是没有对实际字段进行操作:'{0}'",
29
"XFEExtension.NetCore.Analyzer.Diagnostics",
30
DiagnosticSeverity.Warning,
31
true,
32
"设置了自定义的Set方法但是没有对实际字段进行操作.",
33
"https://www.xfegzs.com/codespace/diagnostics/XFW0001.html");
34
35
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics => ImmutableArray.Create(AddGetNoResultError, AddSetNoSetResultWarning);
36
37
public override void Initialize(AnalysisContext context)
38
{
39
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
40
context.EnableConcurrentExecution();
41
context.RegisterSyntaxNodeAction(ProfileExtensionAnalyzer, SyntaxKind.Attribute);
42
}
43
public void ProfileExtensionAnalyzer(SyntaxNodeAnalysisContext context)
44
{
45
foreach (var syntaxTree in context.Compilation.SyntaxTrees)
46
{
47
var root = syntaxTree.GetRoot();
48
foreach (var classDeclaration in root.DescendantNodes().OfType<ClassDeclarationSyntax>())
49
{
50
foreach (var fieldDeclaration in ProfilePropertyAutoGenerator.GetFieldDeclarations(classDeclaration))
51
{
52
if (fieldDeclaration.AttributeLists.Any(ProfilePropertyAutoGenerator.IsProfilePropertyAddGetAttribute))
53
{
54
var getAttributeHasResult = false;
55
var attributeSyntaxList = ProfilePropertyAutoGenerator.GetProfilePropertyAddGetAttributeList(fieldDeclaration);
56
foreach (var attributeSyntax in attributeSyntaxList)
57
{
58
if (attributeSyntax.ArgumentList is null)
59
{
60
continue;
61
}
62
var argument = attributeSyntax.ArgumentList.Arguments.First();
63
var funcText = string.Empty;
64
if (argument.Expression is LiteralExpressionSyntax)
65
{
66
funcText = argument.Expression.GetText().ToString();
67
}
68
else if (argument.Expression is InterpolatedStringExpressionSyntax)
69
{
70
funcText = argument.Expression.GetText().ToString();
71
}
72
else if (argument.Expression is InvocationExpressionSyntax)
73
{
74
funcText = argument.Expression.GetText().ToString();
75
}
76
if (funcText.Contains("return"))
77
{
78
getAttributeHasResult = true;
79
}
80
}
81
if (!getAttributeHasResult)
82
{
83
var diagnostic = Diagnostic.Create(AddGetNoResultError, attributeSyntaxList.Last().GetLocation(), fieldDeclaration.Declaration.Variables.First().Identifier.ValueText);
84
context.ReportDiagnostic(diagnostic);
85
}
86
}
87
if (fieldDeclaration.AttributeLists.Any(ProfilePropertyAutoGenerator.IsProfilePropertyAddSetAttribute))
88
{
89
var setAttributeSetResult = false;
90
var attributeSyntaxList = ProfilePropertyAutoGenerator.GetProfilePropertyAddSetAttributeList(fieldDeclaration);
91
foreach (var attributeSyntax in attributeSyntaxList)
92
{
93
if (attributeSyntax.ArgumentList is null)
94
{
95
continue;
96
}
97
var argument = attributeSyntax.ArgumentList.Arguments.First();
98
var funcText = string.Empty;
99
if (argument.Expression is LiteralExpressionSyntax)
100
{
101
funcText = argument.Expression.GetText().ToString();
102
}
103
else if (argument.Expression is InterpolatedStringExpressionSyntax)
104
{
105
funcText = argument.Expression.GetText().ToString();
106
}
107
else if (argument.Expression is InvocationExpressionSyntax)
108
{
109
funcText = argument.Expression.GetText().ToString();
110
}
111
if (Regex.IsMatch(funcText, $@"{fieldDeclaration.Declaration.Variables.First().Identifier.ValueText}\s*=\s*value"))
112
{
113
setAttributeSetResult = true;
114
}
115
}
116
if (!setAttributeSetResult)
117
{
118
var diagnostic = Diagnostic.Create(AddSetNoSetResultWarning, attributeSyntaxList.Last().GetLocation(), fieldDeclaration.Declaration.Variables.First().Identifier.ValueText);
119
context.ReportDiagnostic(diagnostic);
120
}
121
}
122
}
123
}
124
}
125
}
126
}
127
}
@@ -1,84 +0,0 @@
1
using Microsoft.CodeAnalysis;
2
using Microsoft.CodeAnalysis.CSharp;
3
using Microsoft.CodeAnalysis.Diagnostics;
4
using System;
5
using System.Collections.Immutable;
6
using System.Linq;
7
using System.Text.RegularExpressions;
8
9
namespace XFEExtension.NetCore.Analyzer.Diagnostics
10
{
11
[DiagnosticAnalyzer(LanguageNames.CSharp)]
12
public class TodoCommentAnalyzerDiagnostics : DiagnosticAnalyzer
13
{
14
public const string TodoCommentId = "TODO";
15
16
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
17
{
18
get
19
{
20
var descriptor = new DiagnosticDescriptor(TodoCommentId,
21
"TODO��������",
22
"��������{0}",
23
"XFEExtension.NetCore.Analyzer.Diagnostics",
24
GetSeverityFromInt(GeneratorOptions.TodoListWarningLevel),
25
true,
26
"TODO�Ĵ�������.",
27
"https://www.xfegzs.com/codespace/diagnostics/TODO.html");
28
return ImmutableArray.Create(descriptor);
29
}
30
}
31
32
public override void Initialize(AnalysisContext context)
33
{
34
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
35
context.EnableConcurrentExecution();
36
context.RegisterSyntaxTreeAction(AnalyzeSyntaxTree);
37
}
38
39
private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
40
{
41
if (!GeneratorOptions.TodoList)
42
return;
43
var root = context.Tree.GetRoot(context.CancellationToken);
44
var todoComments = root.DescendantTrivia().Where(trivia => trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) && trivia.ToString().Contains("TODO:"));
45
foreach (var todoComment in todoComments)
46
{
47
var match = Regex.Match(todoComment.ToString(), @"//TODO:\s*(\d)?\s*(.*)");
48
if (match.Success)
49
{
50
var level = match.Groups[1].Value != "" ? int.Parse(match.Groups[1].Value) : GeneratorOptions.TodoListWarningLevel;
51
var task = match.Groups[2].Value;
52
53
var descriptor = new DiagnosticDescriptor(TodoCommentId,
54
"TODO��������",
55
"��������{0}",
56
"XFEExtension.NetCore.Analyzer.Diagnostics",
57
GetSeverityFromInt(level),
58
true,
59
"TODO�Ĵ�������.",
60
"https://www.xfegzs.com/codespace/diagnostics/TODO.html");
61
var diagnostic = Diagnostic.Create(descriptor, todoComment.GetLocation(), task);
62
context.ReportDiagnostic(diagnostic);
63
}
64
}
65
}
66
67
private static DiagnosticSeverity GetSeverityFromInt(int level)
68
{
69
switch (level)
70
{
71
case 0:
72
return DiagnosticSeverity.Hidden;
73
case 1:
74
return DiagnosticSeverity.Info;
75
case 2:
76
return DiagnosticSeverity.Warning;
77
case 3:
78
return DiagnosticSeverity.Error;
79
default:
80
return DiagnosticSeverity.Warning;
81
}
82
}
83
}
84
}
@@ -1,23 +0,0 @@
1
using Microsoft.CodeAnalysis;
2
using Microsoft.CodeAnalysis.CSharp.Syntax;
3
using System.Collections.Generic;
4
using System.Linq;
5
6
namespace XFEExtension.NetCore.Analyzer.Generator
7
{
8
public class AutoPathSyntaxReceiver : ISyntaxReceiver
9
{
10
public List<FieldDeclarationSyntax> CandidateFields { get; } = new List<FieldDeclarationSyntax>();
11
12
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
13
{
14
if (syntaxNode is FieldDeclarationSyntax fieldDeclarationSyntax)
15
{
16
if (fieldDeclarationSyntax.AttributeLists.Any(PathPropertyAutoGenerator.IsAutoPathAttribute))
17
{
18
CandidateFields.Add(fieldDeclarationSyntax);
19
}
20
}
21
}
22
}
23
}
@@ -1,182 +0,0 @@
1
using Microsoft.CodeAnalysis;
2
using Microsoft.CodeAnalysis.CSharp;
3
using Microsoft.CodeAnalysis.CSharp.Syntax;
4
using System.Collections.Generic;
5
using System.Linq;
6
7
namespace XFEExtension.NetCore.Analyzer.Generator
8
{
9
[Generator]
10
public class PathPropertyAutoGenerator : ISourceGenerator
11
{
12
public void Initialize(GeneratorInitializationContext context)
13
{
14
context.RegisterForSyntaxNotifications(() => new AutoPathSyntaxReceiver());
15
}
16
17
public void Execute(GeneratorExecutionContext context)
18
{
19
if(!GeneratorOptions.AutoPath)
20
return;
21
if (!(context.SyntaxReceiver is AutoPathSyntaxReceiver receiver))
22
return;
23
var syntaxTrees = context.Compilation.SyntaxTrees;
24
foreach (var syntaxTree in syntaxTrees)
25
{
26
var root = syntaxTree.GetRoot();
27
var classDeclarations = GetClassDeclarations(root);
28
var fileScopedNamespaceDeclarationSyntax = GetFileScopedNamespaceDeclaration(root);
29
foreach (var classDeclaration in classDeclarations)
30
{
31
var fieldDeclarationSyntaxes = GetFieldDeclarations(classDeclaration);
32
if (fieldDeclarationSyntaxes is null || !fieldDeclarationSyntaxes.Any())
33
{
34
continue;
35
}
36
var className = classDeclaration.Identifier.ValueText;
37
var properties = new List<PropertyDeclarationSyntax>();
38
var methods = new List<MethodDeclarationSyntax>();
39
var enableCheckProperties = new List<PropertyDeclarationSyntax>();
40
foreach (var fieldDeclarationSyntax in fieldDeclarationSyntaxes)
41
{
42
var variableDeclaration = fieldDeclarationSyntax.Declaration.Variables.First();
43
var fieldName = variableDeclaration.Identifier.Text;
44
var propertyName = fieldName[0] == '_' ? fieldName[1].ToString().ToUpper() + fieldName.Substring(2) : fieldName[0].ToString().ToUpper() + fieldName.Substring(1);
45
var getMethodName = $"Get{propertyName}Property";
46
var enableCheckPropertyName = $"{propertyName}EnableCheck";
47
GetAutoPathAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
48
{
49
if (attribute.ArgumentList is null)
50
{
51
return;
52
}
53
var argument = attribute.ArgumentList.Arguments.First();
54
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
55
{
56
propertyName = literalExpressionSyntax.Token.ValueText;
57
}
58
});
59
var propertyType = fieldDeclarationSyntax.Declaration.Type;
60
var triviaText = $@"/// <inheritdoc cref=""{fieldName}""/>
61
/// <remarks>
62
/// <seealso cref=""{propertyName}""/> 是根据 <seealso cref=""{fieldName}""/> 自动生成的路径属性<br/><br/>
63
/// </remarks>
64
";
65
var checkEnableTriviaText = $@"/// <summary>
66
/// 是否为 <seealso cref=""{fieldName}""/> 启用检测路径<br/><br/>
67
/// </summary>
68
";
69
var property = SyntaxFactory.PropertyDeclaration(propertyType, propertyName)
70
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
71
.WithAccessorList(SyntaxFactory.AccessorList(
72
SyntaxFactory.List(new[]
73
{
74
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
75
.WithBody(SyntaxFactory.Block(
76
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"Options ??= new {className}()")),
77
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"global::XFEExtension.NetCore.PathExtension.XFEAutoPath.CheckPathExistAndCreate({fieldName}, Options.{enableCheckPropertyName})")),
78
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{getMethodName}()")),
79
SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression($"{fieldName}"))))
80
})))
81
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText));
82
var enableCheckProperty = SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName("bool"), enableCheckPropertyName)
83
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword)))
84
.WithAccessorList(SyntaxFactory.AccessorList(
85
SyntaxFactory.List(new[]
86
{
87
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
88
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
89
})))
90
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(checkEnableTriviaText))
91
.WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("true")))
92
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
93
var getMethod = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), getMethodName)
94
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)))
95
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
96
properties.Add(property.NormalizeWhitespace());
97
methods.Add(getMethod);
98
enableCheckProperties.Add(enableCheckProperty.NormalizeWhitespace());
99
}
100
var profileClassSyntaxTree = GeneratePathClassSyntaxTree(classDeclaration, properties, enableCheckProperties, methods, fileScopedNamespaceDeclarationSyntax);
101
context.AddSource($"{className}.g.cs", profileClassSyntaxTree.ToString());
102
}
103
}
104
}
105
106
public static bool IsAutoPathAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "AutoPath");
107
108
public static List<AttributeSyntax> GetAutoPathAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsAutoPathAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
109
110
public static FileScopedNamespaceDeclarationSyntax GetFileScopedNamespaceDeclaration(SyntaxNode rootNode)
111
{
112
var namespaceResults = rootNode.DescendantNodes().OfType<FileScopedNamespaceDeclarationSyntax>();
113
if (namespaceResults != null && namespaceResults.Count() > 0)
114
return namespaceResults.First();
115
return null;
116
}
117
118
public static IEnumerable<FieldDeclarationSyntax> GetFieldDeclarations(ClassDeclarationSyntax classDeclaration) => classDeclaration.DescendantNodes()
119
.OfType<FieldDeclarationSyntax>()
120
.Where(fieldDeclarationSyntax => fieldDeclarationSyntax.AttributeLists.Any(IsAutoPathAttribute) && fieldDeclarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword));
121
122
public static IEnumerable<ClassDeclarationSyntax> GetClassDeclarations(SyntaxNode rootNode) => rootNode.DescendantNodes()
123
.OfType<ClassDeclarationSyntax>()
124
.Where(classDeclaration => classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword));
125
126
private static SyntaxTree GeneratePathClassSyntaxTree(ClassDeclarationSyntax classDeclaration, List<PropertyDeclarationSyntax> propertyDeclarationSyntaxes, List<PropertyDeclarationSyntax> enableCheckDeclarationSyntaxes, List<MethodDeclarationSyntax> methodDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax)
127
{
128
var className = classDeclaration.Identifier.ValueText;
129
var triviaText = $@"/// <remarks>
130
/// <code><seealso cref=""{className}""/> 已生成以下路径:</code><br/>
131
/// <code>
132
";
133
triviaText += string.Join("<br/>\n", propertyDeclarationSyntaxes.Select(propertyDeclarationSyntax => $"/// ○ <seealso cref=\"{propertyDeclarationSyntax.Identifier}\"/>")) + "\n/// </code><br/>\n/// <code>来自<seealso cref=\"global::XFEExtension.NetCore.PathExtension\"/></code>\n/// </remarks>\n";
134
var memberDeclarations = new List<MemberDeclarationSyntax>()
135
{
136
SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(className), "Options")
137
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
138
.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Attribute(SyntaxFactory.ParseName("global::XFEExtension.NetCore.ProfileExtension.ProfileInstanceAttribute")))))
139
.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(
140
new[]
141
{
142
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
143
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
144
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
145
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
146
})))
147
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
148
/// 配置选项<br/>
149
/// <seealso cref=""Options""/> 是 <seealso cref=""{className}""/> 类的配置选项
150
/// </summary>
151
"))
152
};
153
memberDeclarations.AddRange(propertyDeclarationSyntaxes);
154
memberDeclarations.AddRange(methodDeclarationSyntaxes);
155
memberDeclarations.AddRange(enableCheckDeclarationSyntaxes);
156
var pathClass = SyntaxFactory.ClassDeclaration(className)
157
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword))
158
.AddMembers(memberDeclarations.ToArray())
159
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText))
160
.NormalizeWhitespace();
161
MemberDeclarationSyntax memberDeclaration;
162
if (fileScopedNamespaceDeclarationSyntax is null)
163
{
164
var namespaceDeclaration = classDeclaration.FirstAncestorOrSelf<NamespaceDeclarationSyntax>();
165
if (namespaceDeclaration is null)
166
memberDeclaration = pathClass;
167
else
168
memberDeclaration = SyntaxFactory.NamespaceDeclaration(namespaceDeclaration.Name)
169
.AddMembers(pathClass);
170
}
171
else
172
{
173
memberDeclaration = SyntaxFactory.FileScopedNamespaceDeclaration(fileScopedNamespaceDeclarationSyntax.Name)
174
.AddMembers(pathClass);
175
}
176
var profileClassCompilationUnit = SyntaxFactory.CompilationUnit()
177
.AddMembers(memberDeclaration)
178
.NormalizeWhitespace();
179
return SyntaxFactory.SyntaxTree(profileClassCompilationUnit);
180
}
181
}
182
}
@@ -1,296 +0,0 @@
1
using Microsoft.CodeAnalysis;
2
using Microsoft.CodeAnalysis.CSharp;
3
using Microsoft.CodeAnalysis.CSharp.Syntax;
4
using System.Collections.Generic;
5
using System.Linq;
6
7
namespace XFEExtension.NetCore.Analyzer.Generator
8
{
9
[Generator]
10
public class ProfilePropertyAutoGenerator : ISourceGenerator
11
{
12
public void Initialize(GeneratorInitializationContext context)
13
{
14
context.RegisterForSyntaxNotifications(() => new ProfilePropertySyntaxReceiver());
15
}
16
17
public void Execute(GeneratorExecutionContext context)
18
{
19
GeneratorOptions.GetOptions(context);
20
if (!GeneratorOptions.AutoProfile)
21
return;
22
var syntaxTrees = context.Compilation.SyntaxTrees;
23
foreach (var syntaxTree in syntaxTrees)
24
{
25
var root = syntaxTree.GetRoot();
26
var classDeclarations = GetClassDeclarations(root);
27
var usingDirectives = root.DescendantNodes().OfType<UsingDirectiveSyntax>().ToArray();
28
var fileScopedNamespaceDeclarationSyntax = GetFileScopedNamespaceDeclaration(root);
29
foreach (var classDeclaration in classDeclarations)
30
{
31
var fieldDeclarationSyntaxes = GetFieldDeclarations(classDeclaration);
32
if (fieldDeclarationSyntaxes is null || !fieldDeclarationSyntaxes.Any())
33
{
34
continue;
35
}
36
var className = classDeclaration.Identifier.ValueText;
37
var attributeSyntax = SyntaxFactory.AttributeList(
38
SyntaxFactory.SingletonSeparatedList(
39
SyntaxFactory.Attribute(SyntaxFactory.ParseName("global::XFEExtension.NetCore.ProfileExtension.ProfileFieldAutoGenerateAttribute"))));
40
var properties = new List<PropertyDeclarationSyntax>();
41
var methods = new List<MethodDeclarationSyntax>();
42
foreach (var fieldDeclarationSyntax in fieldDeclarationSyntaxes)
43
{
44
var variableDeclaration = fieldDeclarationSyntax.Declaration.Variables.First();
45
var fieldName = variableDeclaration.Identifier.Text;
46
var propertyName = fieldName[0] == '_' ? fieldName[1].ToString().ToUpper() + fieldName.Substring(2) : fieldName[0].ToString().ToUpper() + fieldName.Substring(1);
47
var getMethodName = $"Get{propertyName}Property";
48
var setMethodName = $"Set{propertyName}Property";
49
GetProfilePropertyAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
50
{
51
if (attribute.ArgumentList is null)
52
{
53
return;
54
}
55
var argument = attribute.ArgumentList.Arguments.First();
56
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
57
{
58
propertyName = literalExpressionSyntax.Token.ValueText;
59
}
60
});
61
var propertyType = fieldDeclarationSyntax.Declaration.Type;
62
#region Trivia头
63
var triviaText = $@"/// <inheritdoc cref=""{fieldName}""/>
64
/// <remarks>
65
/// <seealso cref=""{propertyName}""/> 是根据 <seealso cref=""{fieldName}""/> 自动生成的属性<br/><br/>
66
/// <code><seealso langword=""get""/>方法已生成以下代码: ○ <seealso cref=""{className}.{getMethodName}()""/>;<br/>";
67
#endregion
68
var getExpressionStatements = new List<StatementSyntax>()
69
{
70
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{getMethodName}()")).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
71
};
72
if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddGetAttribute))
73
{
74
GetProfilePropertyAddGetAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
75
{
76
if (attribute.ArgumentList is null)
77
{
78
return;
79
}
80
var argument = attribute.ArgumentList.Arguments.First();
81
var funcText = string.Empty;
82
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
83
funcText = literalExpressionSyntax.Token.ValueText;
84
if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax)
85
funcText = interpolatedStringExpressionSyntax.Contents.ToString();
86
if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax)
87
funcText = invocationExpressionSyntax.GetText().ToString();
88
getExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
89
#region Get方法注释
90
triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "<br/>").Replace("return", "<seealso langword=\"return\"/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>")};<br/>";
91
#endregion
92
});
93
}
94
else
95
{
96
getExpressionStatements.Add(SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression($"Current.{fieldName}")));
97
#region Get方默认注释
98
triviaText += $@"
99
/// ○ <seealso langword=""return""/> <seealso langword=""{fieldName}""/>;";
100
#endregion
101
}
102
#region Get方法尾及Set方法头注释
103
triviaText += $@"
104
/// </code>
105
/// <br/>
106
/// <code><seealso langword=""set""/>方法已生成以下代码: ○ <seealso cref=""{className}.{setMethodName}({propertyType})""/>;<br/>";
107
#endregion
108
var setExpressionStatements = new List<StatementSyntax>()
109
{
110
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{setMethodName}(value)")).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
111
};
112
if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddSetAttribute))
113
{
114
GetProfilePropertyAddSetAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
115
{
116
if (attribute.ArgumentList is null)
117
{
118
return;
119
}
120
var argument = attribute.ArgumentList.Arguments.First();
121
var funcText = string.Empty;
122
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
123
funcText = literalExpressionSyntax.Token.ValueText;
124
else if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax)
125
funcText = interpolatedStringExpressionSyntax.Contents.ToString();
126
else if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax)
127
funcText = invocationExpressionSyntax.GetText().ToString();
128
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)).WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)));
129
#region Set方法注释
130
triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "<br/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>").Replace("value", "<seealso langword=\"value\"/>")};<br/>";
131
#endregion
132
});
133
}
134
else
135
{
136
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"Current.{fieldName} = value")));
137
#region Set方法默认注释
138
triviaText += $@"
139
/// ○ <seealso langword=""{fieldName}""/> = <seealso langword=""value""/>;<br/>";
140
#endregion
141
}
142
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"global::XFEExtension.NetCore.ProfileExtension.XFEProfile.SaveProfile(typeof({className}))")));
143
#region Set方法中的保存方法的注释
144
triviaText += $@"
145
/// ○ <seealso cref=""global::XFEExtension.NetCore.ProfileExtension.XFEProfile.SaveProfile(ProfileInfo)""/>";
146
#endregion
147
#region Trivia尾
148
triviaText += @"
149
/// </code>
150
/// </remarks>
151
";
152
#endregion
153
var property = SyntaxFactory.PropertyDeclaration(propertyType, propertyName)
154
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
155
.AddAttributeLists(attributeSyntax)
156
.WithAccessorList(SyntaxFactory.AccessorList(
157
SyntaxFactory.List(new[]
158
{
159
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
160
.WithBody(SyntaxFactory.Block(getExpressionStatements)),
161
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
162
.WithBody(SyntaxFactory.Block(setExpressionStatements))
163
})))
164
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText));
165
var getMethod = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), getMethodName)
166
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)))
167
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
168
var setMethod = SyntaxFactory.MethodDeclaration(SyntaxFactory.ParseTypeName("void"), setMethodName)
169
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.StaticKeyword), SyntaxFactory.Token(SyntaxKind.PartialKeyword)))
170
.AddParameterListParameters(SyntaxFactory.Parameter(SyntaxFactory.Identifier("value")).WithType(propertyType))
171
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken));
172
methods.Add(getMethod);
173
methods.Add(setMethod);
174
properties.Add(property.NormalizeWhitespace());
175
}
176
var profileClassSyntaxTree = GenerateProfileClassSyntaxTree(classDeclaration, usingDirectives, properties, methods, fileScopedNamespaceDeclarationSyntax);
177
context.AddSource($"{className}.g.cs", profileClassSyntaxTree.ToString());
178
}
179
}
180
}
181
182
public static bool IsProfilePropertyAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfileProperty");
183
184
public static List<AttributeSyntax> GetProfilePropertyAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsProfilePropertyAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
185
186
public static bool IsAutoLoadProfileAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "AutoLoadProfile");
187
188
public static List<AttributeSyntax> GetAutoLoadProfileAttribute(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsAutoLoadProfileAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
189
190
public static bool IsProfilePropertyAddGetAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfilePropertyAddGet");
191
192
public static List<AttributeSyntax> GetProfilePropertyAddGetAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsProfilePropertyAddGetAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
193
194
public static bool IsProfilePropertyAddSetAttribute(AttributeListSyntax attributeList) => attributeList.Attributes.Any(attribute => attribute.Name.ToString() == "ProfilePropertyAddSet");
195
196
public static List<AttributeSyntax> GetProfilePropertyAddSetAttributeList(FieldDeclarationSyntax fieldDeclaration) => fieldDeclaration.AttributeLists.Where(IsProfilePropertyAddSetAttribute).SelectMany(attributeList => attributeList.Attributes).ToList();
197
198
public static FileScopedNamespaceDeclarationSyntax GetFileScopedNamespaceDeclaration(SyntaxNode rootNode)
199
{
200
var namespaceResults = rootNode.DescendantNodes().OfType<FileScopedNamespaceDeclarationSyntax>();
201
if (namespaceResults != null && namespaceResults.Count() > 0)
202
return namespaceResults.First();
203
return null;
204
}
205
206
public static IEnumerable<FieldDeclarationSyntax> GetFieldDeclarations(ClassDeclarationSyntax classDeclaration) => classDeclaration.DescendantNodes()
207
.OfType<FieldDeclarationSyntax>()
208
.Where(fieldDeclarationSyntax => fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAttribute) && !fieldDeclarationSyntax.Modifiers.Any(SyntaxKind.StaticKeyword));
209
210
public static IEnumerable<ClassDeclarationSyntax> GetClassDeclarations(SyntaxNode rootNode) => rootNode.DescendantNodes()
211
.OfType<ClassDeclarationSyntax>()
212
.Where(classDeclaration => classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword) && !classDeclaration.Modifiers.Any(SyntaxKind.StaticKeyword));
213
214
private static SyntaxTree GenerateProfileClassSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, List<PropertyDeclarationSyntax> propertyDeclarationSyntaxes, List<MethodDeclarationSyntax> methodDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax)
215
{
216
var className = classDeclaration.Identifier.ValueText;
217
var triviaText = $@"/// <remarks>
218
/// <code><seealso cref=""{className}""/> 已自动实现以下属性:</code><br/>
219
/// <code>
220
";
221
triviaText += string.Join("<br/>\n", propertyDeclarationSyntaxes.Select(propertyDeclarationSyntax => $"/// ○ <seealso cref=\"{propertyDeclarationSyntax.Identifier}\"/>")) + "\n/// </code><br/>\n/// <code>来自<seealso cref=\"global::XFEExtension.NetCore.ProfileExtension.XFEProfile\"/></code>\n/// </remarks>\n";
222
var memberDeclarations = new List<MemberDeclarationSyntax>
223
{
224
SyntaxFactory.PropertyDeclaration(SyntaxFactory.ParseTypeName(className), "Current")
225
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
226
.AddAttributeLists(SyntaxFactory.AttributeList(SyntaxFactory.SingletonSeparatedList(SyntaxFactory.Attribute(SyntaxFactory.ParseName("global::XFEExtension.NetCore.ProfileExtension.ProfileInstanceAttribute")))))
227
.WithAccessorList(SyntaxFactory.AccessorList(SyntaxFactory.List(
228
new[]
229
{
230
SyntaxFactory.AccessorDeclaration(SyntaxKind.GetAccessorDeclaration)
231
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken)),
232
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
233
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
234
})))
235
.WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression($"new {className}()")))
236
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
237
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
238
/// 该配置文件的实例<br/>
239
/// <seealso cref=""Current""/> 是 <seealso cref=""{className}""/> 配置文件类的实例数据
240
/// </summary>
241
"))
242
};
243
memberDeclarations.AddRange(propertyDeclarationSyntaxes);
244
memberDeclarations.AddRange(methodDeclarationSyntaxes);
245
var staticConstructorSyntax = SyntaxFactory.ConstructorDeclaration(className)
246
.AddModifiers(SyntaxFactory.Token(SyntaxKind.StaticKeyword))
247
.WithBody(SyntaxFactory.Block(
248
SyntaxFactory.ParseStatement($"global::XFEExtension.NetCore.ProfileExtension.XFEProfile.LoadProfiles(typeof({className}));")));
249
if (classDeclaration.AttributeLists.Any(IsAutoLoadProfileAttribute))
250
{
251
var autoLoadProfileAttribute = classDeclaration.AttributeLists.First(attributeList => IsAutoLoadProfileAttribute(attributeList)).Attributes.First();
252
if (autoLoadProfileAttribute.ArgumentList != null)
253
{
254
var argument = autoLoadProfileAttribute.ArgumentList.Arguments.First();
255
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax && literalExpressionSyntax.Token.ValueText == "true")
256
{
257
memberDeclarations.Add(staticConstructorSyntax);
258
}
259
}
260
else
261
{
262
memberDeclarations.Add(staticConstructorSyntax);
263
}
264
}
265
else
266
{
267
memberDeclarations.Add(staticConstructorSyntax);
268
}
269
var profileClass = SyntaxFactory.ClassDeclaration(className)
270
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword))
271
.AddMembers(memberDeclarations.ToArray())
272
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText))
273
.NormalizeWhitespace();
274
MemberDeclarationSyntax memberDeclaration;
275
if (fileScopedNamespaceDeclarationSyntax is null)
276
{
277
var namespaceDeclaration = classDeclaration.FirstAncestorOrSelf<NamespaceDeclarationSyntax>();
278
if (namespaceDeclaration is null)
279
memberDeclaration = profileClass;
280
else
281
memberDeclaration = SyntaxFactory.NamespaceDeclaration(namespaceDeclaration.Name)
282
.AddMembers(profileClass);
283
}
284
else
285
{
286
memberDeclaration = SyntaxFactory.FileScopedNamespaceDeclaration(fileScopedNamespaceDeclarationSyntax.Name)
287
.AddMembers(profileClass);
288
}
289
var profileClassCompilationUnit = SyntaxFactory.CompilationUnit()
290
.AddUsings(usingDirectiveSyntaxes)
291
.AddMembers(memberDeclaration)
292
.NormalizeWhitespace();
293
return SyntaxFactory.SyntaxTree(profileClassCompilationUnit);
294
}
295
}
296
}
@@ -1,23 +0,0 @@
1
using Microsoft.CodeAnalysis;
2
using Microsoft.CodeAnalysis.CSharp.Syntax;
3
using System.Collections.Generic;
4
using System.Linq;
5
6
namespace XFEExtension.NetCore.Analyzer.Generator
7
{
8
public class ProfilePropertySyntaxReceiver : ISyntaxReceiver
9
{
10
public List<FieldDeclarationSyntax> CandidateFields { get; } = new List<FieldDeclarationSyntax>();
11
12
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
13
{
14
if (syntaxNode is FieldDeclarationSyntax fieldDeclarationSyntax)
15
{
16
if (fieldDeclarationSyntax.AttributeLists.Any(ProfilePropertyAutoGenerator.IsProfilePropertyAttribute))
17
{
18
CandidateFields.Add(fieldDeclarationSyntax);
19
}
20
}
21
}
22
}
23
}
@@ -1,27 +0,0 @@
1
using Microsoft.CodeAnalysis;
2
3
namespace XFEExtension.NetCore.Analyzer
4
{
5
public class GeneratorOptions
6
{
7
public static bool AutoProfile { get; set; } = true;
8
public static bool AutoPath { get; set; } = true;
9
public static bool AutoImplement { get; set; } = true;
10
public static bool TodoList { get; set; } = true;
11
public static int TodoListWarningLevel { get; set; } = 2;
12
public static void GetOptions(GeneratorExecutionContext context)
13
{
14
if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AutoProfile", out var autoProfile))
15
AutoProfile = autoProfile.ToLower() == "true";
16
if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AutoPath", out var autoPath))
17
AutoPath = autoPath.ToLower() == "true";
18
if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.AutoImplement", out var autoImplement))
19
AutoImplement = autoImplement.ToLower() == "true";
20
if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.TodoList", out var todoList))
21
TodoList = todoList.ToLower() == "true";
22
if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.TodoListWarningLevel", out var todoListWarningLevel))
23
if (int.TryParse(todoListWarningLevel, out var warningLevel))
24
TodoListWarningLevel = warningLevel;
25
}
26
}
27
}