afb814239a0a0ba7a1e7e7d1925d8300ef51216d
[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.HasParameters != method.HasParameters)
195                                 return false;
196
197                         if (candidate.Name != method.Name)
198                                 return false;
199
200                         if (candidate.HasGenericParameters != method.HasGenericParameters)
201                                 return false;
202
203                         if (!TypeMatch (candidate.ReturnType, method.ReturnType))
204                                 return false;
205
206                         if (!candidate.HasParameters)
207                                 return true;
208
209                         var cp = candidate.Parameters;
210                         var mp = method.Parameters;
211                         if (cp.Count != mp.Count)
212                                 return false;
213
214                         for (int i = 0; i < cp.Count; i++) {
215                                 if (!TypeMatch (cp [i].ParameterType, mp [i].ParameterType))
216                                         return false;
217                         }
218
219                         return true;
220                 }
221
222                 static bool TypeMatch (IModifierType a, IModifierType b)
223                 {
224                         if (!TypeMatch (a.ModifierType, b.ModifierType))
225                                 return false;
226
227                         return TypeMatch (a.ElementType, b.ElementType);
228                 }
229
230                 static bool TypeMatch (TypeSpecification a, TypeSpecification b)
231                 {
232                         var gita = a as GenericInstanceType;
233                         if (gita != null)
234                                 return TypeMatch (gita, (GenericInstanceType) b);
235
236                         var mta = a as IModifierType;
237                         if (mta != null)
238                                 return TypeMatch (mta, (IModifierType) b);
239
240                         return TypeMatch (a.ElementType, b.ElementType);
241                 }
242
243                 static bool TypeMatch (GenericInstanceType a, GenericInstanceType b)
244                 {
245                         if (!TypeMatch (a.ElementType, b.ElementType))
246                                 return false;
247
248                         if (a.HasGenericArguments != b.HasGenericArguments)
249                                 return false;
250
251                         if (!a.HasGenericArguments)
252                                 return true;
253
254                         var gaa = a.GenericArguments;
255                         var gab = b.GenericArguments;
256                         if (gaa.Count != gab.Count)
257                                 return false;
258
259                         for (int i = 0; i < gaa.Count; i++) {
260                                 if (!TypeMatch (gaa [i], gab [i]))
261                                         return false;
262                         }
263
264                         return true;
265                 }
266
267                 static bool TypeMatch (TypeReference a, TypeReference b)
268                 {
269                         if (a is GenericParameter)
270                                 return true;
271
272                         if (a is TypeSpecification || b is TypeSpecification) {
273                                 if (a.GetType () != b.GetType ())
274                                         return false;
275
276                                 return TypeMatch ((TypeSpecification) a, (TypeSpecification) b);
277                         }
278
279                         return a.FullName == b.FullName;
280                 }
281
282                 static TypeDefinition GetBaseType (TypeDefinition type)
283                 {
284                         if (type == null || type.BaseType == null)
285                                 return null;
286
287                         return type.BaseType.Resolve ();
288                 }
289         }
290 }