diff --git a/ShadowExample.Plugin.Emoji/EmojiPlugin.cs b/ShadowExample.Plugin.Emoji/EmojiPlugin.cs
index 0489f04..b7aff73 100644
--- a/ShadowExample.Plugin.Emoji/EmojiPlugin.cs
+++ b/ShadowExample.Plugin.Emoji/EmojiPlugin.cs
@@ -32,7 +32,7 @@ public override string GetEmoji()
{
return "💡😭";
}
-
+
public override string DisplayName => "";
}
}
diff --git a/ShadowExample.Plugin.Emoji/ShadowExample.Plugin.Emoji.csproj b/ShadowExample.Plugin.Emoji/ShadowExample.Plugin.Emoji.csproj
index a3b1c88..3d48001 100644
--- a/ShadowExample.Plugin.Emoji/ShadowExample.Plugin.Emoji.csproj
+++ b/ShadowExample.Plugin.Emoji/ShadowExample.Plugin.Emoji.csproj
@@ -41,8 +41,8 @@
-
-
+
+
diff --git a/ShadowExample.Plugin.Emoji/ViewModels/Test2ViewModel.cs b/ShadowExample.Plugin.Emoji/ViewModels/Test2ViewModel.cs
new file mode 100644
index 0000000..9a0c4cd
--- /dev/null
+++ b/ShadowExample.Plugin.Emoji/ViewModels/Test2ViewModel.cs
@@ -0,0 +1,11 @@
+using ShadowExample.Core;
+using ShadowPluginLoader.MetaAttributes;
+
+namespace ShadowExample.Plugin.Emoji.ViewModels;
+
+public partial class Test2ViewModel: TestViewModel
+{
+ [Autowired]
+ public ShadowExamplePluginLoader ShadowExamplePluginLoader { get; }
+
+}
\ No newline at end of file
diff --git a/ShadowExample.Plugin.Emoji/ViewModels/TestViewModel.cs b/ShadowExample.Plugin.Emoji/ViewModels/TestViewModel.cs
new file mode 100644
index 0000000..0d9e886
--- /dev/null
+++ b/ShadowExample.Plugin.Emoji/ViewModels/TestViewModel.cs
@@ -0,0 +1,10 @@
+using ShadowPluginLoader.MetaAttributes;
+using ShadowPluginLoader.WinUI;
+
+namespace ShadowExample.Plugin.Emoji.ViewModels;
+
+public partial class TestViewModel
+{
+ [Autowired]
+ public PluginEventService PluginEventService { get; }
+}
\ No newline at end of file
diff --git a/ShadowPluginLoader.SourceGenerator/Generators/AutowiredGenerator.cs b/ShadowPluginLoader.SourceGenerator/Generators/AutowiredGenerator.cs
new file mode 100644
index 0000000..9c716d9
--- /dev/null
+++ b/ShadowPluginLoader.SourceGenerator/Generators/AutowiredGenerator.cs
@@ -0,0 +1,136 @@
+using Microsoft.CodeAnalysis;
+using ShadowPluginLoader.SourceGenerator.Helpers;
+using ShadowPluginLoader.SourceGenerator.Models;
+using ShadowPluginLoader.SourceGenerator.Receivers;
+
+namespace ShadowPluginLoader.SourceGenerator.Generators;
+
+///
+///
+///
+[Generator]
+public class AutowiredGenerator : ISourceGenerator
+{
+ private Dictionary> BaseConstructors { get; } = new();
+
+ private static string ToLowerFirst(string input)
+ {
+ if (string.IsNullOrEmpty(input) || char.IsLower(input[0]))
+ return input;
+
+ return char.ToLower(input[0]) + input.Substring(1);
+ }
+
+ ///
+ public void Initialize(GeneratorInitializationContext context)
+ {
+ context.RegisterForSyntaxNotifications(() => new AutowiredClassSyntaxReceiver());
+ }
+
+ ///
+ public void Execute(GeneratorExecutionContext context)
+ {
+ var logger = new Logger("AutowiredGenerator", context);
+ if (context.SyntaxReceiver is not AutowiredClassSyntaxReceiver receiver)
+ {
+ logger.Warning("SPLW003", "No Autowired Class found, skip Autowired generation.");
+ return;
+ }
+
+ if (receiver.Classes.Count == 0)
+ {
+ logger.Warning("SPLW003", "No Autowired Class found, skip Autowired generation.");
+ return;
+ }
+
+ var sortedClasses = InheritanceSorter.SortTypesByInheritance(receiver.Classes
+ .Select(classSyntax =>
+ context.Compilation
+ .GetSemanticModel(classSyntax.SyntaxTree)
+ .GetDeclaredSymbol(classSyntax))
+ .OfType());
+ foreach (var classSymbol in sortedClasses)
+ {
+ var properties = classSymbol.GetMembers()
+ .OfType().Where(p => p.HasAttribute(context,
+ "ShadowPluginLoader.MetaAttributes.AutowiredAttribute"));
+ var propertySymbols = properties as IPropertySymbol[] ?? properties.ToArray();
+ if (!propertySymbols.Any()) continue;
+ var namespaceName = classSymbol.ContainingNamespace.ToDisplayString();
+ var classClassName = classSymbol.Name;
+
+ var constructors = new List();
+ var assignments = new List();
+ var baseConstructors = new List();
+ var constructorRecord = new List();
+ var baseConstructorString = string.Empty;
+
+ foreach (var property in propertySymbols)
+ {
+ var propertyName = property.Name;
+ var propertySmallName = ToLowerFirst(propertyName);
+ var propertyType = property.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+ constructors.Add($"{propertyType} {propertySmallName}");
+ assignments.Add($"{propertyName} = {propertySmallName};");
+ constructorRecord.Add(new BaseConstructor(propertyType, propertySmallName));
+ }
+
+ var baseTypeSymbol = classSymbol.BaseType;
+ if (baseTypeSymbol != null)
+ {
+ if (BaseConstructors.ContainsKey(
+ baseTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)))
+ {
+ foreach (var parameter in BaseConstructors[
+ baseTypeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)])
+ {
+ constructors.Add($"{parameter.Type} {parameter.Name}");
+ baseConstructors.Add($"{parameter.Name}");
+ }
+ }
+ else
+ {
+ var baseConstructor = baseTypeSymbol?.GetMembers()
+ .OfType()
+ .Where(m => m.MethodKind == MethodKind.Constructor)
+ .OrderByDescending(m => m.Parameters.Length)
+ .FirstOrDefault();
+ if (baseConstructor != null && baseConstructor.Name != "object.Object()")
+ {
+ foreach (var parameter in baseConstructor.Parameters)
+ {
+ var propertyType = parameter.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+ var propertySmallName = ToLowerFirst(parameter.Name);
+ constructors.Add($"{propertyType} {propertySmallName}");
+ baseConstructors.Add($"{propertySmallName}");
+ }
+ }
+ }
+
+ if (baseConstructors.Count > 0)
+ {
+ baseConstructorString = " : base(" + string.Join(", ", baseConstructors) + ")";
+ }
+ }
+
+
+ if (constructors.Count == 0 || assignments.Count == 0) continue;
+ var baseConstructorsKey = classSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
+ BaseConstructors[baseConstructorsKey] = constructorRecord;
+ var code = $$"""
+ // Automatic Generate From ShadowPluginLoader.SourceGenerator
+
+ namespace {{namespaceName}};
+
+ public partial class {{classClassName}}
+ {
+ public {{classClassName}}({{string.Join(", ", constructors)}}){{baseConstructorString}}
+ {
+ {{string.Join("\n", assignments)}}
+ }
+ }
+ """;
+ context.AddSource($"{classClassName}_Autowired.g.cs", code);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ShadowPluginLoader.SourceGenerator/Generators/SettingsGenerator.cs b/ShadowPluginLoader.SourceGenerator/Generators/SettingsGenerator.cs
index 3a742bc..d425f3f 100644
--- a/ShadowPluginLoader.SourceGenerator/Generators/SettingsGenerator.cs
+++ b/ShadowPluginLoader.SourceGenerator/Generators/SettingsGenerator.cs
@@ -1,5 +1,5 @@
using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
+using ShadowPluginLoader.SourceGenerator.Receivers;
namespace ShadowPluginLoader.SourceGenerator.Generators;
@@ -191,15 +191,3 @@ public partial class {{pluginName}}
}
}
-public class EnumSyntaxReceiver : ISyntaxReceiver
-{
- public List Enums { get; } = [];
-
- public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
- {
- if (syntaxNode is EnumDeclarationSyntax enumDeclaration)
- {
- Enums.Add(enumDeclaration);
- }
- }
-}
\ No newline at end of file
diff --git a/ShadowPluginLoader.SourceGenerator/Helpers/InheritanceSorter.cs b/ShadowPluginLoader.SourceGenerator/Helpers/InheritanceSorter.cs
new file mode 100644
index 0000000..311d547
--- /dev/null
+++ b/ShadowPluginLoader.SourceGenerator/Helpers/InheritanceSorter.cs
@@ -0,0 +1,41 @@
+namespace ShadowPluginLoader.SourceGenerator.Helpers;
+
+using Microsoft.CodeAnalysis;
+using System.Collections.Generic;
+public class CustomSymbolComparer : IEqualityComparer
+{
+ public bool Equals(INamedTypeSymbol x, INamedTypeSymbol y)
+ {
+ return x.Name == y.Name && x.Kind == y.Kind;
+ }
+
+ public int GetHashCode(INamedTypeSymbol obj)
+ {
+ return obj.Name.GetHashCode() ^ obj.Kind.GetHashCode();
+ }
+}
+public static class InheritanceSorter
+{
+ public static List SortTypesByInheritance(IEnumerable types)
+ {
+ // 创建一个字典存储每个类型的继承链
+ var inheritanceChains = new Dictionary>(new CustomSymbolComparer());
+
+ var namedTypeSymbols = types as INamedTypeSymbol[] ?? types.ToArray();
+ foreach (var type in namedTypeSymbols)
+ {
+ var chain = new List();
+ var currentType = type;
+
+ while (currentType != null)
+ {
+ chain.Add(currentType);
+ currentType = currentType.BaseType;
+ }
+ chain.Reverse();
+ inheritanceChains[type] = chain;
+ }
+ var sortedTypes = namedTypeSymbols.OrderBy(t => string.Join(",", inheritanceChains[t])).ToList();
+ return sortedTypes;
+ }
+}
diff --git a/ShadowPluginLoader.SourceGenerator/Models/BaseConstructor.cs b/ShadowPluginLoader.SourceGenerator/Models/BaseConstructor.cs
new file mode 100644
index 0000000..7399c30
--- /dev/null
+++ b/ShadowPluginLoader.SourceGenerator/Models/BaseConstructor.cs
@@ -0,0 +1,11 @@
+namespace ShadowPluginLoader.SourceGenerator.Models
+{
+ public record BaseConstructor(string Type, string Name);
+}
+
+namespace System.Runtime.CompilerServices
+{
+ class IsExternalInit
+ {
+ }
+}
\ No newline at end of file
diff --git a/ShadowPluginLoader.SourceGenerator/Receivers/AutowiredClassSyntaxReceiver.cs b/ShadowPluginLoader.SourceGenerator/Receivers/AutowiredClassSyntaxReceiver.cs
new file mode 100644
index 0000000..312fce1
--- /dev/null
+++ b/ShadowPluginLoader.SourceGenerator/Receivers/AutowiredClassSyntaxReceiver.cs
@@ -0,0 +1,15 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace ShadowPluginLoader.SourceGenerator.Receivers;
+
+public class AutowiredClassSyntaxReceiver : ISyntaxReceiver
+{
+ public List Classes { get; } = [];
+
+ public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
+ {
+ if (syntaxNode is not ClassDeclarationSyntax classDeclaration) return;
+ Classes.Add(classDeclaration);
+ }
+}
\ No newline at end of file
diff --git a/ShadowPluginLoader.SourceGenerator/Receivers/EnumSyntaxReceiver.cs b/ShadowPluginLoader.SourceGenerator/Receivers/EnumSyntaxReceiver.cs
new file mode 100644
index 0000000..2c4693a
--- /dev/null
+++ b/ShadowPluginLoader.SourceGenerator/Receivers/EnumSyntaxReceiver.cs
@@ -0,0 +1,17 @@
+using Microsoft.CodeAnalysis;
+using Microsoft.CodeAnalysis.CSharp.Syntax;
+
+namespace ShadowPluginLoader.SourceGenerator.Receivers;
+
+public class EnumSyntaxReceiver : ISyntaxReceiver
+{
+ public List Enums { get; } = [];
+
+ public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
+ {
+ if (syntaxNode is EnumDeclarationSyntax enumDeclaration)
+ {
+ Enums.Add(enumDeclaration);
+ }
+ }
+}
\ No newline at end of file
diff --git a/ShadowPluginLoader.SourceGenerator/ShadowPluginLoader.SourceGenerator.csproj b/ShadowPluginLoader.SourceGenerator/ShadowPluginLoader.SourceGenerator.csproj
index afb292b..b6bf30c 100644
--- a/ShadowPluginLoader.SourceGenerator/ShadowPluginLoader.SourceGenerator.csproj
+++ b/ShadowPluginLoader.SourceGenerator/ShadowPluginLoader.SourceGenerator.csproj
@@ -6,7 +6,7 @@
enable
latest
- 1.4.15
+ 1.5.1
true
ShadowPluginLoader.SourceGenerator
kitUIN