/ src / Ryujinx.HLE.Generators / IpcServiceGenerator.cs
IpcServiceGenerator.cs
 1  using Microsoft.CodeAnalysis;
 2  using Microsoft.CodeAnalysis.CSharp;
 3  using Microsoft.CodeAnalysis.CSharp.Syntax;
 4  using System.Linq;
 5  
 6  namespace Ryujinx.HLE.Generators
 7  {
 8      [Generator]
 9      public class IpcServiceGenerator : ISourceGenerator
10      {
11          public void Execute(GeneratorExecutionContext context)
12          {
13              var syntaxReceiver = (ServiceSyntaxReceiver)context.SyntaxReceiver;
14              CodeGenerator generator = new CodeGenerator();
15  
16              generator.AppendLine("using System;");
17              generator.EnterScope($"namespace Ryujinx.HLE.HOS.Services.Sm");
18              generator.EnterScope($"partial class IUserInterface");
19  
20              generator.EnterScope($"public IpcService? GetServiceInstance(Type type, ServiceCtx context, object? parameter = null)");
21              foreach (var className in syntaxReceiver.Types)
22              {
23                  if (className.Modifiers.Any(SyntaxKind.AbstractKeyword) || className.Modifiers.Any(SyntaxKind.PrivateKeyword) || !className.AttributeLists.Any(x => x.Attributes.Any(y => y.ToString().StartsWith("Service"))))
24                      continue;
25                  var name = GetFullName(className, context).Replace("global::", "");
26                  if (!name.StartsWith("Ryujinx.HLE.HOS.Services"))
27                      continue;
28                  var constructors = className.ChildNodes().Where(x => x.IsKind(SyntaxKind.ConstructorDeclaration)).Select(y => y as ConstructorDeclarationSyntax);
29  
30                  if (!constructors.Any(x => x.ParameterList.Parameters.Count >= 1))
31                      continue;
32  
33                  if (constructors.Where(x => x.ParameterList.Parameters.Count >= 1).FirstOrDefault().ParameterList.Parameters[0].Type.ToString() == "ServiceCtx")
34                  {
35                      generator.EnterScope($"if (type == typeof({GetFullName(className, context)}))");
36                      if (constructors.Any(x => x.ParameterList.Parameters.Count == 2))
37                      {
38                          var type = constructors.Where(x => x.ParameterList.Parameters.Count == 2).FirstOrDefault().ParameterList.Parameters[1].Type;
39                          var model = context.Compilation.GetSemanticModel(type.SyntaxTree);
40                          var typeSymbol = model.GetSymbolInfo(type).Symbol as INamedTypeSymbol;
41                          var fullName = typeSymbol.ToString();
42                          generator.EnterScope("if (parameter != null)");
43                          generator.AppendLine($"return new {GetFullName(className, context)}(context, ({fullName})parameter);");
44                          generator.LeaveScope();
45                      }
46  
47                      if (constructors.Any(x => x.ParameterList.Parameters.Count == 1))
48                      {
49                          generator.AppendLine($"return new {GetFullName(className, context)}(context);");
50                      }
51  
52                      generator.LeaveScope();
53                  }
54              }
55  
56              generator.AppendLine("return null;");
57              generator.LeaveScope();
58  
59              generator.LeaveScope();
60              generator.LeaveScope();
61              context.AddSource($"IUserInterface.g.cs", generator.ToString());
62          }
63  
64          private string GetFullName(ClassDeclarationSyntax syntaxNode, GeneratorExecutionContext context)
65          {
66              var typeSymbol = context.Compilation.GetSemanticModel(syntaxNode.SyntaxTree).GetDeclaredSymbol(syntaxNode);
67  
68              return typeSymbol.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat);
69          }
70  
71          public void Initialize(GeneratorInitializationContext context)
72          {
73              context.RegisterForSyntaxNotifications(() => new ServiceSyntaxReceiver());
74          }
75      }
76  }