Merge back MonoTouch changes inside the linker/tuner code
[mono.git] / mcs / tools / linker / Mono.Linker.Steps / TypeMapStep.cs
1 //
2 // TypeMapStep.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@novell.com)
6 //
7 // (C) 2009 Novell, Inc.
8 //
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:
16 //
17 // The above copyright notice and this permission notice shall be
18 // included in all copies or substantial portions of the Software.
19 //
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.
27 //
28
29 using System;
30 using System.Collections;
31 using System.Collections.Generic;
32
33 using Mono.Cecil;
34
35 namespace Mono.Linker.Steps {
36
37         public class TypeMapStep : BaseStep {
38
39                 protected override void ProcessAssembly (AssemblyDefinition assembly)
40                 {
41                         foreach (TypeDefinition type in assembly.MainModule.Types)
42                                 MapType (type);
43                 }
44
45                 protected virtual void MapType (TypeDefinition type)
46                 {
47                         MapVirtualMethods (type);
48                         MapInterfaceMethodsInTypeHierarchy (type);
49
50                         if (!type.HasNestedTypes)
51                                 return;
52
53                         foreach (var nested in type.NestedTypes)
54                                 MapType (nested);
55                 }
56
57                 void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type)
58                 {
59                         if (!type.HasInterfaces)
60                                 return;
61
62                         foreach (TypeReference @interface in type.Interfaces) {
63                                 var iface = @interface.Resolve ();
64                                 if (iface == null || !iface.HasMethods)
65                                         continue;
66
67                                 foreach (MethodDefinition method in iface.Methods) {
68                                         if (TryMatchMethod (type, method) != null)
69                                                 continue;
70
71                                         var @base = GetBaseMethodInTypeHierarchy (type, method);
72                                         if (@base == null)
73                                                 continue;
74
75                                         Annotations.AddPreservedMethod (type, @base);
76                                 }
77                         }
78                 }
79
80                 void MapVirtualMethods (TypeDefinition type)
81                 {
82                         if (!type.HasMethods)
83                                 return;
84
85                         foreach (MethodDefinition method in type.Methods) {
86                                 if (!method.IsVirtual)
87                                         continue;
88
89                                 MapVirtualMethod (method);
90
91                                 if (method.HasOverrides)
92                                         MapOverrides (method);
93                         }
94                 }
95
96                 void MapVirtualMethod (MethodDefinition method)
97                 {
98                         MapVirtualBaseMethod (method);
99                         MapVirtualInterfaceMethod (method);
100                 }
101
102                 void MapVirtualBaseMethod (MethodDefinition method)
103                 {
104                         MethodDefinition @base = GetBaseMethodInTypeHierarchy (method);
105                         if (@base == null)
106                                 return;
107
108                         AnnotateMethods (@base, method);
109                 }
110
111                 void MapVirtualInterfaceMethod (MethodDefinition method)
112                 {
113                         foreach (MethodDefinition @base in GetBaseMethodsInInterfaceHierarchy (method))
114                                 AnnotateMethods (@base, method);
115                 }
116
117                 void MapOverrides (MethodDefinition method)
118                 {
119                         foreach (MethodReference override_ref in method.Overrides) {
120                                 MethodDefinition @override = override_ref.Resolve ();
121                                 if (@override == null)
122                                         continue;
123
124                                 AnnotateMethods (@override, method);
125                         }
126                 }
127
128                 void AnnotateMethods (MethodDefinition @base, MethodDefinition @override)
129                 {
130                         Annotations.AddBaseMethod (@override, @base);
131                         Annotations.AddOverride (@base, @override);
132                 }
133
134                 static MethodDefinition GetBaseMethodInTypeHierarchy (MethodDefinition method)
135                 {
136                         return GetBaseMethodInTypeHierarchy (method.DeclaringType, method);
137                 }
138
139                 static MethodDefinition GetBaseMethodInTypeHierarchy (TypeDefinition type, MethodDefinition method)
140                 {
141                         TypeDefinition @base = GetBaseType (type);
142                         while (@base != null) {
143                                 MethodDefinition base_method = TryMatchMethod (@base, method);
144                                 if (base_method != null)
145                                         return base_method;
146
147                                 @base = GetBaseType (@base);
148                         }
149
150                         return null;
151                 }
152
153                 static IEnumerable<MethodDefinition> GetBaseMethodsInInterfaceHierarchy (MethodDefinition method)
154                 {
155                         return GetBaseMethodsInInterfaceHierarchy (method.DeclaringType, method);
156                 }
157
158                 static IEnumerable<MethodDefinition> GetBaseMethodsInInterfaceHierarchy (TypeDefinition type, MethodDefinition method)
159                 {
160                         if (!type.HasInterfaces)
161                                 yield break;
162
163                         foreach (TypeReference interface_ref in type.Interfaces) {
164                                 TypeDefinition @interface = interface_ref.Resolve ();
165                                 if (@interface == null)
166                                         continue;
167
168                                 MethodDefinition base_method = TryMatchMethod (@interface, method);
169                                 if (base_method != null)
170                                         yield return base_method;
171
172                                 foreach (MethodDefinition @base in GetBaseMethodsInInterfaceHierarchy (@interface, method))
173                                         yield return @base;
174                         }
175                 }
176
177                 static MethodDefinition TryMatchMethod (TypeDefinition type, MethodDefinition method)
178                 {
179                         if (!type.HasMethods)
180                                 return null;
181
182                         foreach (MethodDefinition candidate in type.Methods)
183                                 if (MethodMatch (candidate, method))
184                                         return candidate;
185
186                         return null;
187                 }
188
189                 static bool MethodMatch (MethodDefinition candidate, MethodDefinition method)
190                 {
191                         if (!candidate.IsVirtual)
192                                 return false;
193
194                         if (candidate.Name != method.Name)
195                                 return false;
196
197                         if (!TypeMatch (candidate.ReturnType, method.ReturnType))
198                                 return false;
199
200                         if (candidate.Parameters.Count != method.Parameters.Count)
201                                 return false;
202
203                         for (int i = 0; i < candidate.Parameters.Count; i++)
204                                 if (!TypeMatch (candidate.Parameters [i].ParameterType, method.Parameters [i].ParameterType))
205                                         return false;
206
207                         return true;
208                 }
209
210                 static bool TypeMatch (IModifierType a, IModifierType b)
211                 {
212                         if (!TypeMatch (a.ModifierType, b.ModifierType))
213                                 return false;
214
215                         return TypeMatch (a.ElementType, b.ElementType);
216                 }
217
218                 static bool TypeMatch (TypeSpecification a, TypeSpecification b)
219                 {
220                         if (a is GenericInstanceType)
221                                 return TypeMatch ((GenericInstanceType) a, (GenericInstanceType) b);
222
223                         if (a is IModifierType)
224                                 return TypeMatch ((IModifierType) a, (IModifierType) b);
225
226                         return TypeMatch (a.ElementType, b.ElementType);
227                 }
228
229                 static bool TypeMatch (GenericInstanceType a, GenericInstanceType b)
230                 {
231                         if (!TypeMatch (a.ElementType, b.ElementType))
232                                 return false;
233
234                         if (a.GenericArguments.Count != b.GenericArguments.Count)
235                                 return false;
236
237                         if (a.GenericArguments.Count == 0)
238                                 return true;
239
240                         for (int i = 0; i < a.GenericArguments.Count; i++)
241                                 if (!TypeMatch (a.GenericArguments [i], b.GenericArguments [i]))
242                                         return false;
243
244                         return true;
245                 }
246
247                 static bool TypeMatch (TypeReference a, TypeReference b)
248                 {
249                         if (a is GenericParameter)
250                                 return true;
251
252                         if (a is TypeSpecification || b is TypeSpecification) {
253                                 if (a.GetType () != b.GetType ())
254                                         return false;
255
256                                 return TypeMatch ((TypeSpecification) a, (TypeSpecification) b);
257                         }
258
259                         return a.FullName == b.FullName;
260                 }
261
262                 static TypeDefinition GetBaseType (TypeDefinition type)
263                 {
264                         if (type == null || type.BaseType == null)
265                                 return null;
266
267                         return type.BaseType.Resolve ();
268                 }
269         }
270 }