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

XFEExtension

【DLL】XFE各类拓展是一个C#的DLL库,旨在优化C#代码中常用语句的使用,并提供更简洁的访问方式,同时提供Xunit测试框架,快速搭建服务器/客户端,免费ChatGPTAPI接口,免费通讯服务器,XFE下载器,新增格式等

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

XFEstudio/XFEExtension

添加TODO自动检测,添加MSBuild属性

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

代码差异

12 个文件 +213 -5
Modified XFEExtension.NetCore.Analyzer.Test/Program.cs +1 -0
@@ -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"]],
Modified XFEExtension.NetCore.Analyzer.Test/XFEExtension.NetCore.Analyzer.Test.csproj +3 -0
@@ -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>
Modified XFEExtension.NetCore.Analyzer/AnalyzerReleases.Unshipped.md +1 -0
@@ -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)
Added XFEExtension.NetCore.Analyzer/Diagnostics/TodoCommentAnalyzerDiagnostics.cs +59 -0
@@ -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 }
Added XFEExtension.NetCore.Analyzer/Generator/AutoPathSyntaxReceiver.cs +23 -0
@@ -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 }
Added XFEExtension.NetCore.Analyzer/Generator/ConstExpressionAutoGenerator.cs +48 -0
@@ -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 }
Modified XFEExtension.NetCore.Analyzer/Generator/ImplementAutoGenerator.cs +2 -0
@@ -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 {
Modified XFEExtension.NetCore.Analyzer/Generator/PathPropertyAutoGenerator.cs +15 -4
@@ -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))
Modified XFEExtension.NetCore.Analyzer/Generator/ProfilePropertyAutoGenerator.cs +4 -1
@@ -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 {
Added XFEExtension.NetCore.Analyzer/Generator/ProfilePropertySyntaxReceiver.cs +23 -0
@@ -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 }
Added XFEExtension.NetCore.Analyzer/GeneratorOptions.cs +26 -0
@@ -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 }
Modified XFEExtension.NetCore.Analyzer/XFEExtension.NetCore.Analyzer.csproj +8 -0
@@ -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>