MissingMetadataChecker.cs 3.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109
  1. using dnlib.DotNet;
  2. using HybridCLR.Editor.Meta;
  3. using System;
  4. using System.Collections.Generic;
  5. using System.IO;
  6. using System.Linq;
  7. using System.Text;
  8. using System.Threading.Tasks;
  9. namespace HybridCLR.Editor.HotUpdate
  10. {
  11. public class MissingMetadataChecker
  12. {
  13. private readonly HashSet<string> _aotAssNames;
  14. private readonly HashSet<string> _hotUpdateAssNames;
  15. private readonly AssemblyCache _assCache;
  16. public MissingMetadataChecker(string aotDllDir, IEnumerable<string> hotUpdateAssNames)
  17. {
  18. _hotUpdateAssNames = new HashSet<string>(hotUpdateAssNames ?? new List<string>());
  19. _aotAssNames = new HashSet<string>();
  20. foreach (var aotFile in Directory.GetFiles(aotDllDir, "*.dll"))
  21. {
  22. string aotAssName = Path.GetFileNameWithoutExtension(aotFile);
  23. if (_hotUpdateAssNames.Contains(aotAssName))
  24. {
  25. continue;
  26. }
  27. _aotAssNames.Add(aotAssName);
  28. }
  29. _assCache = new AssemblyCache(new PathAssemblyResolver(aotDllDir));
  30. }
  31. public bool Check(string hotUpdateDllPath)
  32. {
  33. bool anyMissing = false;
  34. ModuleDef mod = ModuleDefMD.Load(File.ReadAllBytes(hotUpdateDllPath), _assCache.ModCtx);
  35. foreach (var refass in mod.GetAssemblyRefs())
  36. {
  37. string refAssName = refass.Name;
  38. if (_aotAssNames.Contains(refAssName))
  39. {
  40. _assCache.LoadModule(refass.Name, true);
  41. }
  42. else if (!_hotUpdateAssNames.Contains(refAssName))
  43. {
  44. UnityEngine.Debug.LogError($"Missing AOT Assembly: {refAssName}");
  45. anyMissing = true;
  46. }
  47. }
  48. foreach (TypeRef typeRef in mod.GetTypeRefs())
  49. {
  50. string defAssName = typeRef.DefinitionAssembly.Name;
  51. if (!_aotAssNames.Contains(defAssName))
  52. {
  53. continue;
  54. }
  55. if (typeRef.ResolveTypeDef() == null)
  56. {
  57. UnityEngine.Debug.LogError($"Missing Type: {typeRef.FullName}");
  58. anyMissing = true;
  59. }
  60. }
  61. foreach (IMethodDefOrRef memberRef in mod.GetMemberRefs())
  62. {
  63. if (memberRef.DeclaringType.DefinitionAssembly == null)
  64. {
  65. continue;
  66. }
  67. string defAssName = memberRef.DeclaringType.DefinitionAssembly.Name;
  68. if (!_aotAssNames.Contains(defAssName))
  69. {
  70. continue;
  71. }
  72. if (memberRef.IsField)
  73. {
  74. IField field = (IField)memberRef;
  75. if (field.ResolveFieldDef() == null)
  76. {
  77. UnityEngine.Debug.LogError($"Missing Field: {memberRef.FullName}");
  78. anyMissing = true;
  79. }
  80. }
  81. else if (memberRef.IsMethod)
  82. {
  83. TypeSig declaringTypeSig = memberRef.DeclaringType.ToTypeSig();
  84. if (memberRef.ResolveMethodDef() == null)
  85. {
  86. if (declaringTypeSig.ElementType == ElementType.Array || declaringTypeSig.ElementType == ElementType.SZArray)
  87. {
  88. continue;
  89. }
  90. UnityEngine.Debug.LogError($"Missing Method: {memberRef.FullName}");
  91. anyMissing = true;
  92. }
  93. }
  94. }
  95. return !anyMissing;
  96. }
  97. }
  98. }