XFEExtension
【DLL】XFE各类拓展是一个C#的DLL库,旨在优化C#代码中常用语句的使用,并提供更简洁的访问方式,同时提供Xunit测试框架,快速搭建服务器/客户端,免费ChatGPTAPI接口,免费通讯服务器,XFE下载器,新增格式等
关注
0
Fork
0
Star
0
返回提交历史
Modified
XFEExtension.NetCore.Analyzer.Test/Program.cs
+1
-0
Modified
XFEExtension.NetCore.Analyzer.Test/XFEExtension.NetCore.Analyzer.Test.csproj
+3
-0
Modified
XFEExtension.NetCore.Analyzer/AnalyzerReleases.Unshipped.md
+1
-0
Added
XFEExtension.NetCore.Analyzer/Diagnostics/TodoCommentAnalyzerDiagnostics.cs
+59
-0
Added
XFEExtension.NetCore.Analyzer/Generator/AutoPathSyntaxReceiver.cs
+23
-0
Added
XFEExtension.NetCore.Analyzer/Generator/ConstExpressionAutoGenerator.cs
+48
-0
Modified
XFEExtension.NetCore.Analyzer/Generator/ImplementAutoGenerator.cs
+2
-0
Modified
XFEExtension.NetCore.Analyzer/Generator/PathPropertyAutoGenerator.cs
+15
-4
Modified
XFEExtension.NetCore.Analyzer/Generator/ProfilePropertyAutoGenerator.cs
+4
-1
Added
XFEExtension.NetCore.Analyzer/Generator/ProfilePropertySyntaxReceiver.cs
+23
-0
Added
XFEExtension.NetCore.Analyzer/GeneratorOptions.cs
+26
-0
Modified
XFEExtension.NetCore.Analyzer/XFEExtension.NetCore.Analyzer.csproj
+8
-0
XFEstudio/XFEExtension
添加TODO自动检测,添加MSBuild属性
c03824c
代码差异
12 个文件
+213
-5
@@ -6,6 +6,7 @@ internal class Program
6
6
{
7
7
public static void Main(string[] args)
8
8
{
9
//TODO: 编写测试代码
9
10
var testClass = new TestClass("测试名称", "测试描述哈哈", 59)
10
11
{
11
12
Tags = [["123", "321"], ["1234567", "7654321"]],
@@ -5,6 +5,9 @@
5
5
<ImplicitUsings>enable</ImplicitUsings>
6
6
<Nullable>enable</Nullable>
7
7
<OutputType>Exe</OutputType>
8
<AutoPath>false</AutoPath>
9
<TodoListWarningLevel>Info</TodoListWarningLevel>
10
<AutoProfile>false</AutoProfile>
8
11
</PropertyGroup>
9
12
10
13
<ItemGroup>
@@ -5,6 +5,7 @@
5
5
6
6
Rule ID | Category | Severity | Notes
7
7
--------|----------|----------|-------
8
TODO | XFEExtension.NetCore.Analyzer.Diagnostics | `Dynamic` | TodoCommentAnalyzerDiagnostics, [Documentation](https://www.xfegzs.com/codespace/diagnostics/TODO.html)
8
9
XFE0002 | XFEExtension.NetCore.Analyzer.Diagnostics | Error | ProfileExtensionDiagnostics, [Documentation](https://www.xfegzs.com/codespace/diagnostics/XFE0002.html)
9
10
XFE0003 | XFEExtension.NetCore.Analyzer.Diagnostics | Error | ProfileExtensionDiagnostics, [Documentation](https://www.xfegzs.com/codespace/diagnostics/XFE0003.html)
10
11
XFW0001 | XFEExtension.NetCore.Analyzer.Diagnostics | Warning | ProfileExtensionDiagnostics, [Documentation](https://www.xfegzs.com/codespace/diagnostics/XFW0001.html)
@@ -0,0 +1,59 @@
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
8
namespace XFEExtension.NetCore.Analyzer.Diagnostics
9
{
10
[DiagnosticAnalyzer(LanguageNames.CSharp)]
11
public class TodoCommentAnalyzerDiagnostics : DiagnosticAnalyzer
12
{
13
public const string TodoCommentId = "TODO";
14
15
public override ImmutableArray<DiagnosticDescriptor> SupportedDiagnostics
16
{
17
get
18
{
19
var descriptor = new DiagnosticDescriptor(TodoCommentId,
20
"TODO��������",
21
"��������{0}",
22
"XFEExtension.NetCore.Analyzer.Diagnostics",
23
(DiagnosticSeverity)Enum.Parse(typeof(DiagnosticSeverity),GeneratorOptions.TodoListWarningLevel.ToString()),
24
true,
25
"TODO�Ĵ�������.",
26
"https://www.xfegzs.com/codespace/diagnostics/TODO.html");
27
return ImmutableArray.Create(descriptor);
28
}
29
}
30
31
public override void Initialize(AnalysisContext context)
32
{
33
context.ConfigureGeneratedCodeAnalysis(GeneratedCodeAnalysisFlags.Analyze | GeneratedCodeAnalysisFlags.ReportDiagnostics);
34
context.EnableConcurrentExecution();
35
context.RegisterSyntaxTreeAction(AnalyzeSyntaxTree);
36
}
37
38
private void AnalyzeSyntaxTree(SyntaxTreeAnalysisContext context)
39
{
40
if (!GeneratorOptions.EnableTodoList)
41
return;
42
var root = context.Tree.GetRoot(context.CancellationToken);
43
var todoComments = root.DescendantTrivia().Where(trivia => trivia.IsKind(SyntaxKind.SingleLineCommentTrivia) && trivia.ToString().Contains("TODO:"));
44
foreach (var todoComment in todoComments)
45
{
46
var descriptor = new DiagnosticDescriptor(TodoCommentId,
47
"TODO��������",
48
"��������{0}",
49
"XFEExtension.NetCore.Analyzer.Diagnostics",
50
(DiagnosticSeverity)Enum.Parse(typeof(DiagnosticSeverity),GeneratorOptions.TodoListWarningLevel.ToString()),
51
true,
52
"TODO�Ĵ�������.",
53
"https://www.xfegzs.com/codespace/diagnostics/TODO.html");
54
var diagnostic = Diagnostic.Create(descriptor, todoComment.GetLocation(), todoComment.ToString().Replace("//", "").Replace("TODO:", ""));
55
context.ReportDiagnostic(diagnostic);
56
}
57
}
58
}
59
}
@@ -0,0 +1,23 @@
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
}
@@ -0,0 +1,48 @@
1
using Microsoft.CodeAnalysis;
2
using Microsoft.CodeAnalysis.CSharp;
3
using Microsoft.CodeAnalysis.CSharp.Syntax;
4
using Microsoft.CodeAnalysis.Text;
5
using System.Collections.Generic;
6
using System.Linq;
7
using System.Text;
8
9
namespace XFEExtension.NetCore.Analyzer.Generator
10
{
11
[Generator]
12
public class ConstExpressionAutoGenerator : ISourceGenerator
13
{
14
public void Execute(GeneratorExecutionContext context)
15
{
16
if (!(context.SyntaxReceiver is FieldSyntaxReceiver receiver))
17
return;
18
19
foreach (var field in receiver.CandidateFields)
20
{
21
// TODO: 解析字段的初始值,执行方法并获取返回值
22
// 注意:这是一个非常困难的任务,可能需要运行时环境
23
24
// TODO: 在新的部分类中生成一个const常量,其值为方法的返回值
25
}
26
}
27
28
public void Initialize(GeneratorInitializationContext context)
29
{
30
context.RegisterForSyntaxNotifications(() => new FieldSyntaxReceiver());
31
}
32
}
33
34
class FieldSyntaxReceiver : ISyntaxReceiver
35
{
36
public List<FieldDeclarationSyntax> CandidateFields { get; } = new List<FieldDeclarationSyntax>();
37
38
public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
39
{
40
// TODO: 查找带有特定属性的字段
41
if (syntaxNode is FieldDeclarationSyntax fieldDeclarationSyntax
42
&& fieldDeclarationSyntax.AttributeLists.Count > 0)
43
{
44
CandidateFields.Add(fieldDeclarationSyntax);
45
}
46
}
47
}
48
}
@@ -14,6 +14,8 @@ namespace XFEExtension.NetCore.Analyzer.Generator
14
14
15
15
public void Execute(GeneratorExecutionContext context)
16
16
{
17
if (!GeneratorOptions.AutoImplement)
18
return;
17
19
var syntaxTrees = context.Compilation.SyntaxTrees;
18
20
foreach (var syntaxTree in syntaxTrees)
19
21
{
@@ -11,10 +11,15 @@ namespace XFEExtension.NetCore.Analyzer.Generator
11
11
{
12
12
public void Initialize(GeneratorInitializationContext context)
13
13
{
14
context.RegisterForSyntaxNotifications(() => new AutoPathSyntaxReceiver());
14
15
}
15
16
16
17
public void Execute(GeneratorExecutionContext context)
17
18
{
19
if(!GeneratorOptions.AutoPath)
20
return;
21
if (!(context.SyntaxReceiver is AutoPathSyntaxReceiver receiver))
22
return;
18
23
var syntaxTrees = context.Compilation.SyntaxTrees;
19
24
foreach (var syntaxTree in syntaxTrees)
20
25
{
@@ -30,12 +35,14 @@ namespace XFEExtension.NetCore.Analyzer.Generator
30
35
}
31
36
var className = classDeclaration.Identifier.ValueText;
32
37
var properties = new List<PropertyDeclarationSyntax>();
38
var methods = new List<MethodDeclarationSyntax>();
33
39
var enableCheckProperties = new List<PropertyDeclarationSyntax>();
34
40
foreach (var fieldDeclarationSyntax in fieldDeclarationSyntaxes)
35
41
{
36
42
var variableDeclaration = fieldDeclarationSyntax.Declaration.Variables.First();
37
43
var fieldName = variableDeclaration.Identifier.Text;
38
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";
39
46
var enableCheckPropertyName = $"{propertyName}EnableCheck";
40
47
GetAutoPathAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
41
48
{
@@ -68,6 +75,7 @@ namespace XFEExtension.NetCore.Analyzer.Generator
68
75
.WithBody(SyntaxFactory.Block(
69
76
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"Options ??= new {className}()")),
70
77
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"global::XFEExtension.NetCore.PathExtension.XFEAutoPath.CheckPathExistAndCreate({fieldName}, Options.{enableCheckPropertyName})")),
78
SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{getMethodName}()")),
71
79
SyntaxFactory.ReturnStatement(SyntaxFactory.ParseExpression($"{fieldName}"))))
72
80
})))
73
81
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText));
@@ -82,10 +90,14 @@ namespace XFEExtension.NetCore.Analyzer.Generator
82
90
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(checkEnableTriviaText))
83
91
.WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression("true")))
84
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));
85
96
properties.Add(property.NormalizeWhitespace());
97
methods.Add(getMethod);
86
98
enableCheckProperties.Add(enableCheckProperty.NormalizeWhitespace());
87
99
}
88
var profileClassSyntaxTree = GeneratePathClassSyntaxTree(classDeclaration, properties, enableCheckProperties, fileScopedNamespaceDeclarationSyntax);
100
var profileClassSyntaxTree = GeneratePathClassSyntaxTree(classDeclaration, properties, enableCheckProperties, methods, fileScopedNamespaceDeclarationSyntax);
89
101
context.AddSource($"{className}.g.cs", profileClassSyntaxTree.ToString());
90
102
}
91
103
}
@@ -111,7 +123,7 @@ namespace XFEExtension.NetCore.Analyzer.Generator
111
123
.OfType<ClassDeclarationSyntax>()
112
124
.Where(classDeclaration => classDeclaration.Modifiers.Any(SyntaxKind.PartialKeyword));
113
125
114
private static SyntaxTree GeneratePathClassSyntaxTree(ClassDeclarationSyntax classDeclaration, List<PropertyDeclarationSyntax> propertyDeclarationSyntaxes, List<PropertyDeclarationSyntax> enableCheckDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax)
126
private static SyntaxTree GeneratePathClassSyntaxTree(ClassDeclarationSyntax classDeclaration, List<PropertyDeclarationSyntax> propertyDeclarationSyntaxes, List<PropertyDeclarationSyntax> enableCheckDeclarationSyntaxes, List<MethodDeclarationSyntax> methodDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax)
115
127
{
116
128
var className = classDeclaration.Identifier.ValueText;
117
129
var triviaText = $@"/// <remarks>
@@ -132,8 +144,6 @@ namespace XFEExtension.NetCore.Analyzer.Generator
132
144
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
133
145
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
134
146
})))
135
.WithInitializer(SyntaxFactory.EqualsValueClause(SyntaxFactory.ParseExpression($"new {className}()")))
136
.WithSemicolonToken(SyntaxFactory.Token(SyntaxKind.SemicolonToken))
137
147
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia($@"/// <summary>
138
148
/// 配置选项<br/>
139
149
/// <seealso cref=""Options""/> 是 <seealso cref=""{className}""/> 类的配置选项
@@ -141,6 +151,7 @@ namespace XFEExtension.NetCore.Analyzer.Generator
141
151
"))
142
152
};
143
153
memberDeclarations.AddRange(propertyDeclarationSyntaxes);
154
memberDeclarations.AddRange(methodDeclarationSyntaxes);
144
155
memberDeclarations.AddRange(enableCheckDeclarationSyntaxes);
145
156
var pathClass = SyntaxFactory.ClassDeclaration(className)
146
157
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword))
@@ -1,7 +1,6 @@
1
1
using Microsoft.CodeAnalysis;
2
2
using Microsoft.CodeAnalysis.CSharp;
3
3
using Microsoft.CodeAnalysis.CSharp.Syntax;
4
using System;
5
4
using System.Collections.Generic;
6
5
using System.Linq;
7
6
@@ -12,10 +11,14 @@ namespace XFEExtension.NetCore.Analyzer.Generator
12
11
{
13
12
public void Initialize(GeneratorInitializationContext context)
14
13
{
14
context.RegisterForSyntaxNotifications(() => new ProfilePropertySyntaxReceiver());
15
15
}
16
16
17
17
public void Execute(GeneratorExecutionContext context)
18
18
{
19
GeneratorOptions.GetOptions(context);
20
if (!GeneratorOptions.AutoProfile)
21
return;
19
22
var syntaxTrees = context.Compilation.SyntaxTrees;
20
23
foreach (var syntaxTree in syntaxTrees)
21
24
{
@@ -0,0 +1,23 @@
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
}
@@ -0,0 +1,26 @@
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 EnableTodoList { get; set; } = true;
11
public static string TodoListWarningLevel { get; set; } = "Warning";
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.EnableTodoList", out var enableTodoList))
21
EnableTodoList = enableTodoList.ToLower() == "true";
22
if (context.AnalyzerConfigOptions.GlobalOptions.TryGetValue("build_property.TodoListWarningLevel", out var todoListWarningLevel))
23
TodoListWarningLevel = todoListWarningLevel;
24
}
25
}
26
}
@@ -17,4 +17,12 @@
17
17
<PackageReference Include="Microsoft.CodeAnalysis.Workspaces.Common" Version="4.9.2" />
18
18
</ItemGroup>
19
19
20
<ItemGroup>
21
<CompilerVisibleProperty Include="AutoProfile" />
22
<CompilerVisibleProperty Include="AutoPath" />
23
<CompilerVisibleProperty Include="AutoImplement" />
24
<CompilerVisibleProperty Include="EnableTodoList" />
25
<CompilerVisibleProperty Include="TodoListWarningLevel" />
26
</ItemGroup>
27
20
28
</Project>