5 // Jb Evain (jbevain@novell.com)
7 // (C) 2009 Novell, Inc.
9 // Permission is hereby granted, free of charge, to any person obtaining
10 // a copy of this software and associated documentation files (the
11 // "Software"), to deal in the Software without restriction, including
12 // without limitation the rights to use, copy, modify, merge, publish,
13 // distribute, sublicense, and/or sell copies of the Software, and to
14 // permit persons to whom the Software is furnished to do so, subject to
15 // the following conditions:
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
20 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
21 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
22 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
23 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
24 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
25 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
26 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
30 using System.Collections;
31 using System.Collections.Generic;
35 namespace Mono.Linker.Steps {
37 public class TypeMapStep : BaseStep {
39 protected override void ProcessAssembly (AssemblyDefinition assembly)
41 foreach (TypeDefinition type in assembly.MainModule.Types)
45 protected virtual void MapType (TypeDefinition type)
47 MapVirtualMethods (type);
48 MapInterfaceMethodsInTypeHierarchy (type);
50 if (!type.HasNestedTypes)
53 foreach (var nested in type.NestedTypes)
57 void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type)
59 if (!type.HasInterfaces)
62 foreach (TypeReference @interface in type.Interfaces) {
63 var iface = @interface.Resolve ();
64 if (iface == null || !iface.HasMethods)
67 foreach (MethodDefinition method in iface.Methods) {
68 if (TryMatchMethod (type, method) != null)
71 var @base = GetBaseMethodInTypeHierarchy (type, method);
75 Annotations.AddPreservedMethod (type, @base);
80 void MapVirtualMethods (TypeDefinition type)
85 foreach (MethodDefinition method in type.Methods) {
86 if (!method.IsVirtual)
89 MapVirtualMethod (method);
91 if (method.HasOverrides)
92 MapOverrides (method);
96 void MapVirtualMethod (MethodDefinition method)
98 MapVirtualBaseMethod (method);
99 MapVirtualInterfaceMethod (method);
102 void MapVirtualBaseMethod (MethodDefinition method)
104 MethodDefinition @base = GetBaseMethodInTypeHierarchy (method);
108 AnnotateMethods (@base, method);
111 void MapVirtualInterfaceMethod (MethodDefinition method)
113 foreach (MethodDefinition @base in GetBaseMethodsInInterfaceHierarchy (method))
114 AnnotateMethods (@base, method);
117 void MapOverrides (MethodDefinition method)
119 foreach (MethodReference override_ref in method.Overrides) {
120 MethodDefinition @override = override_ref.Resolve ();
121 if (@override == null)
124 AnnotateMethods (@override, method);
128 void AnnotateMethods (MethodDefinition @base, MethodDefinition @override)
130 Annotations.AddBaseMethod (@override, @base);
131 Annotations.AddOverride (@base, @override);
134 static MethodDefinition GetBaseMethodInTypeHierarchy (MethodDefinition method)
136 return GetBaseMethodInTypeHierarchy (method.DeclaringType, method);
139 static MethodDefinition GetBaseMethodInTypeHierarchy (TypeDefinition type, MethodDefinition method)
141 TypeDefinition @base = GetBaseType (type);
142 while (@base != null) {
143 MethodDefinition base_method = TryMatchMethod (@base, method);
144 if (base_method != null)
147 @base = GetBaseType (@base);
153 static IEnumerable<MethodDefinition> GetBaseMethodsInInterfaceHierarchy (MethodDefinition method)
155 return GetBaseMethodsInInterfaceHierarchy (method.DeclaringType, method);
158 static IEnumerable<MethodDefinition> GetBaseMethodsInInterfaceHierarchy (TypeDefinition type, MethodDefinition method)
160 if (!type.HasInterfaces)
163 foreach (TypeReference interface_ref in type.Interfaces) {
164 TypeDefinition @interface = interface_ref.Resolve ();
165 if (@interface == null)
168 MethodDefinition base_method = TryMatchMethod (@interface, method);
169 if (base_method != null)
170 yield return base_method;
172 foreach (MethodDefinition @base in GetBaseMethodsInInterfaceHierarchy (@interface, method))
177 static MethodDefinition TryMatchMethod (TypeDefinition type, MethodDefinition method)
179 if (!type.HasMethods)
182 foreach (MethodDefinition candidate in type.Methods)
183 if (MethodMatch (candidate, method))
189 static bool MethodMatch (MethodDefinition candidate, MethodDefinition method)
191 if (!candidate.IsVirtual)
194 if (candidate.HasParameters != method.HasParameters)
197 if (candidate.Name != method.Name)
200 if (candidate.HasGenericParameters != method.HasGenericParameters)
203 if (!TypeMatch (candidate.ReturnType, method.ReturnType))
206 if (!candidate.HasParameters)
209 var cp = candidate.Parameters;
210 var mp = method.Parameters;
211 if (cp.Count != mp.Count)
214 for (int i = 0; i < cp.Count; i++) {
215 if (!TypeMatch (cp [i].ParameterType, mp [i].ParameterType))
222 static bool TypeMatch (IModifierType a, IModifierType b)
224 if (!TypeMatch (a.ModifierType, b.ModifierType))
227 return TypeMatch (a.ElementType, b.ElementType);
230 static bool TypeMatch (TypeSpecification a, TypeSpecification b)
232 var gita = a as GenericInstanceType;
234 return TypeMatch (gita, (GenericInstanceType) b);
236 var mta = a as IModifierType;
238 return TypeMatch (mta, (IModifierType) b);
240 return TypeMatch (a.ElementType, b.ElementType);
243 static bool TypeMatch (GenericInstanceType a, GenericInstanceType b)
245 if (!TypeMatch (a.ElementType, b.ElementType))
248 if (a.HasGenericArguments != b.HasGenericArguments)
251 if (!a.HasGenericArguments)
254 var gaa = a.GenericArguments;
255 var gab = b.GenericArguments;
256 if (gaa.Count != gab.Count)
259 for (int i = 0; i < gaa.Count; i++) {
260 if (!TypeMatch (gaa [i], gab [i]))
267 static bool TypeMatch (TypeReference a, TypeReference b)
269 if (a is GenericParameter)
272 if (a is TypeSpecification || b is TypeSpecification) {
273 if (a.GetType () != b.GetType ())
276 return TypeMatch ((TypeSpecification) a, (TypeSpecification) b);
279 return a.FullName == b.FullName;
282 static TypeDefinition GetBaseType (TypeDefinition type)
284 if (type == null || type.BaseType == null)
287 return type.BaseType.Resolve ();