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 (var @interface in type.Interfaces) {
63 var iface = @interface.InterfaceType.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 (var interface_ref in type.Interfaces) {
164 TypeDefinition @interface = interface_ref.InterfaceType.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 Dictionary<string,string> gp = null;
183 foreach (MethodDefinition candidate in type.Methods) {
184 if (MethodMatch (candidate, method, ref gp))
193 static bool MethodMatch (MethodDefinition candidate, MethodDefinition method, ref Dictionary<string,string> genericParameters)
195 if (!candidate.IsVirtual)
198 if (candidate.HasParameters != method.HasParameters)
201 if (candidate.Name != method.Name)
204 if (candidate.HasGenericParameters != method.HasGenericParameters)
207 // we need to track what the generic parameter represent - as we cannot allow it to
208 // differ between the return type or any parameter
209 if (!TypeMatch (candidate.ReturnType, method.ReturnType, ref genericParameters))
212 if (!candidate.HasParameters)
215 var cp = candidate.Parameters;
216 var mp = method.Parameters;
217 if (cp.Count != mp.Count)
220 for (int i = 0; i < cp.Count; i++) {
221 if (!TypeMatch (cp [i].ParameterType, mp [i].ParameterType, ref genericParameters))
228 static bool TypeMatch (IModifierType a, IModifierType b, ref Dictionary<string,string> gp)
230 if (!TypeMatch (a.ModifierType, b.ModifierType, ref gp))
233 return TypeMatch (a.ElementType, b.ElementType, ref gp);
236 static bool TypeMatch (TypeSpecification a, TypeSpecification b, ref Dictionary<string,string> gp)
238 var gita = a as GenericInstanceType;
240 return TypeMatch (gita, (GenericInstanceType) b, ref gp);
242 var mta = a as IModifierType;
244 return TypeMatch (mta, (IModifierType) b, ref gp);
246 return TypeMatch (a.ElementType, b.ElementType, ref gp);
249 static bool TypeMatch (GenericInstanceType a, GenericInstanceType b, ref Dictionary<string,string> gp)
251 if (!TypeMatch (a.ElementType, b.ElementType, ref gp))
254 if (a.HasGenericArguments != b.HasGenericArguments)
257 if (!a.HasGenericArguments)
260 var gaa = a.GenericArguments;
261 var gab = b.GenericArguments;
262 if (gaa.Count != gab.Count)
265 for (int i = 0; i < gaa.Count; i++) {
266 if (!TypeMatch (gaa [i], gab [i], ref gp))
273 static bool TypeMatch (TypeReference a, TypeReference b, ref Dictionary<string,string> gp)
275 var gpa = a as GenericParameter;
278 gp = new Dictionary<string, string> ();
280 if (!gp.TryGetValue (gpa.FullName, out match)) {
281 // first use, we assume it will always be used this way
282 gp.Add (gpa.FullName, b.ToString ());
285 // re-use, it should match the previous usage
286 return match == b.ToString ();
289 if (a is TypeSpecification || b is TypeSpecification) {
290 if (a.GetType () != b.GetType ())
293 return TypeMatch ((TypeSpecification) a, (TypeSpecification) b, ref gp);
296 return a.FullName == b.FullName;
299 static TypeDefinition GetBaseType (TypeDefinition type)
301 if (type == null || type.BaseType == null)
304 return type.BaseType.Resolve ();