Skip to content

Instantly share code, notes, and snippets.

@mattwarren
Created May 13, 2015 11:25
Show Gist options
  • Save mattwarren/33edc6d07ea087542ccb to your computer and use it in GitHub Desktop.
Save mattwarren/33edc6d07ea087542ccb to your computer and use it in GitHub Desktop.
Using Cecil to find all the types in "System." assemblies that DON'T override ToString()
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using Mono.Cecil;
namespace ClrToStringOverrides
{
internal class Program
{
private static void Main(string[] args)
{
if (args.Length == 0)
args = new[]
{
@"C:\Windows\assembly\gac_32",
@"C:\Windows\assembly\gac_msil",
@"C:\Windows\assembly\gac_64"
};
var assemblies =
args.SelectMany(dir => Directory.GetFiles(dir, "*.dll", SearchOption.AllDirectories)).ToArray();
bool valueTypes = false;
//bool valueTypes = true;
var fileName = String.Format("{0} Types That Do Not Override ToString", valueTypes ? "VALUE" : "REFERENCE");
using (var fullOutfile = new StreamWriter(fileName + ".txt", append: false))
using (var summaryOutfile = new StreamWriter(fileName + "-SUMMARY.txt", append: false))
{
var analyser = new Analyzer(assemblies);
analyser.Analyze(fullOutfile, summaryOutfile, valueTypes);
}
}
}
internal class Analyzer
{
private readonly string[] _assemblies;
private readonly IAssemblyResolver _resolver;
public Analyzer(string[] assemblies)
{
_assemblies = assemblies;
_resolver = new DefaultAssemblyResolver();
}
public void Analyze(StreamWriter fullStream, StreamWriter summaryStream, bool valueTypes)
{
var counter = 0;
foreach (var file in _assemblies)
{
var assembly = ReadAssembly(file);
if (assembly != null)
{
var results = Analyze(assembly, valueTypes);
if (results.Count > 0)
{
var msg = String.Format("{0} - {1} types that don't override ToString()", file, results.Count);
fullStream.WriteLine(msg);
summaryStream.WriteLine(msg);
Console.WriteLine(msg);
fullStream.WriteLine(" " + String.Join("\n ", results));
counter += results.Count;
}
}
}
var summary = String.Format("\nIn total there are {0:N0} {1} types that don't override ToString()\n",
counter, valueTypes ? "VALUE" : "REFERENCE");
fullStream.WriteLine(summary);
summaryStream.WriteLine(summary);
Console.WriteLine(summary);
}
private AssemblyDefinition ReadAssembly(string file)
{
try
{
return AssemblyDefinition.ReadAssembly(file, new ReaderParameters {AssemblyResolver = _resolver});
}
catch
{
return null;
}
}
private IList<String> Analyze(AssemblyDefinition assembly, bool valueTypes)
{
var types = assembly.MainModule.GetTypes();
var results = new List<String>(50);
foreach (var typeDefinition in types.Where(t => t.IsPublic &&
t.FullName.StartsWith("System.") &&
t.IsAbstract == false &&
t.IsInterface == false &&
t.IsValueType == valueTypes))
{
if (!typeDefinition.HasMethods)
continue;
var toStringMethods = typeDefinition.Methods
.Where(m => m.IsPublic &&
m.Name == "ToString" &&
m.Parameters.Count == 0 &&
m.ReturnType.FullName == "System.String" &&
m.IsAbstract == false &&
m.IsNewSlot == false)
.ToList();
if (toStringMethods.Count > 1)
Console.WriteLine("ERROR there are more than 1 ToString() methods!!!");
else if (toStringMethods.Count == 0)
results.Add(typeDefinition.FullName);
}
return results;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment