Source

CodeShape / src / CodeShapes / ClassAnalyzer.cs

Full commit
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
using System.Reflection.Emit;
using CodeShapes.Disassembler;
using CodeShapes.Shapes;
using QuickGraph;

namespace CodeShapes
{
	public class AnalizedClass
	{
		private IEnumerable<CodeShape> _classShapes;

		public AnalizedClass(IEnumerable<CodeShape> classShapes)
		{
			_classShapes = classShapes;
		}

		public bool RenderToImage(string path)
		{
			throw new NotImplementedException();
		}
		
		public bool RenderToTextFile(string path)
		{
			throw new NotImplementedException();
		}
	}

	public class ClassAnalyzer
	{
		public IEnumerable<CodeShape> Analyze<T>()
		{
			var shapes = FindMethods(typeof(T))
				.Concat(FindFields(typeof(T))).ToArray();

			var methods = shapes.Where(s => s is MethodCodeShape).Cast<MethodCodeShape>();
			foreach (var methodShape in methods)
			{
				foreach (var buildAdjacencyList in BuildAdjacencyLists(methodShape.MethodBase.GetInstructions(), shapes))
				{
					var method = shapes.First(x => x.Name == methodShape.Name);
					method.AdjacencyList.Add(buildAdjacencyList.Key, buildAdjacencyList.Value);
				}
				
			}
			return shapes;
		}

		public AdjacencyGraph<string, SEdge<string>> TransformToGraph(IEnumerable<CodeShape> shapes)
		{
			throw new NotImplementedException();	
		}
	
		private IDictionary<int, CodeShape> BuildAdjacencyLists(IList<Instruction> instructions, IEnumerable<CodeShape> shapes)
		{
			var result = new Dictionary<int, CodeShape>();
			foreach (var instruction in instructions)
			{
				if(instruction.OpCode.OperandType == OperandType.InlineMethod)
				{
					var methods = shapes
						.Where(s => s is MethodCodeShape)
						.Cast<MethodCodeShape>();
					var dependency = methods.FirstOrDefault(m => m.MethodBase == (MethodBase)instruction.Operand);

					int dependencyKey = ((MethodBase)instruction.Operand).MetadataToken;
					if(dependency != null && !result.ContainsKey(dependencyKey))
					{
						result.Add(dependencyKey, dependency);
					}
				}

				//TODO: properties and protected and internal methods
				
				if(instruction.OpCode.OperandType == OperandType.InlineField)
				{
					var dependency = shapes
						.Where(s => s is FieldCodeShape).Cast<FieldCodeShape>()
						.FirstOrDefault(f => f.Name == ((FieldInfo)instruction.Operand).Name);

					int dependencyKey = ((FieldInfo)instruction.Operand).MetadataToken;
					if (dependency != null && !result.ContainsKey(dependencyKey))
						result.Add(dependencyKey, dependency);
				}
			}
			return result;
		}

		public IEnumerable<FieldCodeShape> FindFields(Type type)
		{
			var fieldInfos = type.GetFields(BindingFlags.Public| BindingFlags.NonPublic| BindingFlags.Static| BindingFlags.Instance);
			IList<FieldCodeShape> fieldShapes = new List<FieldCodeShape>();
			foreach (var fieldInfo in fieldInfos)
			{
				var visibility = fieldInfo.IsPublic ? Visibility.Public : Visibility.NonPublic;
				fieldShapes.Add(new FieldCodeShape(fieldInfo.Name, visibility));
			}
			return fieldShapes.ToArray();
		}
		// todo: properties
		private IEnumerable<CodeShape> FindMethods(Type type)
		{
			var privateProtectedInternalMethods = type.GetMethods( BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance);
			var publicMethods = type.GetMethods();

			var result = privateProtectedInternalMethods.Select(methodInfo => new MethodCodeShape(methodInfo, methodInfo.Name, Visibility.NonPublic)).ToList();
			result.AddRange(publicMethods.Select(methodInfo => new MethodCodeShape(methodInfo, methodInfo.Name, Visibility.Public)));
			return result;
		}
	}
}