-
Notifications
You must be signed in to change notification settings - Fork 0
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
11 changed files
with
246 additions
and
17 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 |
---|---|---|
|
@@ -32,7 +32,7 @@ public override string GetEmoji() | |
{ | ||
return "💡😭"; | ||
} | ||
|
||
public override string DisplayName => ""; | ||
} | ||
} |
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,11 @@ | ||
using ShadowExample.Core; | ||
using ShadowPluginLoader.MetaAttributes; | ||
|
||
namespace ShadowExample.Plugin.Emoji.ViewModels; | ||
|
||
public partial class Test2ViewModel: TestViewModel | ||
{ | ||
[Autowired] | ||
public ShadowExamplePluginLoader ShadowExamplePluginLoader { get; } | ||
|
||
} |
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,10 @@ | ||
using ShadowPluginLoader.MetaAttributes; | ||
using ShadowPluginLoader.WinUI; | ||
|
||
namespace ShadowExample.Plugin.Emoji.ViewModels; | ||
|
||
public partial class TestViewModel | ||
{ | ||
[Autowired] | ||
public PluginEventService PluginEventService { get; } | ||
} |
136 changes: 136 additions & 0 deletions
136
ShadowPluginLoader.SourceGenerator/Generators/AutowiredGenerator.cs
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,136 @@ | ||
using Microsoft.CodeAnalysis; | ||
using ShadowPluginLoader.SourceGenerator.Helpers; | ||
using ShadowPluginLoader.SourceGenerator.Models; | ||
using ShadowPluginLoader.SourceGenerator.Receivers; | ||
|
||
namespace ShadowPluginLoader.SourceGenerator.Generators; | ||
|
||
/// <summary> | ||
/// | ||
/// </summary> | ||
[Generator] | ||
public class AutowiredGenerator : ISourceGenerator | ||
{ | ||
private Dictionary<string, List<BaseConstructor>> 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); | ||
} | ||
|
||
/// <inheritdoc /> | ||
public void Initialize(GeneratorInitializationContext context) | ||
{ | ||
context.RegisterForSyntaxNotifications(() => new AutowiredClassSyntaxReceiver()); | ||
} | ||
|
||
/// <inheritdoc /> | ||
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<INamedTypeSymbol>()); | ||
foreach (var classSymbol in sortedClasses) | ||
{ | ||
var properties = classSymbol.GetMembers() | ||
.OfType<IPropertySymbol>().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<string>(); | ||
var assignments = new List<string>(); | ||
var baseConstructors = new List<string>(); | ||
var constructorRecord = new List<BaseConstructor>(); | ||
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<IMethodSymbol>() | ||
.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); | ||
} | ||
} | ||
} |
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
41 changes: 41 additions & 0 deletions
41
ShadowPluginLoader.SourceGenerator/Helpers/InheritanceSorter.cs
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,41 @@ | ||
namespace ShadowPluginLoader.SourceGenerator.Helpers; | ||
|
||
using Microsoft.CodeAnalysis; | ||
using System.Collections.Generic; | ||
public class CustomSymbolComparer : IEqualityComparer<INamedTypeSymbol> | ||
{ | ||
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<INamedTypeSymbol> SortTypesByInheritance(IEnumerable<INamedTypeSymbol> types) | ||
{ | ||
// 创建一个字典存储每个类型的继承链 | ||
var inheritanceChains = new Dictionary<INamedTypeSymbol, List<INamedTypeSymbol>>(new CustomSymbolComparer()); | ||
|
||
var namedTypeSymbols = types as INamedTypeSymbol[] ?? types.ToArray(); | ||
foreach (var type in namedTypeSymbols) | ||
{ | ||
var chain = new List<INamedTypeSymbol>(); | ||
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; | ||
} | ||
} |
11 changes: 11 additions & 0 deletions
11
ShadowPluginLoader.SourceGenerator/Models/BaseConstructor.cs
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,11 @@ | ||
namespace ShadowPluginLoader.SourceGenerator.Models | ||
{ | ||
public record BaseConstructor(string Type, string Name); | ||
} | ||
|
||
namespace System.Runtime.CompilerServices | ||
{ | ||
class IsExternalInit | ||
{ | ||
} | ||
} |
15 changes: 15 additions & 0 deletions
15
ShadowPluginLoader.SourceGenerator/Receivers/AutowiredClassSyntaxReceiver.cs
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,15 @@ | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
|
||
namespace ShadowPluginLoader.SourceGenerator.Receivers; | ||
|
||
public class AutowiredClassSyntaxReceiver : ISyntaxReceiver | ||
{ | ||
public List<ClassDeclarationSyntax> Classes { get; } = []; | ||
|
||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode) | ||
{ | ||
if (syntaxNode is not ClassDeclarationSyntax classDeclaration) return; | ||
Classes.Add(classDeclaration); | ||
} | ||
} |
17 changes: 17 additions & 0 deletions
17
ShadowPluginLoader.SourceGenerator/Receivers/EnumSyntaxReceiver.cs
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,17 @@ | ||
using Microsoft.CodeAnalysis; | ||
using Microsoft.CodeAnalysis.CSharp.Syntax; | ||
|
||
namespace ShadowPluginLoader.SourceGenerator.Receivers; | ||
|
||
public class EnumSyntaxReceiver : ISyntaxReceiver | ||
{ | ||
public List<EnumDeclarationSyntax> Enums { get; } = []; | ||
|
||
public void OnVisitSyntaxNode(SyntaxNode syntaxNode) | ||
{ | ||
if (syntaxNode is EnumDeclarationSyntax enumDeclaration) | ||
{ | ||
Enums.Add(enumDeclaration); | ||
} | ||
} | ||
} |
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