PageRenderTime 30ms CodeModel.GetById 15ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/ILSpy/TreeNodes/Analyzer/Helpers.cs

http://github.com/icsharpcode/ILSpy
C# | 144 lines | 103 code | 17 blank | 24 comment | 42 complexity | 4d60004a9c4ef0b3bc05d1d7b13a3fa2 MD5 | raw file
  1// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
  2// 
  3// Permission is hereby granted, free of charge, to any person obtaining a copy of this
  4// software and associated documentation files (the "Software"), to deal in the Software
  5// without restriction, including without limitation the rights to use, copy, modify, merge,
  6// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
  7// to whom the Software is furnished to do so, subject to the following conditions:
  8// 
  9// The above copyright notice and this permission notice shall be included in all copies or
 10// substantial portions of the Software.
 11// 
 12// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
 13// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
 14// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
 15// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
 16// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
 17// DEALINGS IN THE SOFTWARE.
 18
 19using System;
 20using System.Linq;
 21using ICSharpCode.Decompiler;
 22using Mono.Cecil;
 23using Mono.Cecil.Cil;
 24
 25namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
 26{
 27	internal static class Helpers
 28	{
 29		public static bool IsReferencedBy(TypeDefinition type, TypeReference typeRef)
 30		{
 31			// TODO: move it to a better place after adding support for more cases.
 32			if (type == null)
 33				throw new ArgumentNullException("type");
 34			if (typeRef == null)
 35				throw new ArgumentNullException("typeRef");
 36
 37			if (type == typeRef)
 38				return true;
 39			if (type.Name != typeRef.Name)
 40				return false;
 41			if (type.Namespace != typeRef.Namespace)
 42				return false;
 43
 44			if (type.DeclaringType != null || typeRef.DeclaringType != null) {
 45				if (type.DeclaringType == null || typeRef.DeclaringType == null)
 46					return false;
 47				if (!IsReferencedBy(type.DeclaringType, typeRef.DeclaringType))
 48					return false;
 49			}
 50
 51			return true;
 52		}
 53
 54		public static MemberReference GetOriginalCodeLocation(MemberReference member)
 55		{
 56			if (member is MethodDefinition)
 57				return GetOriginalCodeLocation((MethodDefinition)member);
 58			return member;
 59		}
 60
 61		public static MethodDefinition GetOriginalCodeLocation(MethodDefinition method)
 62		{
 63			if (method.IsCompilerGenerated()) {
 64				return FindMethodUsageInType(method.DeclaringType, method) ?? method;
 65			}
 66
 67			var typeUsage = GetOriginalCodeLocation(method.DeclaringType);
 68
 69			return typeUsage ?? method;
 70		}
 71		
 72		/// <summary>
 73		/// Given a compiler-generated type, returns the method where that type is used.
 74		/// Used to detect the 'parent method' for a lambda/iterator/async state machine.
 75		/// </summary>
 76		public static MethodDefinition GetOriginalCodeLocation(TypeDefinition type)
 77		{
 78			if (type != null && type.DeclaringType != null && type.IsCompilerGenerated()) {
 79				if (type.IsValueType) {
 80					// Value types might not have any constructor; but they must be stored in a local var
 81					// because 'initobj' (or 'call .ctor') expects a managed ref.
 82					return FindVariableOfTypeUsageInType(type.DeclaringType, type);
 83				} else {
 84					MethodDefinition constructor = GetTypeConstructor(type);
 85					if (constructor == null)
 86						return null;
 87					return FindMethodUsageInType(type.DeclaringType, constructor);
 88				}
 89			}
 90			return null;
 91		}
 92
 93		private static MethodDefinition GetTypeConstructor(TypeDefinition type)
 94		{
 95			return type.Methods.FirstOrDefault(method => method.Name == ".ctor");
 96		}
 97
 98		private static MethodDefinition FindMethodUsageInType(TypeDefinition type, MethodDefinition analyzedMethod)
 99		{
100			string name = analyzedMethod.Name;
101			foreach (MethodDefinition method in type.Methods) {
102				bool found = false;
103				if (!method.HasBody)
104					continue;
105				foreach (Instruction instr in method.Body.Instructions) {
106					MethodReference mr = instr.Operand as MethodReference;
107					if (mr != null && mr.Name == name &&
108						IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) &&
109						mr.Resolve() == analyzedMethod) {
110						found = true;
111						break;
112					}
113				}
114
115				method.Body = null;
116
117				if (found)
118					return method;
119			}
120			return null;
121		}
122		
123		private static MethodDefinition FindVariableOfTypeUsageInType(TypeDefinition type, TypeDefinition variableType)
124		{
125			foreach (MethodDefinition method in type.Methods) {
126				bool found = false;
127				if (!method.HasBody)
128					continue;
129				foreach (var v in method.Body.Variables) {
130					if (v.VariableType.ResolveWithinSameModule() == variableType) {
131						found = true;
132						break;
133					}
134				}
135
136				method.Body = null;
137
138				if (found)
139					return method;
140			}
141			return null;
142		}
143	}
144}