Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
30 changes: 30 additions & 0 deletions doc/AutoInject版本日志.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,36 @@

## v0.1.4
- ⚡️升级`.NET10`
- 🛠重构生成逻辑,每个项目生成自身的注入代码,由注入程序方法调用

```csharp
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.DependencyInjection.Extensions;
using AutoInjectGenerator.Models;
// <auto-generated/>
#pragma warning disable
#nullable enable
namespace Blazor.Test
{
/// <inheritdoc/>
[global::System.CodeDom.Compiler.GeneratedCode("AutoInjectGenerator.AutoInjectContextGenerator", "0.1.4.0")]
static partial class AutoInjectContext
{
private static readonly global::System.Collections.Generic.List<string> _includes = ["SERVER"] ;

private static readonly global::System.Collections.Generic.List<string> _excludes = [] ;


public static partial void Inject(this Microsoft.Extensions.DependencyInjection.IServiceCollection services)
{
var config = new global::AutoInjectGenerator.AutoInjectConfiguration(_excludes, _includes);
global::Blazor.Test.Client.AutoInjectModuleServices.InjectModuleServices(services, config);
global::InjectTest.AutoInjectModuleServices.InjectModuleServices(services, config);
global::TestProject1.AutoInjectModuleServices.InjectModuleServices(services, config);
}
}
}
```

## v0.1.3
- 🛠优化分组判断,现在可以配置在不同的分组中注入相同的实例
Expand Down
51 changes: 2 additions & 49 deletions src/AutoInject.Roslyn/AutoInjectContextGenerator.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,58 +11,11 @@
namespace AutoInjectGenerator;


[Generator(LanguageNames.CSharp)]
public class AutoInjectContextGenerator : IIncrementalGenerator
//[Generator(LanguageNames.CSharp)]
public class AutoInjectContextGenerator //: IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
//只能获取到当前程序集的节点
//var ctx = context.SyntaxProvider.ForAttributeWithMetadataName(
// AutoInjectContext
// , static (node, _) => node is ClassDeclarationSyntax
// , CollectContextInfo).Collect();
//var services = context.SyntaxProvider.ForAttributeWithMetadataName(
// AutoInject
// , static (node, _) => node is ClassDeclarationSyntax
// , CollectInjectInfo).Collect();

//var ctx = context.CompilationProvider.ForAttributeWithMetadataName(
// AutoInjectContext
// , static (node, _) => true
// , (ctx, _) => CollectContextInfo(ctx)).Collect();
//var services = context.CompilationProvider.ForAttributeWithMetadataName(
// AutoInject
// , static (node, _) => true
// , (ctx, _) => CollectInjectInfo(ctx)).Collect();

//context.RegisterSourceOutput(context.CompilationProvider.Combine(ctx.Combine(services)), static (context, source) =>
//{
// (Compilation compilation, var Right) = source;
// (var allContext, var services) = Right;
// foreach (var item in allContext)
// {
// if (item is null) continue;
// if (!EqualityComparer<IAssemblySymbol>.Default.Equals(item.TargetSymbol.ContainingAssembly, compilation.SourceModule.ContainingAssembly))
// {
// continue;
// }
// if (item.Diagnostic != null)
// {
// context.ReportDiagnostic(item.Diagnostic);
// return;
// }

// foreach (var a in services.Where(a => a?.Diagnostic is not null))
// {
// context.ReportDiagnostic(a!.Diagnostic!);
// return;
// }
// var codefile = CreateContextCodeFile(item, services);
// context.AddSource(codefile);
// }
//});


