XFEExtension
【DLL】XFE各类拓展是一个C#的DLL库,旨在优化C#代码中常用语句的使用,并提供更简洁的访问方式,同时提供Xunit测试框架,快速搭建服务器/客户端,免费ChatGPTAPI接口,免费通讯服务器,XFE下载器,新增格式等
关注
0
Fork
0
Star
0
返回提交历史
Modified
XFEExtension.NetCore.Analyzer.Test/SystemProfile.cs
+10
-7
Modified
XFEExtension.NetCore.Analyzer.Test/TestClass.cs
+2
-4
Modified
XFEExtension.NetCore.Analyzer/CodeFix/ProfileExtensionCodeFixProvider.cs
+0
-54
Modified
XFEExtension.NetCore.Analyzer/Diagnostics/ProfileExtensionDiagnostics.cs
+30
-3
Modified
XFEExtension.NetCore.Analyzer/Generator/ProfilePropertyAutoGenerator.cs
+140
-6
XFEstudio/XFEExtension
现在,配置文件生成的注释会自动显示getset方法中的内容
ce25a10
代码差异
5 个文件
+182
-74
@@ -4,15 +4,18 @@ namespace XFEExtension.NetCore.Analyzer.Test;
4
4
5
5
public static partial class SystemProfile
6
6
{
7
#region Name
8
/// <summary>
9
/// 名称
10
/// </summary>
7
11
[ProfileProperty]
8
[ProfilePropertyAddGet(@"Console.WriteLine(""123"")")]
9
[ProfilePropertyAddSet(@"Console.WriteLine(value)")]
10
[ProfilePropertyAddGet(@"Console.WriteLine(""456"")")]
11
[ProfilePropertyAddSet(@"Console.WriteLine()")]
12
[ProfilePropertyAddGet("Console.WriteLine()")]
13
[ProfilePropertyAddGet("Console.WriteLine()")]
14
[ProfilePropertyAddGet($@"return name")]
15
[ProfilePropertyAddSet("Console.WriteLine(value)")]
16
[ProfilePropertyAddSet("name = value")]
12
17
private static string name = string.Empty;
18
#endregion
13
19
[ProfileProperty]
14
[ProfilePropertyAddSet(@"_age = 1")]
15
[ProfilePropertyAddSet(@"_age = 2")]
16
[ProfilePropertyAddSet(@"_age = value")]
17
20
private static int _age;
18
21
}
@@ -4,9 +4,7 @@ internal class TestClass
4
4
{
5
5
static void Main(string[] args)
6
6
{
7
var task = new Task(() =>
8
{
9
Console.WriteLine("Hello World");
10
});
7
Console.WriteLine(SystemProfile.Name);
8
Console.WriteLine(SystemProfile.Age);
11
9
}
12
10
}
@@ -44,60 +44,6 @@ namespace XFEExtension.NetCore.Analyzer.CodeFix
44
44
}
45
45
return Task.CompletedTask;
46
46
}
47
[DllImport("user32.dll")]
48
[return: MarshalAs(UnmanagedType.Bool)]
49
public static extern bool OpenClipboard(IntPtr hWndNewOwner);
50
51
[DllImport("user32.dll")]
52
[return: MarshalAs(UnmanagedType.Bool)]
53
public static extern bool EmptyClipboard();
54
55
[DllImport("user32.dll")]
56
public static extern IntPtr SetClipboardData(uint uFormat, IntPtr data);
57
58
[DllImport("user32.dll")]
59
[return: MarshalAs(UnmanagedType.Bool)]
60
public static extern bool CloseClipboard();
61
62
[DllImport("kernel32.dll", SetLastError = true)]
63
public static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);
64
65
[DllImport("kernel32.dll", SetLastError = true)]
66
public static extern IntPtr GlobalLock(IntPtr hMem);
67
68
[DllImport("kernel32.dll", SetLastError = true)]
69
[return: MarshalAs(UnmanagedType.Bool)]
70
public static extern bool GlobalUnlock(IntPtr hMem);
71
public static bool SetClipboardText(string text)
72
{
73
// 打开剪切板
74
if (!OpenClipboard(IntPtr.Zero))
75
return false;
76
77
// 清空剪切板
78
EmptyClipboard();
79
80
// 分配内存
81
IntPtr hGlobal = GlobalAlloc(0x2000, (UIntPtr)((text.Length + 1) * 2)); // 0x2000 是GMEM_MOVEABLE
82
83
// 锁定内存
84
IntPtr pGlobal = GlobalLock(hGlobal);
85
86
// 将文本复制到内存
87
byte[] bytes = Encoding.Unicode.GetBytes(text);
88
Marshal.Copy(bytes, 0, pGlobal, bytes.Length);
89
90
// 解锁内存
91
GlobalUnlock(hGlobal);
92
93
// 将内存设置到剪切板
94
SetClipboardData(13, hGlobal);
95
96
// 关闭剪切板
97
CloseClipboard();
98
99
return true;
100
}
101
47
private async Task<Document> AddReturnFuncAsync(Document document, TextSpan sourceSpan, System.Threading.CancellationToken c)
102
48
{
103
49
var root = await document.GetSyntaxRootAsync(c);
@@ -3,10 +3,11 @@ using Microsoft.CodeAnalysis.CSharp;
3
3
using Microsoft.CodeAnalysis.CSharp.Syntax;
4
4
using Microsoft.CodeAnalysis.Diagnostics;
5
5
using System.Collections.Immutable;
6
using System.Diagnostics;
7
6
using System.Linq;
8
7
using System.Text.RegularExpressions;
8
using XFEExtension.NetCore.Analyzer.CodeFix;
9
9
using XFEExtension.NetCore.Analyzer.Generator;
10
using static System.Net.Mime.MediaTypeNames;
10
11
11
12
namespace XFEExtension.NetCore.Analyzer.Diagnostics
12
13
{
@@ -61,7 +62,20 @@ namespace XFEExtension.NetCore.Analyzer.Diagnostics
61
62
continue;
62
63
}
63
64
var argument = attributeSyntax.ArgumentList.Arguments.First();
64
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax && literalExpressionSyntax.Token.ValueText.Contains("return"))
65
var funcText = string.Empty;
66
if (argument.Expression is LiteralExpressionSyntax)
67
{
68
funcText = argument.Expression.GetText().ToString();
69
}
70
else if (argument.Expression is InterpolatedStringExpressionSyntax)
71
{
72
funcText = argument.Expression.GetText().ToString();
73
}
74
else if (argument.Expression is InvocationExpressionSyntax)
75
{
76
funcText = argument.Expression.GetText().ToString();
77
}
78
if (funcText.Contains("return"))
65
79
{
66
80
getAttributeHasResult = true;
67
81
}
@@ -83,7 +97,20 @@ namespace XFEExtension.NetCore.Analyzer.Diagnostics
83
97
continue;
84
98
}
85
99
var argument = attributeSyntax.ArgumentList.Arguments.First();
86
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax && Regex.IsMatch(literalExpressionSyntax.Token.ValueText, $@"{fieldDeclaration.Declaration.Variables.First().Identifier.ValueText}\s*=\s*value"))
100
var funcText = string.Empty;
101
if (argument.Expression is LiteralExpressionSyntax)
102
{
103
funcText = argument.Expression.GetText().ToString();
104
}
105
else if (argument.Expression is InterpolatedStringExpressionSyntax)
106
{
107
funcText = argument.Expression.GetText().ToString();
108
}
109
else if (argument.Expression is InvocationExpressionSyntax)
110
{
111
funcText = argument.Expression.GetText().ToString();
112
}
113
if (Regex.IsMatch(funcText, $@"{fieldDeclaration.Declaration.Variables.First().Identifier.ValueText}\s*=\s*value"))
87
114
{
88
115
setAttributeSetResult = true;
89
116
}
@@ -1,8 +1,12 @@
1
1
using Microsoft.CodeAnalysis;
2
2
using Microsoft.CodeAnalysis.CSharp;
3
3
using Microsoft.CodeAnalysis.CSharp.Syntax;
4
using System;
4
5
using System.Collections.Generic;
5
6
using System.Linq;
7
using System.Reflection;
8
using System.Runtime.InteropServices;
9
using System.Text;
6
10
7
11
namespace XFEExtension.NetCore.Analyzer.Generator
8
12
{
@@ -51,7 +55,14 @@ namespace XFEExtension.NetCore.Analyzer.Generator
51
55
}
52
56
});
53
57
var propertyType = fieldDeclarationSyntax.Declaration.Type;
58
#region Trivia头
59
var triviaText = $@"/// <remarks>
60
/// <seealso cref=""{propertyName}""/> 是根据 <seealso cref=""{fieldName}""/> 自动生成的属性<br/><br/>
61
/// <code><seealso langword=""get""/>方法已生成以下代码:";
62
#endregion
54
63
var getExpressionStatements = new List<StatementSyntax>();
64
var getIndex = 0;
65
var setIndex = 0;
55
66
if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddGetAttribute))
56
67
{
57
68
GetProfilePropertyAddGetAttributeList(fieldDeclarationSyntax).ForEach(attribute =>
@@ -61,16 +72,43 @@ namespace XFEExtension.NetCore.Analyzer.Generator
61
72
return;
62
73
}
63
74
var argument = attribute.ArgumentList.Arguments.First();
75
var funcText = string.Empty;
64
76
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
77
funcText = literalExpressionSyntax.Token.ValueText;
78
if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax)
79
funcText = interpolatedStringExpressionSyntax.Contents.ToString();
80
if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax)
81
funcText = invocationExpressionSyntax.GetText().ToString();
82
getExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)));
83
if (getIndex == 0)
65
84
{
66
getExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(literalExpressionSyntax.Token.ValueText)));
85
#region Get方法首个注释
86
triviaText += $"\t○ {funcText.Replace("\n", "<br/>").Replace("return", "<seealso langword=\"return\"/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>")};<br/>";
87
#endregion
67
88
}
89
else
90
{
91
#region Get剩余方法注释
92
triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "<br/>").Replace("return", "<seealso langword=\"return\"/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>")};<br/>";
93
#endregion
94
}
95
getIndex++;
68
96
});
69
97
}
70
98
else
71
99
{
72
100
getExpressionStatements.Add(SyntaxFactory.ReturnStatement(SyntaxFactory.IdentifierName(fieldName)));
101
#region Get方默认注释
102
triviaText += $@" ○ <seealso langword=""return""/> <seealso langword=""{fieldName}""/>;";
103
#endregion
104
getIndex++;
73
105
}
106
#region Get方法尾及Set方法头注释
107
triviaText += @"
108
/// </code>
109
/// <br/>
110
/// <code><seealso langword=""set""/>方法已生成以下代码:";
111
#endregion
74
112
var setExpressionStatements = new List<StatementSyntax>();
75
113
if (fieldDeclarationSyntax.AttributeLists.Any(IsProfilePropertyAddSetAttribute))
76
114
{
@@ -81,17 +119,58 @@ namespace XFEExtension.NetCore.Analyzer.Generator
81
119
return;
82
120
}
83
121
var argument = attribute.ArgumentList.Arguments.First();
122
var funcText = string.Empty;
84
123
if (argument.Expression is LiteralExpressionSyntax literalExpressionSyntax)
124
funcText = literalExpressionSyntax.Token.ValueText;
125
else if (argument.Expression is InterpolatedStringExpressionSyntax interpolatedStringExpressionSyntax)
126
funcText = interpolatedStringExpressionSyntax.Contents.ToString();
127
else if (argument.Expression is InvocationExpressionSyntax invocationExpressionSyntax)
128
funcText = invocationExpressionSyntax.GetText().ToString();
129
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(funcText)));
130
if (setIndex == 0)
131
{
132
#region Set方法首个注释
133
triviaText += $"\t○ {funcText.Replace("\n", "<br/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>").Replace("value", "<seealso langword=\"value\"/>")};<br/>";
134
#endregion
135
}
136
else
85
137
{
86
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression(literalExpressionSyntax.Token.ValueText)));
138
#region Set剩余方法注释
139
triviaText += $"\n///\t\t\t\t○ {funcText.Replace("\n", "<br/>").Replace(fieldName, $"<seealso langword=\"{fieldName}\"/>").Replace("value", "<seealso langword=\"value\"/>")};<br/>";
140
#endregion
87
141
}
142
setIndex++;
88
143
});
89
144
}
90
145
else
91
146
{
92
147
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"{fieldName} = value")));
148
#region Set方法默认注释
149
triviaText += $@" ○ <seealso langword=""{fieldName}""/> = <seealso langword=""value""/>;<br/>";
150
#endregion
151
setIndex++;
93
152
}
94
153
setExpressionStatements.Add(SyntaxFactory.ExpressionStatement(SyntaxFactory.ParseExpression($"global::XFEExtension.NetCore.ProfileExtension.XFEProfile.SaveProfile(typeof({className}))")));
154
if (setIndex == 0)
155
{
156
#region Set方法中的保存方法在第一位情况的注释
157
triviaText += $@" ○ <seealso cref=""global::XFEExtension.NetCore.ProfileExtension.XFEProfile.SaveProfile(ProfileInfo)""/>";
158
#endregion
159
}
160
else
161
{
162
#region Set方法中的保存方法在非第一位情况的注释
163
triviaText += $"\n///\t\t\t\t○ <seealso cref=\"global::XFEExtension.NetCore.ProfileExtension.XFEProfile.SaveProfile(ProfileInfo)\"/>;";
164
#endregion
165
}
166
#region Trivia尾
167
triviaText += @"
168
/// </code>
169
/// </remarks>
170
";
171
#endregion
172
var leadingTrivia = fieldDeclarationSyntax.DescendantTrivia().ToList();
173
leadingTrivia.AddRange(SyntaxFactory.ParseLeadingTrivia(triviaText));
95
174
var property = SyntaxFactory.PropertyDeclaration(propertyType, propertyName)
96
175
.WithModifiers(SyntaxFactory.TokenList(SyntaxFactory.Token(SyntaxKind.PublicKeyword), SyntaxFactory.Token(SyntaxKind.StaticKeyword)))
97
176
.AddAttributeLists(attributeSyntax)
@@ -103,7 +182,7 @@ namespace XFEExtension.NetCore.Analyzer.Generator
103
182
SyntaxFactory.AccessorDeclaration(SyntaxKind.SetAccessorDeclaration)
104
183
.WithBody(SyntaxFactory.Block(setExpressionStatements))
105
184
})))
106
.WithLeadingTrivia(fieldDeclarationSyntax.GetLeadingTrivia());
185
.WithLeadingTrivia(leadingTrivia);
107
186
return property.NormalizeWhitespace();
108
187
});
109
188
var profileClassSyntaxTree = GenerateProfileClassSyntaxTree(classDeclaration, usingDirectives, properties, fileScopedNamespaceDeclarationSyntax);
@@ -163,11 +242,11 @@ namespace XFEExtension.NetCore.Analyzer.Generator
163
242
private static SyntaxTree GenerateProfileClassSyntaxTree(ClassDeclarationSyntax classDeclaration, UsingDirectiveSyntax[] usingDirectiveSyntaxes, IEnumerable<PropertyDeclarationSyntax> propertyDeclarationSyntaxes, FileScopedNamespaceDeclarationSyntax fileScopedNamespaceDeclarationSyntax)
164
243
{
165
244
var className = classDeclaration.Identifier.ValueText;
166
var summaryText = $@"/// <remarks>
245
var triviaText = $@"/// <remarks>
167
246
/// <code><seealso cref=""{className}""/> 已自动实现以下属性:</code><br/>
168
247
/// <code>
169
248
";
170
summaryText += 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";
249
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";
171
250
var memberDeclarations = new List<MemberDeclarationSyntax>();
172
251
memberDeclarations.AddRange(propertyDeclarationSyntaxes);
173
252
var staticConstructorSyntax = SyntaxFactory.ConstructorDeclaration(className)
@@ -197,7 +276,7 @@ namespace XFEExtension.NetCore.Analyzer.Generator
197
276
var profileClass = SyntaxFactory.ClassDeclaration(className)
198
277
.AddModifiers(SyntaxFactory.Token(SyntaxKind.PartialKeyword))
199
278
.AddMembers(memberDeclarations.ToArray())
200
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(summaryText))
279
.WithLeadingTrivia(SyntaxFactory.ParseLeadingTrivia(triviaText))
201
280
.NormalizeWhitespace();
202
281
MemberDeclarationSyntax memberDeclaration;
203
282
if (fileScopedNamespaceDeclarationSyntax is null)
@@ -220,5 +299,60 @@ namespace XFEExtension.NetCore.Analyzer.Generator
220
299
.NormalizeWhitespace();
221
300
return SyntaxFactory.SyntaxTree(profileClassCompilationUnit);
222
301
}
302
// 定义Windows API
303
[DllImport("user32.dll")]
304
[return: MarshalAs(UnmanagedType.Bool)]
305
public static extern bool OpenClipboard(IntPtr hWndNewOwner);
306
307
[DllImport("user32.dll")]
308
[return: MarshalAs(UnmanagedType.Bool)]
309
public static extern bool EmptyClipboard();
310
311
[DllImport("user32.dll")]
312
public static extern IntPtr SetClipboardData(uint uFormat, IntPtr data);
313
314
[DllImport("user32.dll")]
315
[return: MarshalAs(UnmanagedType.Bool)]
316
public static extern bool CloseClipboard();
317
318
[DllImport("kernel32.dll", SetLastError = true)]
319
public static extern IntPtr GlobalAlloc(uint uFlags, UIntPtr dwBytes);
320
321
[DllImport("kernel32.dll", SetLastError = true)]
322
public static extern IntPtr GlobalLock(IntPtr hMem);
323
324
[DllImport("kernel32.dll", SetLastError = true)]
325
[return: MarshalAs(UnmanagedType.Bool)]
326
public static extern bool GlobalUnlock(IntPtr hMem);
327
public static bool SetClipboardText(string text)
328
{
329
// 打开剪切板
330
if (!OpenClipboard(IntPtr.Zero))
331
return false;
332
333
// 清空剪切板
334
EmptyClipboard();
335
336
// 分配内存
337
IntPtr hGlobal = GlobalAlloc(0x2000, (UIntPtr)((text.Length + 1) * 2)); // 0x2000 是GMEM_MOVEABLE
338
339
// 锁定内存
340
IntPtr pGlobal = GlobalLock(hGlobal);
341
342
// 将文本复制到内存
343
byte[] bytes = Encoding.Unicode.GetBytes(text);
344
Marshal.Copy(bytes, 0, pGlobal, bytes.Length);
345
346
// 解锁内存
347
GlobalUnlock(hGlobal);
348
349
// 将内存设置到剪切板
350
SetClipboardData(13, hGlobal);
351
352
// 关闭剪切板
353
CloseClipboard();
354
355
return true;
356
}
223
357
}
224
358
}