MethodReferenceAnalyzer.cs 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687
  1. using dnlib.DotNet;
  2. using System;
  3. using System.Collections.Concurrent;
  4. using System.Collections.Generic;
  5. using System.Linq;
  6. using System.Text;
  7. using System.Threading.Tasks;
  8. namespace HybridCLR.Editor.Meta
  9. {
  10. public class MethodReferenceAnalyzer
  11. {
  12. private readonly Action<GenericMethod> _onNewMethod;
  13. private readonly ConcurrentDictionary<MethodDef, List<IMethod>> _methodEffectInsts = new ConcurrentDictionary<MethodDef, List<IMethod>>();
  14. public MethodReferenceAnalyzer(Action<GenericMethod> onNewMethod)
  15. {
  16. _onNewMethod = onNewMethod;
  17. }
  18. public void WalkMethod(MethodDef method, List<TypeSig> klassGenericInst, List<TypeSig> methodGenericInst)
  19. {
  20. if (klassGenericInst != null || methodGenericInst != null)
  21. {
  22. //var typeSig = klassGenericInst != null ? new GenericInstSig(method.DeclaringType.ToTypeSig().ToClassOrValueTypeSig(), klassGenericInst) : method.DeclaringType?.ToTypeSig();
  23. //Debug.Log($"== walk generic method {typeSig}::{method.Name} {method.MethodSig}");
  24. }
  25. else
  26. {
  27. //Debug.Log($"== walk not geneeric method:{method}");
  28. }
  29. var ctx = new GenericArgumentContext(klassGenericInst, methodGenericInst);
  30. if (_methodEffectInsts.TryGetValue(method, out var effectInsts))
  31. {
  32. foreach (var met in effectInsts)
  33. {
  34. var resolveMet = GenericMethod.ResolveMethod(met, ctx)?.ToGenericShare();
  35. _onNewMethod(resolveMet);
  36. }
  37. return;
  38. }
  39. var body = method.Body;
  40. if (body == null || !body.HasInstructions)
  41. {
  42. return;
  43. }
  44. effectInsts = new List<IMethod>();
  45. foreach (var inst in body.Instructions)
  46. {
  47. if (inst.Operand == null)
  48. {
  49. continue;
  50. }
  51. switch (inst.Operand)
  52. {
  53. case IMethod met:
  54. {
  55. if (!met.IsMethod)
  56. {
  57. continue;
  58. }
  59. var resolveMet = GenericMethod.ResolveMethod(met, ctx)?.ToGenericShare();
  60. if (resolveMet == null)
  61. {
  62. continue;
  63. }
  64. effectInsts.Add(met);
  65. _onNewMethod(resolveMet);
  66. break;
  67. }
  68. case ITokenOperand token:
  69. {
  70. //GenericParamContext paramContext = method.HasGenericParameters || method.DeclaringType.HasGenericParameters ?
  71. // new GenericParamContext(method.DeclaringType, method) : default;
  72. //method.Module.ResolveToken(token.MDToken, paramContext);
  73. break;
  74. }
  75. }
  76. }
  77. _methodEffectInsts.TryAdd(method, effectInsts);
  78. }
  79. }
  80. }