context.RegisterSourceOutput(context.CompilationProvider, static (context, source) =>
{
var allContext = source.FindByAttributeMetadataName(
Expand Down
60 changes: 58 additions & 2 deletions src/AutoInject.Roslyn/AutoInjectContextGeneratorHelpers.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,10 @@ namespace AutoInjectGenerator;
internal static class AutoInjectContextGeneratorHelpers
{
public const string AutoInjectContext = "AutoInjectGenerator.AutoInjectContextAttribute";
public const string AutoInjectConfiguration = "AutoInjectGenerator.AutoInjectConfiguration";
public const string AutoInjectConfiguration = "AutoInjectGenerator.AutoInjectConfigurationAttribute";
public const string AutoInject = "AutoInjectGenerator.AutoInjectAttribute";
public const string AutoInjectSelf = "AutoInjectGenerator.AutoInjectSelfAttribute";
public const string AutoInjectModule = "AutoInjectGenerator.AutoInjectModuleAttribute";
private static bool IsInjectSelf(AttributeData data) => data.AttributeClass?.ToDisplayString() == AutoInjectSelf;

// new ServiceDescriptor()
Expand Down Expand Up @@ -165,7 +166,62 @@ bool HasDifferentScopedInSameMemberShip()
.Any(g => g.Select(s => s.Scoped).Distinct().Count() > 1);
}
}
public static AutoInjectInfo CollectInjectInfo(INamedTypeSymbol classSymbol, SyntaxNode targetNode)
{
var info = new AutoInjectInfo(classSymbol);
foreach (var a in classSymbol.GetAttributes(AutoInject, true))
{
if (!a.GetNamedValue("LifeTime", out var injectType))
{
injectType = 1;
}
var scoped = FormatInjectType(injectType);

string serviceType;
if (IsInjectSelf(a))
{
serviceType = info.Implement;
}
else if(a.GetNamedValue("ServiceType", out var t) && t is INamedTypeSymbol type)
{
serviceType = type.ToDisplayString();
if (!classSymbol.AllInterfaces.Contains(type)
&& !SymbolEqualityComparer.Default.Equals(classSymbol, type)
&& !classSymbol.IsSubClassOf(type))
{
info.Diagnostic = DiagnosticDefinitions.AIG00003(serviceType, info.Implement, targetNode.GetLocation());
return info;
}
}
// 获取到的Interfaces跟AllInterfaces一样
else if (classSymbol.Interfaces.Length >= 1)
{
serviceType = classSymbol.Interfaces[0].ToDisplayString();
}
else
{
serviceType = info.Implement;
}

_ = a.GetNamedValue<string>("ServiceKey", out var serviceKey);
_ = a.GetNamedValue<string>("Group", out var group);
info.Services.Add(new RegisterServiceInfo(scoped, serviceType, serviceKey, group));
}

if (HasDifferentScopedInSameMemberShip())
{
info.Diagnostic = DiagnosticDefinitions.AIG00004(targetNode.GetLocation());
}

return info;

bool HasDifferentScopedInSameMemberShip()
{
return info.Services.Where(s => s.MemberShip != null)
.GroupBy(s => s.MemberShip)
.Any(g => g.Select(s => s.Scoped).Distinct().Count() > 1);
}
}
public static CodeFile? CreateContextCodeFile(AutoInjectContextInfo context, IEnumerable<AutoInjectInfo?> items)
{
var classSymbol = context.TargetSymbol;
Expand Down Expand Up @@ -269,7 +325,7 @@ private static IEnumerable<string> CreateRegisterStatement(AutoInjectContextInfo
}
}



yield return "";
static bool ShouldRegister(AutoInjectContextInfo context, string? group)
Expand Down
100 changes: 100 additions & 0 deletions src/AutoInject.Roslyn/AutoInjectEntryGenerator.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
using Generators.Shared;
using Generators.Shared.Builder;
using Microsoft.CodeAnalysis;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using static AutoInjectGenerator.AutoInjectContextGeneratorHelpers;
namespace AutoInjectGenerator;

[Generator(LanguageNames.CSharp)]
public class AutoInjectEntryGenerator : IIncrementalGenerator
{
public void Initialize(IncrementalGeneratorInitializationContext context)
{
var value = context.SyntaxProvider.ForAttributeWithMetadataName(AutoInjectContext
, static (node, _) => node is ClassDeclarationSyntax
, static (ctx, _) => CollectContextInfo(ctx, _));
context.RegisterSourceOutput(value, static (spc, source) =>
{
var target = source.TargetSymbol;
var asm = target.ContainingAssembly;
var modules = new List<INamedTypeSymbol>();
if (asm.GlobalNamespace is not null)
{
modules.AddRange(asm.GlobalNamespace.GetAllMembers<INamedTypeSymbol>(i => i is INamedTypeSymbol m && m.HasAttribute(AutoInjectModule)));
}
foreach (var item in asm.Modules)
{
foreach (var referencedAssembly in item.ReferencedAssemblySymbols)
{
if (referencedAssembly.Name.StartsWith("System.") || referencedAssembly.Name.StartsWith("Microsoft."))
continue;

if (referencedAssembly.GlobalNamespace is null) continue;
modules.AddRange(referencedAssembly.GlobalNamespace.GetAllMembers<INamedTypeSymbol>(i => i is INamedTypeSymbol m && m.HasAttribute(AutoInjectModule)));
}
}
var file = CreateCodeFile(source, modules);
#if DEBUG
var sss = file?.ToString();
#endif
spc.AddSource(file);
});
}

private static CodeFile? CreateCodeFile(AutoInjectContextInfo context, List<INamedTypeSymbol> modules)
{
var classSymbol = context.TargetSymbol;
var className = context.ClassName;
var methodSymbol = context.MethodSymbol!;
var gn = NamespaceBuilder.Default.Namespace(classSymbol.ContainingNamespace.ToDisplayString());
var gclass = ClassBuilder.Default
.ClassName(className)
.AddGeneratedCodeAttribute(typeof(AutoInjectContextGenerator))
.Modifiers("static partial");

var serviceName = methodSymbol.Parameters.First(p =>
p.Type.ToDisplayString().Contains("Microsoft.Extensions.DependencyInjection.IServiceCollection")).Name;

var includeField = FieldBuilder.Default
.Modifiers("private static readonly")
.MemberType("global::System.Collections.Generic.List<string>")
.FieldName("_includes")
.InitializeWith($"[{string.Join(", ", context.Includes.Select(s => $"\"{s}\""))}] ");
var excludeField = FieldBuilder.Default
.Modifiers("private static readonly")
.MemberType("global::System.Collections.Generic.List<string>")
.FieldName("_excludes")
.InitializeWith($"[{string.Join(", ", context.Excludes.Select(s => $"\"{s}\""))}] ");

var cm = MethodBuilder.Default.Partial(methodSymbol);
{
// 创建配置
List<string> methodBody = [
"var config = new global::AutoInjectGenerator.AutoInjectConfiguration(_excludes, _includes)",
//$"global::AutoInjectGenerator.AutoInjectManager.ApplyProjectServices({serviceName}, config)"
];
foreach (var item in modules)
{
methodBody.Add($"global::{item.ContainingAssembly.Name}.AutoInjectModuleServices.InjectModuleServices({serviceName}, config)");
}
cm.AddBody([.. methodBody]);
}
gclass.AddMembers(includeField);
gclass.AddMembers(excludeField);
gclass.AddMembers(cm);

var file = CodeFile.New($"{className}.AutoInject.g.cs")
.AddUsings("using Microsoft.Extensions.DependencyInjection;")
.AddUsings("using Microsoft.Extensions.DependencyInjection.Extensions;")
.AddUsings("using AutoInjectGenerator.Models;")
.AddMembers(gn.AddMembers(gclass));

#if DEBUG
var ss = file.ToString();
#endif
return file;
}
}
Loading
Loading