-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
6 changed files
with
156 additions
and
2 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,142 @@ | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
using Microsoft.CodeAnalysis.Text; | ||
using System; | ||
using System.Collections.Generic; | ||
using System.Linq; | ||
using System.Reflection; | ||
using System.Resources; | ||
using System.Runtime.Versioning; | ||
using System.Text; | ||
|
||
namespace Biwen.AutoClassGen; | ||
|
||
/// <summary> | ||
/// 生成程序集元数据 | ||
/// </summary> | ||
[Generator] | ||
public class AssemblyMetadataGenerator : IIncrementalGenerator | ||
{ | ||
private static readonly HashSet<string> _attributes = [ | ||
nameof(AssemblyCompanyAttribute), | ||
nameof(AssemblyConfigurationAttribute), | ||
nameof(AssemblyCopyrightAttribute), | ||
nameof(AssemblyCultureAttribute), | ||
nameof(AssemblyDelaySignAttribute), | ||
nameof(AssemblyDescriptionAttribute), | ||
nameof(AssemblyFileVersionAttribute), | ||
nameof(AssemblyInformationalVersionAttribute), | ||
nameof(AssemblyKeyFileAttribute), | ||
nameof(AssemblyKeyNameAttribute), | ||
nameof(AssemblyMetadataAttribute), | ||
nameof(AssemblyProductAttribute), | ||
nameof(AssemblySignatureKeyAttribute), | ||
nameof(AssemblyTitleAttribute), | ||
nameof(AssemblyTrademarkAttribute), | ||
nameof(AssemblyVersionAttribute), | ||
nameof(NeutralResourcesLanguageAttribute), | ||
nameof(TargetFrameworkAttribute), | ||
"UserSecretsIdAttribute"]; | ||
|
||
private const string AssemblyVersionAttributeMetadataName = "System.Reflection.AssemblyVersionAttribute"; | ||
private const string ONamespace = "build_property.rootnamespace";//命名空间 | ||
|
||
private readonly record struct AssemblyConstant(string Name, string Value); | ||
|
||
public void Initialize(IncrementalGeneratorInitializationContext context) | ||
{ | ||
//获取根命名空间 | ||
var rootNamespace = context.AnalyzerConfigOptionsProvider.Select((pvd, _) => | ||
{ | ||
pvd.GlobalOptions.TryGetValue(ONamespace, out var @namespace); | ||
return @namespace; | ||
}); | ||
|
||
//获取程序集元数据 | ||
var attrs = context.SyntaxProvider.ForAttributeWithMetadataName( | ||
AssemblyVersionAttributeMetadataName, | ||
(context, _) => context is CompilationUnitSyntax, | ||
(syntaxContext, _) => | ||
{ | ||
var attributes = syntaxContext.TargetSymbol.GetAttributes(); | ||
var constants = new List<AssemblyConstant>(); | ||
|
||
foreach (var attribute in attributes) | ||
{ | ||
var name = attribute.AttributeClass?.Name; | ||
if (name == null || !_attributes.Contains(name)) | ||
continue; | ||
|
||
if (attribute.ConstructorArguments.Length == 1) | ||
{ | ||
// remove Assembly | ||
if (name.Length > 8 && name.StartsWith("Assembly", StringComparison.Ordinal)) | ||
name = name.Substring(8); | ||
|
||
// remove Attribute | ||
if (name.Length > 9) | ||
name = name.Substring(0, name.Length - 9); | ||
|
||
var argument = attribute.ConstructorArguments.FirstOrDefault(); | ||
var value = argument.ToCSharpString() ?? string.Empty; | ||
|
||
if (string.IsNullOrWhiteSpace(value)) | ||
continue; | ||
|
||
var constant = new AssemblyConstant(name, value); | ||
constants.Add(constant); | ||
} | ||
else if (name == nameof(AssemblyMetadataAttribute) && attribute.ConstructorArguments.Length == 2) | ||
{ | ||
var nameArgument = attribute.ConstructorArguments[0]; | ||
var key = nameArgument.Value?.ToString() ?? string.Empty; | ||
|
||
var valueArgument = attribute.ConstructorArguments[1]; | ||
var value = valueArgument.ToCSharpString() ?? string.Empty; | ||
|
||
if (string.IsNullOrWhiteSpace(key) || string.IsNullOrWhiteSpace(value)) | ||
continue; | ||
|
||
// prevent duplicates | ||
if (constants.Any(c => c.Name == key)) | ||
continue; | ||
|
||
var constant = new AssemblyConstant(key, value); | ||
constants.Add(constant); | ||
} | ||
} | ||
return constants; | ||
}).Where(c => c?.Count > 0); | ||
|
||
//合并数据 | ||
var inc = attrs.Combine(rootNamespace); | ||
|
||
//生成源代码 | ||
context.RegisterSourceOutput(inc, (ctx, info) => | ||
{ | ||
var constants = info.Left; | ||
var rootNamespace = info.Right; | ||
|
||
if (string.IsNullOrEmpty(rootNamespace)) | ||
return; | ||
|
||
var sb = new StringBuilder(); | ||
sb.AppendLine("// <auto-generated/>"); | ||
sb.AppendLine($"namespace {rootNamespace}.Generated;"); | ||
sb.AppendLine(); | ||
sb.AppendLine($"[global::System.CodeDom.Compiler.GeneratedCode(\"{ThisAssembly.Product}\", \"{ThisAssembly.FileVersion}\")]"); | ||
sb.AppendLine("public static class AssemblyMetadata"); | ||
sb.AppendLine("{"); | ||
foreach (var constant in constants) | ||
{ | ||
sb.AppendLine($"public const string {constant.Name} = {constant.Value};"); | ||
} | ||
sb.AppendLine("}"); | ||
|
||
var source = sb.ToString().FormatContent(); | ||
|
||
ctx.AddSource("AssemblyMetadata.g.cs", SourceText.From(source, Encoding.UTF8)); | ||
}); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,7 @@ | ||
## 自动创建程序集Metadata信息 | ||
|
||
#### 使用方式: | ||
```csharp | ||
Console.WriteLine({namespace}.Generated.AssemblyMetadata.TargetFramework); | ||
//... | ||
``` |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters