Click here to Skip to main content
15,886,639 members
Articles / Programming Languages / MSIL

Code Analysis Tools - A collection of IL code analysis tools

Rate me:
Please Sign up or sign in to vote.
4.96/5 (41 votes)
1 Sep 2006CPOL24 min read 231.2K   1.6K   138  
This tool analyses the IL of a list of assemblies, looking for types, methods, and fields that are not used by another list of assemblies. This lets you see if you have unused legacy code lying around that should be cleaned up.
using System;
using System.Diagnostics;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;
using System.Reflection;
using Microsoft.Cci;

namespace NotUsedFinder
{
	/// <summary>
	/// This class spins through Modules and catalogs every type, method and field in that module.
	/// These catalogs will be used later by the analyzer in order to determine what members are not used
	/// </summary>
	public class AssemblyCataloger
	{
		private Dictionary<string, MyTypeNode> typeCatalog = new Dictionary<string, MyTypeNode>();
        private Dictionary<string, MyMethodNode> methodCatalog = new Dictionary<string, MyMethodNode>();
        private Dictionary<string, MyFieldNode> fieldCatalog = new Dictionary<string, MyFieldNode>();
		private AnalysisOptions options;

		public AssemblyCataloger(AnalysisOptions options)
		{					
			this.options = options;
		}

		public void Catalog(Microsoft.Cci.Module module)
		{
			//spin through the module and catalog each type
			foreach (TypeNode type in module.Types)
			{
				CatalogType(type);
			}
		}

		private void CatalogType(TypeNode type)
		{
			//Filter out types that start with < because these are generated by the compiler
			if (type.FullName.StartsWith("<"))
				return;

			//rip through the type and catalog all its parts
			this.VisitTypeNode(type);

			//check for and catalog nested types recursivly
			foreach (TypeNode nestedType in type.NestedTypes)
				this.CatalogType(nestedType);
		}

		private void VisitTypeNode(TypeNode type)
		{
			//Filter out types that start with < because these are generated by the compiler
			if (!type.FullName.StartsWith("<"))
			{
				//use MyTypeNode wrapper in order to use full type hierarchy
				MyTypeNode myType = new MyTypeNode(type);

				//Add type to catalog
				if (!typeCatalog.ContainsKey(myType.FullName))
					typeCatalog.Add(myType.FullName, myType);

				//now catalog entire type hierarchy, from lowest base class to all sub classes
				CatalogTypeHierarcy(myType);

				//look for and catalog every method and field
				foreach (Member member in type.Members)
				{
					Field field = member as Field;
					if (field != null)
					{
						VisitField(field);
						continue;
					}			

					Method method = member as Method;
					if (method != null)
					{
						VisitMethod(method);												
						continue;
					}
				}
			}			
		}

		/// <summary>
		/// Catalog the entire inheritance hierarchy
		/// </summary>
		Type objType = typeof(System.Object);
		private void CatalogTypeHierarcy(MyTypeNode myType)
		{
			//dont worry about it if type doesnt have a base or base is object
			if (myType.thisType.BaseType != null && myType.thisType.BaseType.FullName != objType.FullName)
			{												
				MyTypeNode baseType = null;
				if (typeCatalog.ContainsKey(myType.thisType.BaseType.FullName))
				{
					//get base type
					baseType = typeCatalog[myType.thisType.BaseType.FullName];
				}
				else
				{
					//create base type
					baseType = new MyTypeNode(myType.thisType.BaseType);
					//Add base type to catalog
					typeCatalog.Add(baseType.FullName, baseType);
				}

				//add base as sub's base
				myType.baseType = baseType;

				//add sub as base's sub
				if (!baseType.subTypes.Contains(myType))
					baseType.subTypes.Add(myType);

				//recursivly catalog base types
				CatalogTypeHierarcy(baseType);
			}
		}

		private void VisitMethod(Method method)
		{
			if (options.AnalyzeForMethods)
			{			
				//Filter out static ctors
				if (method.Name.Name == ".cctor")
					return;
				
				if (method.Name.Name == ".ctor")
				{
					//Filter out default instance ctors.  These are either required or generated by the compiler
					if (method.Parameters.Length == 0)
						return;
					else if (method.DeclaringType.BaseType != null)
					{
						//Filter out ctor if it has parms AND its base class has a matching ctor
						Method baseCtor = method.DeclaringType.BaseType.GetMatchingMethod(method);						
						if (baseCtor != null)
							return;
					}
				}

				//Filter out finalizers since they are not called explicitly
				if (method.Name.Name == "Finalize")
					return;

				if (!methodCatalog.ContainsKey(method.FullName))
					methodCatalog.Add(method.FullName, new MyMethodNode(method));
			}
		}

		private void VisitField(Field field)
		{			
			//Check for literal (const) because the value just gets put into the IL and you cant check for the field name.
			//Also check for "value__" for a field name.  not sure what this is, but every enum has a field with this name.
			if (options.AnalyzeForFields && 
				!field.IsLiteral && 
				field.Name.Name != "value__")
			{
				if (!fieldCatalog.ContainsKey(field.FullName))
					fieldCatalog.Add(field.FullName, new MyFieldNode(field));
			}
		}

		public Dictionary<string, MyTypeNode> TypeCatalog
		{
			get { return typeCatalog; }
		}

		public Dictionary<string, MyMethodNode> MethodCatalog
		{
			get { return methodCatalog; }
		}		

		public Dictionary<string, MyFieldNode> FieldCatalog
		{
			get { return fieldCatalog; }
		}
	} 
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
United States United States
I have been a professional developer since 1996. My experience comes from many different industries; Data Mining Software, Consulting, E-Commerce, Wholesale Operations, Clinical Software, Insurance, Energy.

I started programming in the military, trying to find better ways to analyze database data, eventually automating my entire job. Later, in college, I automated my way out of another job. This gave me the great idea to switch majors to the only thing that seemed natural…Programming!

Comments and Discussions