Created
May 13, 2015 11:25
-
-
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()
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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