diff --git a/Directory.Packages.props b/Directory.Packages.props
index fd61602a8..4a74eba02 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -38,6 +38,7 @@
+
@@ -59,4 +60,4 @@
-
\ No newline at end of file
+
diff --git a/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs b/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs
index cdd062826..a5c8e9c5f 100644
--- a/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs
+++ b/src/Ryujinx.HLE.Generators/IpcServiceGenerator.cs
@@ -6,73 +6,73 @@ using System.Linq;
namespace Ryujinx.HLE.Generators
{
[Generator]
- public class IpcServiceGenerator : ISourceGenerator
+ public sealed class IpcServiceGenerator : IIncrementalGenerator
{
- public void Execute(GeneratorExecutionContext context)
+ private sealed record ServiceData
{
- ServiceSyntaxReceiver syntaxReceiver = (ServiceSyntaxReceiver)context.SyntaxReceiver;
- CodeGenerator generator = new();
-
- generator.AppendLine("#nullable enable");
- generator.AppendLine("using System;");
- generator.EnterScope($"namespace Ryujinx.HLE.HOS.Services.Sm");
- generator.EnterScope($"partial class IUserInterface");
-
- generator.EnterScope($"public IpcService? GetServiceInstance(Type type, ServiceCtx context, object? parameter = null)");
- foreach (ClassDeclarationSyntax className in syntaxReceiver.Types)
- {
- if (className.Modifiers.Any(SyntaxKind.AbstractKeyword) || className.Modifiers.Any(SyntaxKind.PrivateKeyword) || !className.AttributeLists.Any(x => x.Attributes.Any(y => y.ToString().StartsWith("Service"))))
- continue;
- string name = GetFullName(className, context).Replace("global::", string.Empty);
- if (!name.StartsWith("Ryujinx.HLE.HOS.Services"))
- continue;
- ConstructorDeclarationSyntax[] constructors = className.ChildNodes().Where(x => x.IsKind(SyntaxKind.ConstructorDeclaration)).Select(y => y as ConstructorDeclarationSyntax).ToArray();
-
- if (!constructors.Any(x => x.ParameterList.Parameters.Count >= 1))
- continue;
-
- if (constructors.Where(x => x.ParameterList.Parameters.Count >= 1).FirstOrDefault().ParameterList.Parameters[0].Type.ToString() == "ServiceCtx")
+ public required string FullName { get; init; }
+ public required bool HasOneParamCtor { get; init; }
+ public required bool HasTwoParamCtor { get; init; }
+ public required string SecondParamTypeFullName { get; init; }
+ }
+
+ public void Initialize(IncrementalGeneratorInitializationContext context)
+ {
+ var pipeline = context.SyntaxProvider.ForAttributeWithMetadataName("Ryujinx.HLE.HOS.Services.ServiceAttribute",
+ predicate: (node, _) => node is ClassDeclarationSyntax decl && !decl.Modifiers.Any(SyntaxKind.AbstractKeyword) && !decl.Modifiers.Any(SyntaxKind.PrivateKeyword),
+ transform: (ctx, _) =>
{
- generator.EnterScope($"if (type == typeof({GetFullName(className, context)}))");
- if (constructors.Any(x => x.ParameterList.Parameters.Count == 2))
+ var target = (INamedTypeSymbol)ctx.TargetSymbol;
+ var twoParamCtor = target.Constructors.FirstOrDefault(ctor => ctor.Parameters.Length == 2);
+ return new ServiceData
{
- TypeSyntax type = constructors.Where(x => x.ParameterList.Parameters.Count == 2).FirstOrDefault().ParameterList.Parameters[1].Type;
- SemanticModel model = context.Compilation.GetSemanticModel(type.SyntaxTree);
- INamedTypeSymbol typeSymbol = model.GetSymbolInfo(type).Symbol as INamedTypeSymbol;
- string fullName = typeSymbol.ToString();
- generator.EnterScope("if (parameter != null)");
- generator.AppendLine($"return new {GetFullName(className, context)}(context, ({fullName})parameter);");
+ FullName = target.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
+ HasOneParamCtor = target.Constructors.Any(ctor => ctor.Parameters.Length == 1),
+ HasTwoParamCtor = twoParamCtor != null,
+ SecondParamTypeFullName = twoParamCtor?.Parameters[1].Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat),
+ };
+ }
+ )
+ .Where(data => data.HasOneParamCtor || data.HasTwoParamCtor);
+
+ context.RegisterSourceOutput(pipeline.Collect(),
+ (ctx, data) =>
+ {
+ var generator = new CodeGenerator();
+
+ generator.AppendLine("#nullable enable");
+ generator.AppendLine("using System;");
+ generator.EnterScope("namespace Ryujinx.HLE.HOS.Services.Sm");
+ generator.EnterScope("partial class IUserInterface");
+
+ generator.EnterScope("public IpcService? GetServiceInstance(Type type, ServiceCtx context, object? parameter = null)");
+
+ foreach (var service in data)
+ {
+ generator.EnterScope($"if (type == typeof({service.FullName}))");
+ if (service.HasTwoParamCtor)
+ {
+ generator.EnterScope("if (parameter != null)");
+ generator.AppendLine($"return new {service.FullName}(context, ({service.SecondParamTypeFullName})parameter);");
+ generator.LeaveScope();
+ }
+ if (service.HasOneParamCtor)
+ {
+ generator.AppendLine($"return new {service.FullName}(context);");
+ }
generator.LeaveScope();
}
-
- if (constructors.Any(x => x.ParameterList.Parameters.Count == 1))
- {
- generator.AppendLine($"return new {GetFullName(className, context)}(context);");
- }
+
+ generator.AppendLine("return null;");
+ generator.LeaveScope();
generator.LeaveScope();
- }
- }
-
- generator.AppendLine("return null;");
- generator.LeaveScope();
-
- generator.LeaveScope();
- generator.LeaveScope();
- generator.AppendLine("#nullable disable");
- context.AddSource($"IUserInterface.g.cs", generator.ToString());
- }
-
- private string GetFullName(ClassDeclarationSyntax syntaxNode, GeneratorExecutionContext context)
- {
- INamedTypeSymbol typeSymbol = context.Compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
-
- return typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
- }
-
- public void Initialize(GeneratorInitializationContext context)
- {
- context.RegisterForSyntaxNotifications(() => new ServiceSyntaxReceiver());
+ generator.LeaveScope();
+
+ generator.AppendLine("#nullable disable");
+
+ ctx.AddSource("IUserInterface.g.cs", generator.ToString());
+ });
}
}
}
diff --git a/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj b/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj
index 4791a3b27..5de37c865 100644
--- a/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj
+++ b/src/Ryujinx.HLE.Generators/Ryujinx.HLE.Generators.csproj
@@ -3,8 +3,6 @@
netstandard2.0
true
- true
- Generated
true
$(DefaultItemExcludes);._*
@@ -15,6 +13,10 @@
runtime; build; native; contentfiles; analyzers; buildtransitive
+
+ all
+ runtime; build; native; contentfiles; analyzers; buildtransitive
+
diff --git a/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs b/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs
deleted file mode 100644
index 7513f5f45..000000000
--- a/src/Ryujinx.HLE.Generators/ServiceSyntaxReceiver.cs
+++ /dev/null
@@ -1,24 +0,0 @@
-using Microsoft.CodeAnalysis;
-using Microsoft.CodeAnalysis.CSharp.Syntax;
-using System.Collections.Generic;
-
-namespace Ryujinx.HLE.Generators
-{
- internal class ServiceSyntaxReceiver : ISyntaxReceiver
- {
- public HashSet Types = [];
-
- public void OnVisitSyntaxNode(SyntaxNode syntaxNode)
- {
- if (syntaxNode is ClassDeclarationSyntax classDeclaration)
- {
- if (classDeclaration.BaseList == null)
- {
- return;
- }
-
- Types.Add(classDeclaration);
- }
- }
- }
-}