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