using System; using System.Collections; using System.Collections.Generic; using System.Collections.Immutable; using System.Diagnostics; using System.Linq; using System.Reflection; using System.Runtime.CompilerServices; using System.Runtime.Versioning; using System.Text; using System.Threading; using Hikaria.Core.SourceGenerators.Emitters; using Hikaria.Core.SourceGenerators.Internal; using Microsoft.CodeAnalysis; using Microsoft.CodeAnalysis.CSharp; using Microsoft.CodeAnalysis.CSharp.Syntax; using Microsoft.CodeAnalysis.Text; [assembly: CompilationRelaxations(8)] [assembly: RuntimeCompatibility(WrapNonExceptionThrows = true)] [assembly: Debuggable(DebuggableAttribute.DebuggingModes.IgnoreSymbolStoreSequencePoints)] [assembly: TargetFramework(".NETStandard,Version=v2.0", FrameworkDisplayName = ".NET Standard 2.0")] [assembly: AssemblyCompany("Hikaria.Core.SourceGenerators")] [assembly: AssemblyConfiguration("Release")] [assembly: AssemblyFileVersion("1.0.0.0")] [assembly: AssemblyInformationalVersion("1.0.0+8e797dd13b1c12c7844f86fafa6094111cf7b07a")] [assembly: AssemblyProduct("Hikaria.Core.SourceGenerators")] [assembly: AssemblyTitle("Hikaria.Core.SourceGenerators")] [assembly: AssemblyVersion("1.0.0.0")] [module: RefSafetyRules(11)] namespace Microsoft.CodeAnalysis { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class EmbeddedAttribute : Attribute { } } namespace System.Runtime.CompilerServices { [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] internal sealed class IsReadOnlyAttribute : Attribute { } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Property | AttributeTargets.Field | AttributeTargets.Event | AttributeTargets.Parameter | AttributeTargets.ReturnValue | AttributeTargets.GenericParameter, AllowMultiple = false, Inherited = false)] internal sealed class NullableAttribute : Attribute { public readonly byte[] NullableFlags; public NullableAttribute(byte P_0) { NullableFlags = new byte[1] { P_0 }; } public NullableAttribute(byte[] P_0) { NullableFlags = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Class | AttributeTargets.Struct | AttributeTargets.Method | AttributeTargets.Interface | AttributeTargets.Delegate, AllowMultiple = false, Inherited = false)] internal sealed class NullableContextAttribute : Attribute { public readonly byte Flag; public NullableContextAttribute(byte P_0) { Flag = P_0; } } [CompilerGenerated] [Microsoft.CodeAnalysis.Embedded] [AttributeUsage(AttributeTargets.Module, AllowMultiple = false, Inherited = false)] internal sealed class RefSafetyRulesAttribute : Attribute { public readonly int Version; public RefSafetyRulesAttribute(int P_0) { Version = P_0; } } internal static class IsExternalInit { } } namespace Hikaria.Core.SourceGenerators { internal static class Diagnostics { private const string Category = "NativeDetour"; public static readonly DiagnosticDescriptor EZD001_NotPartial = new DiagnosticDescriptor("EZD001", "包含 [NativeDetour] 方法的类必须声明为 partial", "类 '{0}' 含有 [NativeDetour] 方法,必须声明为 partial 才能由源生成器扩展", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD002_NotStatic = new DiagnosticDescriptor("EZD002", "[NativeDetour] hook 方法必须 static", "[NativeDetour] hook 方法 '{0}' 必须是 static", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD003_BadLastParam = new DiagnosticDescriptor("EZD003", "hook 末参必须是 Il2CppMethodInfo*", "[NativeDetour] hook 方法 '{0}' 的最后一个参数必须是 'Il2CppMethodInfo*' 类型,实际为 '{1}'", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD004_BadFirstParam = new DiagnosticDescriptor("EZD004", "实例方法首参必须是 IntPtr", "[NativeDetour] 实例方法 hook '{0}' 的第一个参数必须是 IntPtr;若目标是静态方法,请在 attribute 上设置 'Static = true'", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD005_DuplicateTarget = new DiagnosticDescriptor("EZD005", "目标方法被多个 hook 重复 detour", "目标方法 '{0}' 已被 '{1}' 注解,不能再由 '{2}' 重复 detour", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD006_StemConflict = new DiagnosticDescriptor("EZD006", "Stem 命名冲突", "类 '{0}' 中存在多个 hook 方法导致生成名称 '{1}_Handle' 冲突", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD007_GenericContainer = new DiagnosticDescriptor("EZD007", "包含类不能是泛型", "[NativeDetour] hook 不能位于泛型类 '{0}<...>' 中", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD008_BadModifier = new DiagnosticDescriptor("EZD008", "hook 方法形态不合法", "[NativeDetour] hook 方法 '{0}' 不能是 {1}", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD009_CtorWithMethodName = new DiagnosticDescriptor("EZD009", "构造器不应填 MethodName", "当 Member=Constructor 时,MethodName 应省略或为空(SG 自动解糖为 \".ctor\")", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD010_PropMissingName = new DiagnosticDescriptor("EZD010", "Getter/Setter 必须有属性名", "Member={0} 时必须提供属性名作为 MethodName", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD011_UnresolvedDeclaringType = new DiagnosticDescriptor("EZD011", "DeclaringType 必须可解析", "[NativeDetour] 的 DeclaringType 无法解析为已知类型", "NativeDetour", (DiagnosticSeverity)3, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD012_TypeArgsIgnored = new DiagnosticDescriptor("EZD012", "TypeArguments 与 Member 不兼容", "TypeArguments 仅在 Member=Method 时有效,当前 Member={0} 将被忽略", "NativeDetour", (DiagnosticSeverity)2, true, (string)null, (string)null, Array.Empty()); public static readonly DiagnosticDescriptor EZD014_GenericMethodExperimental = new DiagnosticDescriptor("EZD014", "方法级泛型 detour 是试验性能力", "方法级泛型 detour 是试验性能力,请验证目标方法能正确解析", "NativeDetour", (DiagnosticSeverity)1, true, (string)null, (string)null, Array.Empty()); } public sealed record HookInfo(string ContainingNamespace, EquatableArray ContainingTypeChain, bool ContainingIsPartial, bool ContainingIsStatic, Accessibility ContainingAccessibility, string HookMethodName, string Stem, string ReturnTypeSyntax, EquatableArray Parameters, bool HookIsStatic, string TargetDeclaringTypeSyntax, string TargetMethodNameOrCtor, NativeDetourMember TargetMember, bool TargetIsStatic, EquatableArray TargetTypeArgumentSyntax, FileLinePositionSpan HookSpan, EquatableArray Diagnostics) { [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { //IL_00a1: Unknown result type (might be due to invalid IL or missing references) //IL_00a6: Unknown result type (might be due to invalid IL or missing references) //IL_0209: Unknown result type (might be due to invalid IL or missing references) //IL_020e: Unknown result type (might be due to invalid IL or missing references) RuntimeHelpers.EnsureSufficientExecutionStack(); builder.Append("ContainingNamespace = "); builder.Append((object?)ContainingNamespace); builder.Append(", ContainingTypeChain = "); builder.Append(ContainingTypeChain.ToString()); builder.Append(", ContainingIsPartial = "); builder.Append(ContainingIsPartial.ToString()); builder.Append(", ContainingIsStatic = "); builder.Append(ContainingIsStatic.ToString()); builder.Append(", ContainingAccessibility = "); Accessibility containingAccessibility = ContainingAccessibility; builder.Append(((object)(Accessibility)(ref containingAccessibility)).ToString()); builder.Append(", HookMethodName = "); builder.Append((object?)HookMethodName); builder.Append(", Stem = "); builder.Append((object?)Stem); builder.Append(", ReturnTypeSyntax = "); builder.Append((object?)ReturnTypeSyntax); builder.Append(", Parameters = "); builder.Append(Parameters.ToString()); builder.Append(", HookIsStatic = "); builder.Append(HookIsStatic.ToString()); builder.Append(", TargetDeclaringTypeSyntax = "); builder.Append((object?)TargetDeclaringTypeSyntax); builder.Append(", TargetMethodNameOrCtor = "); builder.Append((object?)TargetMethodNameOrCtor); builder.Append(", TargetMember = "); builder.Append(TargetMember.ToString()); builder.Append(", TargetIsStatic = "); builder.Append(TargetIsStatic.ToString()); builder.Append(", TargetTypeArgumentSyntax = "); builder.Append(TargetTypeArgumentSyntax.ToString()); builder.Append(", HookSpan = "); FileLinePositionSpan hookSpan = HookSpan; builder.Append(((object)(FileLinePositionSpan)(ref hookSpan)).ToString()); builder.Append(", Diagnostics = "); builder.Append(Diagnostics.ToString()); return true; } [CompilerGenerated] public void Deconstruct(out string ContainingNamespace, out EquatableArray ContainingTypeChain, out bool ContainingIsPartial, out bool ContainingIsStatic, out Accessibility ContainingAccessibility, out string HookMethodName, out string Stem, out string ReturnTypeSyntax, out EquatableArray Parameters, out bool HookIsStatic, out string TargetDeclaringTypeSyntax, out string TargetMethodNameOrCtor, out NativeDetourMember TargetMember, out bool TargetIsStatic, out EquatableArray TargetTypeArgumentSyntax, out FileLinePositionSpan HookSpan, out EquatableArray Diagnostics) { //IL_0028: Unknown result type (might be due to invalid IL or missing references) //IL_002e: Expected I4, but got Unknown //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) ContainingNamespace = this.ContainingNamespace; ContainingTypeChain = this.ContainingTypeChain; ContainingIsPartial = this.ContainingIsPartial; ContainingIsStatic = this.ContainingIsStatic; ContainingAccessibility = (Accessibility)(int)this.ContainingAccessibility; HookMethodName = this.HookMethodName; Stem = this.Stem; ReturnTypeSyntax = this.ReturnTypeSyntax; Parameters = this.Parameters; HookIsStatic = this.HookIsStatic; TargetDeclaringTypeSyntax = this.TargetDeclaringTypeSyntax; TargetMethodNameOrCtor = this.TargetMethodNameOrCtor; TargetMember = this.TargetMember; TargetIsStatic = this.TargetIsStatic; TargetTypeArgumentSyntax = this.TargetTypeArgumentSyntax; HookSpan = this.HookSpan; Diagnostics = this.Diagnostics; } } public sealed record ParamInfo(string TypeSyntax, string Name) : IEquatable; public sealed record DiagnosticInfo(string Id, string Message, FileLinePositionSpan Span) : IEquatable { [CompilerGenerated] private bool PrintMembers(StringBuilder builder) { //IL_0045: Unknown result type (might be due to invalid IL or missing references) //IL_004a: Unknown result type (might be due to invalid IL or missing references) RuntimeHelpers.EnsureSufficientExecutionStack(); builder.Append("Id = "); builder.Append((object?)Id); builder.Append(", Message = "); builder.Append((object?)Message); builder.Append(", Span = "); FileLinePositionSpan span = Span; builder.Append(((object)(FileLinePositionSpan)(ref span)).ToString()); return true; } } public enum NativeDetourMember { Method, Constructor, Getter, Setter } internal static class HookMethodAnalyzer { internal record struct AttrInfo(string DeclaringTypeSyntax, string MethodName, bool IsStatic, NativeDetourMember Member, EquatableArray TypeArgumentSyntax); private const string Il2CppMethodInfoFullName = "global::Il2CppInterop.Runtime.Runtime.Il2CppMethodInfo*"; public static HookInfo? Analyze(GeneratorAttributeSyntaxContext ctx, CancellationToken ct) { //IL_002b: Unknown result type (might be due to invalid IL or missing references) //IL_0030: Unknown result type (might be due to invalid IL or missing references) //IL_0039: Unknown result type (might be due to invalid IL or missing references) //IL_003e: Unknown result type (might be due to invalid IL or missing references) //IL_0041: Unknown result type (might be due to invalid IL or missing references) //IL_004c: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_008a: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) //IL_00e3: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) ISymbol targetSymbol = ((GeneratorAttributeSyntaxContext)(ref ctx)).TargetSymbol; IMethodSymbol val = (IMethodSymbol)(object)((targetSymbol is IMethodSymbol) ? targetSymbol : null); if (val == null) { return null; } SyntaxNode targetNode = ((GeneratorAttributeSyntaxContext)(ref ctx)).TargetNode; MethodDeclarationSyntax val2 = (MethodDeclarationSyntax)(object)((targetNode is MethodDeclarationSyntax) ? targetNode : null); if (val2 == null) { return null; } List list = new List(); SyntaxToken identifier = val2.Identifier; FileLinePositionSpan lineSpan = ((SyntaxToken)(ref identifier)).GetLocation().GetLineSpan(); (string, EquatableArray, bool, bool, Accessibility) tuple = ExtractContainingType(val, val2, lineSpan, list); ValidateHookMethodForm(val, val2, lineSpan, list); AttributeData val3 = ((GeneratorAttributeSyntaxContext)(ref ctx)).Attributes.FirstOrDefault(); if (val3 == null) { return null; } AttrInfo attr = ExtractAttributeInfo(val3, lineSpan, list); ValidateSignature(val, attr.IsStatic, attr.Member, lineSpan, list); ValidateMemberAndMethodName(attr, lineSpan, list); ValidateTypeArguments(attr, lineSpan, list); EquatableArray parameters = ExtractParameters(val); string returnTypeSyntax = TypeSyntax(val.ReturnType); string stem = DeriveStem(((ISymbol)val).Name); string targetMethodNameOrCtor = DesugarTargetMethodName(attr); return new HookInfo(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4, tuple.Item5, ((ISymbol)val).Name, stem, returnTypeSyntax, parameters, ((ISymbol)val).IsStatic, attr.DeclaringTypeSyntax, targetMethodNameOrCtor, attr.Member, attr.IsStatic, attr.TypeArgumentSyntax, lineSpan, new EquatableArray(list)); } private static (string Namespace, EquatableArray Chain, bool IsPartial, bool IsStatic, Accessibility Accessibility) ExtractContainingType(IMethodSymbol m, MethodDeclarationSyntax decl, FileLinePositionSpan loc, List diags) { //IL_0079: Unknown result type (might be due to invalid IL or missing references) //IL_0098: Unknown result type (might be due to invalid IL or missing references) //IL_0118: Unknown result type (might be due to invalid IL or missing references) //IL_00d8: Unknown result type (might be due to invalid IL or missing references) //IL_00dd: Unknown result type (might be due to invalid IL or missing references) //IL_00eb: Unknown result type (might be due to invalid IL or missing references) INamedTypeSymbol containingType = ((ISymbol)m).ContainingType; string item = (((ISymbol)containingType).ContainingNamespace.IsGlobalNamespace ? string.Empty : ((ISymbol)((ISymbol)containingType).ContainingNamespace).ToDisplayString((SymbolDisplayFormat)null)); List list = new List(); for (INamedTypeSymbol val = containingType; val != null; val = ((ISymbol)val).ContainingType) { list.Insert(0, ((ISymbol)val).Name); } if (containingType.IsGenericType || containingType.TypeParameters.Length > 0) { diags.Add(new DiagnosticInfo("EZD007", $"[NativeDetour] hook 不能位于泛型类 '{((ISymbol)containingType).Name}<...>' 中", loc)); } bool item2 = true; SyntaxNode parent = ((SyntaxNode)decl).Parent; TypeDeclarationSyntax val2 = (TypeDeclarationSyntax)(object)((parent is TypeDeclarationSyntax) ? parent : null); while (val2 != null) { if (!((IEnumerable)(object)((MemberDeclarationSyntax)val2).Modifiers).Any((SyntaxToken m2) => CSharpExtensions.IsKind(m2, (SyntaxKind)8406))) { item2 = false; SyntaxToken identifier = ((BaseTypeDeclarationSyntax)val2).Identifier; diags.Add(new DiagnosticInfo("EZD001", $"类 '{((SyntaxToken)(ref identifier)).Text}' 含有 [NativeDetour] 方法,必须声明为 partial 才能由源生成器扩展", loc)); } SyntaxNode parent2 = ((SyntaxNode)val2).Parent; val2 = (TypeDeclarationSyntax)(object)((parent2 is TypeDeclarationSyntax) ? parent2 : null); } return (item, new EquatableArray(list), item2, ((ISymbol)containingType).IsStatic, ((ISymbol)containingType).DeclaredAccessibility); } private static void ValidateHookMethodForm(IMethodSymbol m, MethodDeclarationSyntax decl, FileLinePositionSpan loc, List diags) { //IL_001e: Unknown result type (might be due to invalid IL or missing references) //IL_0093: Unknown result type (might be due to invalid IL or missing references) if (!((ISymbol)m).IsStatic) { diags.Add(new DiagnosticInfo("EZD002", $"[NativeDetour] hook 方法 '{((ISymbol)m).Name}' 必须是 static", loc)); } string text = null; if (((ISymbol)m).IsAbstract) { text = "abstract"; } else if (((ISymbol)m).IsVirtual) { text = "virtual"; } else if (((ISymbol)m).IsExtern) { text = "extern"; } else if (m.IsAsync) { text = "async"; } else if (m.IsPartialDefinition) { text = "partial"; } if (text != null) { diags.Add(new DiagnosticInfo("EZD008", $"[NativeDetour] hook 方法 '{((ISymbol)m).Name}' 不能是 {text}", loc)); } } private static AttrInfo ExtractAttributeInfo(AttributeData attr, FileLinePositionSpan loc, List diags) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0031: Unknown result type (might be due to invalid IL or missing references) //IL_0081: Unknown result type (might be due to invalid IL or missing references) //IL_0086: Unknown result type (might be due to invalid IL or missing references) //IL_0069: Unknown result type (might be due to invalid IL or missing references) //IL_0047: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Invalid comparison between Unknown and I4 //IL_00db: Unknown result type (might be due to invalid IL or missing references) //IL_00e0: Unknown result type (might be due to invalid IL or missing references) //IL_016b: Unknown result type (might be due to invalid IL or missing references) //IL_0170: Unknown result type (might be due to invalid IL or missing references) string declaringTypeSyntax = "global::System.Object"; string methodName = string.Empty; bool isStatic = false; NativeDetourMember member = NativeDetourMember.Method; List list = new List(); ImmutableArray constructorArguments = attr.ConstructorArguments; TypedConstant val; if (constructorArguments.Length >= 1) { val = constructorArguments[0]; object value = ((TypedConstant)(ref val)).Value; INamedTypeSymbol val2 = (INamedTypeSymbol)((value is INamedTypeSymbol) ? value : null); if (val2 != null && (int)((ITypeSymbol)val2).TypeKind != 6) { declaringTypeSyntax = ((ISymbol)val2).ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); } else { diags.Add(new DiagnosticInfo("EZD011", "[NativeDetour] 的 DeclaringType 无法解析为已知类型", loc)); } } if (constructorArguments.Length >= 2) { val = constructorArguments[1]; if (((TypedConstant)(ref val)).Value is string text) { methodName = text; goto IL_00b1; } } if (constructorArguments.Length == 1) { member = NativeDetourMember.Constructor; methodName = string.Empty; } goto IL_00b1; IL_00b1: ImmutableArray>.Enumerator enumerator = attr.NamedArguments.GetEnumerator(); while (enumerator.MoveNext()) { KeyValuePair current = enumerator.Current; string key = current.Key; TypedConstant value2 = current.Value; switch (key) { case "Static": isStatic = (bool)(((TypedConstant)(ref value2)).Value ?? ((object)false)); break; case "Member": member = (NativeDetourMember)(int)(((TypedConstant)(ref value2)).Value ?? ((object)0)); break; case "TypeArguments": { if (((TypedConstant)(ref value2)).Values.IsDefaultOrEmpty) { break; } ImmutableArray.Enumerator enumerator2 = ((TypedConstant)(ref value2)).Values.GetEnumerator(); while (enumerator2.MoveNext()) { TypedConstant current2 = enumerator2.Current; object value3 = ((TypedConstant)(ref current2)).Value; ITypeSymbol val3 = (ITypeSymbol)((value3 is ITypeSymbol) ? value3 : null); if (val3 != null) { list.Add(((ISymbol)val3).ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat)); } } break; } } } return new AttrInfo(declaringTypeSyntax, methodName, isStatic, member, new EquatableArray(list)); } private static void ValidateSignature(IMethodSymbol m, bool targetIsStatic, NativeDetourMember member, FileLinePositionSpan loc, List diags) { //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_009c: Unknown result type (might be due to invalid IL or missing references) //IL_00e6: Unknown result type (might be due to invalid IL or missing references) //IL_00c1: Unknown result type (might be due to invalid IL or missing references) //IL_00c8: Invalid comparison between Unknown and I4 ImmutableArray parameters = m.Parameters; if (parameters.Length == 0) { diags.Add(new DiagnosticInfo("EZD003", "[NativeDetour] hook 方法 '" + ((ISymbol)m).Name + "' 的最后一个参数必须是 'Il2CppMethodInfo*' 类型,实际为 '(无参)'", loc)); return; } string text = ((ISymbol)parameters[parameters.Length - 1].Type).ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); if (text != "global::Il2CppInterop.Runtime.Runtime.Il2CppMethodInfo*") { diags.Add(new DiagnosticInfo("EZD003", "[NativeDetour] hook 方法 '" + ((ISymbol)m).Name + "' 的最后一个参数必须是 'Il2CppMethodInfo*' 类型,实际为 '" + text + "'", loc)); } if (!targetIsStatic && (parameters.Length < 1 || (int)parameters[0].Type.SpecialType != 21)) { diags.Add(new DiagnosticInfo("EZD004", "[NativeDetour] 实例方法 hook '" + ((ISymbol)m).Name + "' 的第一个参数必须是 IntPtr;若目标是静态方法,请在 attribute 上设置 'Static = true'", loc)); } } private static void ValidateMemberAndMethodName(AttrInfo attr, FileLinePositionSpan loc, List diags) { //IL_0023: Unknown result type (might be due to invalid IL or missing references) //IL_006c: Unknown result type (might be due to invalid IL or missing references) if (attr.Member == NativeDetourMember.Constructor && !string.IsNullOrEmpty(attr.MethodName)) { diags.Add(new DiagnosticInfo("EZD009", "当 Member=Constructor 时,MethodName 应省略或为空(SG 自动解糖为 \".ctor\")", loc)); } if ((attr.Member == NativeDetourMember.Getter || attr.Member == NativeDetourMember.Setter) && string.IsNullOrWhiteSpace(attr.MethodName)) { diags.Add(new DiagnosticInfo("EZD010", $"Member={attr.Member} 时必须提供属性名作为 MethodName", loc)); } } private static void ValidateTypeArguments(AttrInfo attr, FileLinePositionSpan loc, List diags) { //IL_0051: Unknown result type (might be due to invalid IL or missing references) //IL_003a: Unknown result type (might be due to invalid IL or missing references) if (!attr.TypeArgumentSyntax.IsEmpty) { if (attr.Member != 0) { diags.Add(new DiagnosticInfo("EZD012", $"TypeArguments 仅在 Member=Method 时有效,当前 Member={attr.Member} 将被忽略", loc)); } else { diags.Add(new DiagnosticInfo("EZD014", "方法级泛型 detour 是试验性能力,请验证目标方法能正确解析", loc)); } } } private static EquatableArray ExtractParameters(IMethodSymbol m) { List list = new List(m.Parameters.Length); ImmutableArray.Enumerator enumerator = m.Parameters.GetEnumerator(); while (enumerator.MoveNext()) { IParameterSymbol current = enumerator.Current; list.Add(new ParamInfo(((ISymbol)current.Type).ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat), ((ISymbol)current).Name)); } return new EquatableArray(list); } private static string TypeSyntax(ITypeSymbol t) { return ((ISymbol)t).ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); } private static string DeriveStem(string hookName) { if (!hookName.EndsWith("_Hook")) { return hookName; } return hookName.Substring(0, hookName.Length - "_Hook".Length); } private static string DesugarTargetMethodName(AttrInfo attr) { return attr.Member switch { NativeDetourMember.Constructor => ".ctor", NativeDetourMember.Getter => "get_" + attr.MethodName, NativeDetourMember.Setter => "set_" + attr.MethodName, _ => attr.MethodName, }; } } [Generator("C#", new string[] { })] public sealed class NativeDetourGenerator : IIncrementalGenerator { public const string AttributeFullName = "Hikaria.Core.Detour.NativeDetourAttribute"; public void Initialize(IncrementalGeneratorInitializationContext context) { //IL_0002: Unknown result type (might be due to invalid IL or missing references) //IL_0007: Unknown result type (might be due to invalid IL or missing references) //IL_004d: Unknown result type (might be due to invalid IL or missing references) //IL_0071: Unknown result type (might be due to invalid IL or missing references) //IL_0095: Unknown result type (might be due to invalid IL or missing references) //IL_009a: Unknown result type (might be due to invalid IL or missing references) //IL_009f: Unknown result type (might be due to invalid IL or missing references) //IL_00a2: Unknown result type (might be due to invalid IL or missing references) SyntaxValueProvider syntaxProvider = ((IncrementalGeneratorInitializationContext)(ref context)).SyntaxProvider; IncrementalValueProvider> val = IncrementalValueProviderExtensions.Collect(IncrementalValueProviderExtensions.Select(IncrementalValueProviderExtensions.Where(((SyntaxValueProvider)(ref syntaxProvider)).ForAttributeWithMetadataName("Hikaria.Core.Detour.NativeDetourAttribute", (Func)((SyntaxNode node, CancellationToken _) => node is MethodDeclarationSyntax), (Func)((GeneratorAttributeSyntaxContext ctx, CancellationToken ct) => HookMethodAnalyzer.Analyze(ctx, ct))), (Func)((HookInfo info) => (object)info != null)), (Func)((HookInfo info, CancellationToken _) => info))); ((IncrementalGeneratorInitializationContext)(ref context)).RegisterSourceOutput>(val, (Action>)delegate(SourceProductionContext ctx, ImmutableArray all) { List list = DetectCrossHookConflicts(all); ImmutableArray.Enumerator enumerator = all.GetEnumerator(); while (enumerator.MoveNext()) { foreach (DiagnosticInfo diagnostic in enumerator.Current.Diagnostics) { ((SourceProductionContext)(ref ctx)).ReportDiagnostic(MakeDiagnostic(diagnostic)); } } foreach (DiagnosticInfo item in list) { ((SourceProductionContext)(ref ctx)).ReportDiagnostic(MakeDiagnostic(item)); } Dictionary> dictionary = new Dictionary>(); enumerator = all.GetEnumerator(); while (enumerator.MoveNext()) { HookInfo current3 = enumerator.Current; if (!current3.Diagnostics.AsImmutableArray().Any(delegate(DiagnosticInfo d) { switch (d.Id) { case "EZD001": case "EZD011": case "EZD002": case "EZD003": case "EZD004": case "EZD007": case "EZD008": case "EZD009": case "EZD010": return true; default: return false; } })) { string key = current3.ContainingNamespace + "::" + string.Join("+", current3.ContainingTypeChain.AsImmutableArray()); if (!dictionary.TryGetValue(key, out var value)) { value = (dictionary[key] = new List()); } value.Add(current3); } } foreach (KeyValuePair> item2 in dictionary) { HookInfo hookInfo = item2.Value[0]; string text = CompanionEmitter.Emit(hookInfo.ContainingNamespace, hookInfo.ContainingTypeChain.AsImmutableArray(), item2.Value); string text2 = string.Join("+", hookInfo.ContainingTypeChain.AsImmutableArray()) + ".NativeDetour.g.cs"; ((SourceProductionContext)(ref ctx)).AddSource(text2, text); } }); } private static List DetectCrossHookConflicts(ImmutableArray all) { //IL_0122: Unknown result type (might be due to invalid IL or missing references) //IL_01f2: Unknown result type (might be due to invalid IL or missing references) List list = new List(); Dictionary dictionary = new Dictionary(); ImmutableArray.Enumerator enumerator = all.GetEnumerator(); while (enumerator.MoveNext()) { HookInfo current = enumerator.Current; if (!current.Diagnostics.AsImmutableArray().Any((DiagnosticInfo d) => d.Id == "EZD011")) { string key = string.Format("{0}.{1}<{2}>[{3}]", current.TargetDeclaringTypeSyntax, current.TargetMethodNameOrCtor, current.TargetMember, string.Join(",", current.TargetTypeArgumentSyntax.AsImmutableArray())); if (dictionary.TryGetValue(key, out var value)) { list.Add(new DiagnosticInfo("EZD005", "目标方法 '" + current.TargetDeclaringTypeSyntax + "." + current.TargetMethodNameOrCtor + "' 已被 '" + value.HookMethodName + "' 注解,不能再由 '" + current.HookMethodName + "' 重复 detour", current.HookSpan)); } else { dictionary[key] = current; } } } Dictionary dictionary2 = new Dictionary(); enumerator = all.GetEnumerator(); while (enumerator.MoveNext()) { HookInfo current2 = enumerator.Current; string text = current2.ContainingNamespace + "." + string.Join("+", current2.ContainingTypeChain.AsImmutableArray()); string key2 = text + "::" + current2.Stem; if (dictionary2.TryGetValue(key2, out var _)) { list.Add(new DiagnosticInfo("EZD006", "类 '" + text + "' 中存在多个 hook 方法导致生成名称 '" + current2.Stem + "_Handle' 冲突", current2.HookSpan)); } else { dictionary2[key2] = current2; } } return list; } private static Diagnostic MakeDiagnostic(DiagnosticInfo info) { //IL_000d: Unknown result type (might be due to invalid IL or missing references) //IL_0012: Unknown result type (might be due to invalid IL or missing references) //IL_001c: Unknown result type (might be due to invalid IL or missing references) //IL_0022: Unknown result type (might be due to invalid IL or missing references) //IL_0024: Unknown result type (might be due to invalid IL or missing references) //IL_0029: Unknown result type (might be due to invalid IL or missing references) //IL_002c: Unknown result type (might be due to invalid IL or missing references) //IL_0055: Unknown result type (might be due to invalid IL or missing references) //IL_0067: Unknown result type (might be due to invalid IL or missing references) //IL_0077: Expected O, but got Unknown DiagnosticDescriptor val = ResolveDescriptor(info.Id); FileLinePositionSpan span = info.Span; string path = ((FileLinePositionSpan)(ref span)).Path; span = info.Span; Location val2 = Location.Create(path, default(TextSpan), ((FileLinePositionSpan)(ref span)).Span); return Diagnostic.Create(new DiagnosticDescriptor(val.Id, val.Title, LocalizableString.op_Implicit(info.Message), val.Category, val.DefaultSeverity, val.IsEnabledByDefault, (LocalizableString)null, (string)null, Array.Empty()), val2, Array.Empty()); } private static DiagnosticDescriptor ResolveDescriptor(string id) { return (DiagnosticDescriptor)(id switch { "EZD001" => Diagnostics.EZD001_NotPartial, "EZD002" => Diagnostics.EZD002_NotStatic, "EZD003" => Diagnostics.EZD003_BadLastParam, "EZD004" => Diagnostics.EZD004_BadFirstParam, "EZD005" => Diagnostics.EZD005_DuplicateTarget, "EZD006" => Diagnostics.EZD006_StemConflict, "EZD007" => Diagnostics.EZD007_GenericContainer, "EZD008" => Diagnostics.EZD008_BadModifier, "EZD009" => Diagnostics.EZD009_CtorWithMethodName, "EZD010" => Diagnostics.EZD010_PropMissingName, "EZD011" => Diagnostics.EZD011_UnresolvedDeclaringType, "EZD012" => Diagnostics.EZD012_TypeArgsIgnored, "EZD014" => Diagnostics.EZD014_GenericMethodExperimental, _ => throw new InvalidOperationException("未知 EZD: " + id), }); } } } namespace Hikaria.Core.SourceGenerators.Internal { public readonly struct EquatableArray : IEquatable>, IEnumerable, IEnumerable where T : IEquatable { public static readonly EquatableArray Empty = new EquatableArray(ImmutableArray.Empty); private readonly ImmutableArray _array; public int Length { get { if (!_array.IsDefault) { return _array.Length; } return 0; } } public bool IsEmpty => Length == 0; public T this[int index] => _array[index]; public EquatableArray(ImmutableArray array) { _array = array; } public EquatableArray(IEnumerable source) { _array = source?.ToImmutableArray() ?? ImmutableArray.Empty; } public ImmutableArray AsImmutableArray() { if (!_array.IsDefault) { return _array; } return ImmutableArray.Empty; } public bool Equals(EquatableArray other) { if (Length != other.Length) { return false; } for (int i = 0; i < Length; i++) { if (!_array[i].Equals(other._array[i])) { return false; } } return true; } public override bool Equals(object obj) { if (obj is EquatableArray other) { return Equals(other); } return false; } public override int GetHashCode() { if (_array.IsDefault) { return 0; } int num = 17; ImmutableArray.Enumerator enumerator = _array.GetEnumerator(); while (enumerator.MoveNext()) { num = num * 31 + (enumerator.Current?.GetHashCode() ?? 0); } return num; } public IEnumerator GetEnumerator() { return AsImmutableArray().AsEnumerable().GetEnumerator(); } IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } public static bool operator ==(EquatableArray a, EquatableArray b) { return a.Equals(b); } public static bool operator !=(EquatableArray a, EquatableArray b) { return !a.Equals(b); } } } namespace Hikaria.Core.SourceGenerators.Emitters { internal static class CompanionEmitter { private const string HandleType = "global::Hikaria.Core.Detour.NativeDetourHandle"; private const string DescriptorType = "global::Hikaria.Core.Detour.DetourDescriptor"; private const string NativeDetourType = "global::Hikaria.Core.Detour.NativeDetour"; private const string TypeArrayType = "global::System.Type"; private const string UnmanagedFunctionPointerAttr = "global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute"; private const string CallingConvCdecl = "global::System.Runtime.InteropServices.CallingConvention.Cdecl"; public static string Emit(string @namespace, IReadOnlyList typeChain, IReadOnlyList hooks) { StringBuilder stringBuilder = new StringBuilder(2048); EmitHeader(stringBuilder); EmitNamespaceOpen(stringBuilder, @namespace); EmitTypeChainOpen(stringBuilder, typeChain); foreach (HookInfo hook in hooks) { EmitHookMembers(stringBuilder, hook); } EmitContainerAggregators(stringBuilder, hooks); EmitTypeChainClose(stringBuilder, typeChain); EmitNamespaceClose(stringBuilder, @namespace); return stringBuilder.ToString(); } private static void EmitHeader(StringBuilder sb) { sb.AppendLine("// "); sb.AppendLine("// Generated by Hikaria.Core.SourceGenerators.NativeDetourGenerator"); sb.AppendLine("#nullable disable"); sb.AppendLine("#pragma warning disable CS8019 // unused usings"); sb.AppendLine(); } private static void EmitNamespaceOpen(StringBuilder sb, string ns) { if (!string.IsNullOrEmpty(ns)) { sb.Append("namespace ").Append(ns).AppendLine() .AppendLine("{"); } } private static void EmitNamespaceClose(StringBuilder sb, string ns) { if (!string.IsNullOrEmpty(ns)) { sb.AppendLine("}"); } } private static void EmitTypeChainOpen(StringBuilder sb, IReadOnlyList chain) { for (int i = 0; i < chain.Count; i++) { sb.Append(" unsafe partial class ").Append(chain[i]).AppendLine() .AppendLine(" {"); } } private static void EmitTypeChainClose(StringBuilder sb, IReadOnlyList chain) { for (int num = chain.Count - 1; num >= 0; num--) { sb.AppendLine(" }"); } } private static void EmitHookMembers(StringBuilder sb, HookInfo h) { string stem = h.Stem; sb.Append(" [").Append("global::System.Runtime.InteropServices.UnmanagedFunctionPointerAttribute").Append('(') .Append("global::System.Runtime.InteropServices.CallingConvention.Cdecl") .AppendLine(")]"); sb.Append(" private delegate ").Append(h.ReturnTypeSyntax).Append(' ') .Append(stem) .Append("_HookDelegate("); EmitParamList(sb, h.Parameters); sb.AppendLine(");"); sb.AppendLine(); sb.Append(" private static readonly ").Append("global::Hikaria.Core.Detour.NativeDetourHandle").Append('<') .Append(stem) .Append("_HookDelegate> "); sb.Append(stem).Append("_Handle = ").Append("global::Hikaria.Core.Detour.NativeDetour") .Append(".Create<") .Append(stem) .Append("_HookDelegate>(") .AppendLine(); sb.Append(" new ").Append("global::Hikaria.Core.Detour.DetourDescriptor").AppendLine(); sb.AppendLine(" {"); sb.Append(" Type = typeof(").Append(h.TargetDeclaringTypeSyntax).AppendLine("),"); sb.Append(" MethodName = \"").Append(h.TargetMethodNameOrCtor).AppendLine("\","); sb.Append(" ReturnType = typeof(").Append(EmitDescriptorReturnType(h)).AppendLine("),"); sb.Append(" ArgTypes = new ").Append("global::System.Type").Append("[] { "); EmitDescriptorArgTypes(sb, h); sb.AppendLine(" },"); sb.Append(" IsGeneric = ").Append(h.TargetTypeArgumentSyntax.IsEmpty ? "false" : "true").AppendLine(","); if (!h.TargetTypeArgumentSyntax.IsEmpty) { sb.Append(" GenericTypeArguments = new ").Append("global::System.Type").Append("[] { "); bool flag = true; foreach (string item in h.TargetTypeArgumentSyntax) { if (!flag) { sb.Append(", "); } sb.Append("typeof(").Append(item).Append(')'); flag = false; } sb.AppendLine(" },"); } sb.AppendLine(" },"); sb.Append(" ").Append(h.HookMethodName).AppendLine(");"); sb.AppendLine(); sb.Append(" private static ").Append(stem).Append("_HookDelegate ") .Append(stem) .Append("_Original => ") .Append(stem) .AppendLine("_Handle.Original;"); sb.AppendLine(); sb.Append(" public static bool ").Append(stem).Append("_Apply() => ") .Append(stem) .AppendLine("_Handle.Apply();"); sb.Append(" public static void ").Append(stem).Append("_Dispose() => ") .Append(stem) .AppendLine("_Handle.Dispose();"); sb.AppendLine(); } private static void EmitContainerAggregators(StringBuilder sb, IReadOnlyList hooks) { sb.AppendLine(" public static void ApplyAll()"); sb.AppendLine(" {"); foreach (HookInfo hook in hooks) { sb.Append(" ").Append(hook.Stem).AppendLine("_Apply();"); } sb.AppendLine(" }"); sb.AppendLine(); sb.AppendLine(" public static void DisposeAll()"); sb.AppendLine(" {"); foreach (HookInfo hook2 in hooks) { sb.Append(" ").Append(hook2.Stem).AppendLine("_Dispose();"); } sb.AppendLine(" }"); sb.AppendLine(); } private static void EmitParamList(StringBuilder sb, EquatableArray ps) { bool flag = true; foreach (ParamInfo item in ps) { if (!flag) { sb.Append(", "); } sb.Append(item.TypeSyntax).Append(' ').Append(item.Name); flag = false; } } private static string EmitDescriptorReturnType(HookInfo h) { if (h.TargetMember != NativeDetourMember.Constructor) { return h.ReturnTypeSyntax; } return "void"; } private static void EmitDescriptorArgTypes(StringBuilder sb, HookInfo h) { bool num = !h.TargetIsStatic; int num2 = h.Parameters.Length - 1; bool flag = true; for (int i = (num ? 1 : 0); i < num2; i++) { if (!flag) { sb.Append(", "); } sb.Append("typeof(").Append(h.Parameters[i].TypeSyntax).Append(')'); flag = false; } } } }