Skip to content

Instantly share code, notes, and snippets.

@magicxor
Created October 27, 2024 03:42
Show Gist options
  • Select an option

  • Save magicxor/5abc3df8dadd61e1329d87681d6bdf3c to your computer and use it in GitHub Desktop.

Select an option

Save magicxor/5abc3df8dadd61e1329d87681d6bdf3c to your computer and use it in GitHub Desktop.
Retrieve possible exceptions
using System.Collections.Concurrent;
using System.Xml.Linq;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ExceptionRetriever;
public class ExceptionExtractor
{
public static void ExtractExceptions(string assemblyPath, string xmlDocPath)
{
var assembly = AssemblyDefinition.ReadAssembly(assemblyPath);
var xmlDoc = XDocument.Load(xmlDocPath);
var allMethodsExceptions = new ConcurrentDictionary<string, HashSet<string>>();
foreach (var type in assembly.MainModule.Types)
{
foreach (var method in type.Methods)
{
if (!method.HasBody) continue;
foreach (var instruction in method.Body.Instructions)
{
MethodReference methodReference = null;
// Проверка на вызов методов
if (instruction.OpCode == OpCodes.Call || instruction.OpCode == OpCodes.Callvirt)
{
methodReference = instruction.Operand as MethodReference;
}
// Проверка на вызов конструкторов
else if (instruction.OpCode == OpCodes.Newobj)
{
methodReference = instruction.Operand as MethodReference;
}
// Если найден вызов метода или конструктора из System.IO
if (methodReference != null && methodReference.DeclaringType.Namespace.StartsWith("System.IO"))
{
// Ищем исключения в XML-документации
var exceptions = GetExceptionsFromXmlDoc(xmlDoc, methodReference);
foreach (var ex in exceptions)
{
var methodExceptions = allMethodsExceptions.GetOrAdd(method.FullName, _ => new HashSet<string>());
methodExceptions.Add(ex);
}
}
}
}
}
foreach (var methodExceptions in allMethodsExceptions)
{
Console.WriteLine(methodExceptions.Key + " throws: " + string.Join(", ", methodExceptions.Value));
Console.WriteLine(Environment.NewLine);
}
}
private static IEnumerable<string> GetExceptionsFromXmlDoc(XDocument xmlDoc, MethodReference methodReference)
{
// Собираем имя метода вместе с типами параметров, чтобы точно найти нужную перегрузку
var methodSignature = $"{methodReference.DeclaringType.FullName}.{methodReference.Name}({string.Join(",", methodReference.Parameters.Select(p => p.ParameterType.FullName))})";
// Ищем элемент member, у которого атрибут name соответствует точной сигнатуре метода
var member = xmlDoc.Descendants("member")
.FirstOrDefault(m => m.Attribute("name")?.Value == $"M:{methodSignature}");
if (member == null) yield break;
foreach (var exceptionElement in member.Descendants("exception"))
{
yield return exceptionElement.Attribute("cref")?.Value;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment