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;
34 namespace Mono.Linker.Steps {
36 public class TypeMapStep : BaseStep {
38 protected override void ProcessAssembly (AssemblyDefinition assembly)
40 foreach (TypeDefinition type in assembly.MainModule.Types)
44 void MapType (TypeDefinition type)
46 MapVirtualMethods (type);
47 MapInterfaceMethodsInTypeHierarchy (type);
49 if (!type.HasNestedTypes)
52 foreach (var nested in type.NestedTypes)
56 void MapInterfaceMethodsInTypeHierarchy (TypeDefinition type)
58 if (!type.HasInterfaces)
61 foreach (TypeReference @interface in type.Interfaces) {
62 var iface = @interface.Resolve ();
63 if (iface == null || !iface.HasMethods)
66 foreach (MethodDefinition method in iface.Methods) {
67 if (TryMatchMethod (type, method) != null)
70 var @base = GetBaseMethodInTypeHierarchy (type, method);
74 Annotations.AddPreservedMethod (type, @base);
79 void MapVirtualMethods (TypeDefinition type)
84 foreach (MethodDefinition method in type.Methods) {
85 if (!method.IsVirtual)
88 MapVirtualMethod (method);
90 if (method.HasOverrides)
91 MapOverrides (method);
95 void MapVirtualMethod (MethodDefinition method)
97 MapVirtualBaseMethod (method);
98 MapVirtualInterfaceMethod (method);
101 void MapVirtualBaseMethod (MethodDefinition method)
103 MethodDefinition @base = GetBaseMethodInTypeHierarchy (method);
107 AnnotateMethods (@base, method);
110 void MapVirtualInterfaceMethod (MethodDefinition method)
112 MethodDefinition @base = GetBaseMethodInInterfaceHierarchy (method);
116 AnnotateMethods (@base, method);
119 void MapOverrides (MethodDefinition method)
121 foreach (MethodReference override_ref in method.Overrides) {
122 MethodDefinition @override = override_ref.Resolve ();
123 if (@override == null)
126 AnnotateMethods (@override, method);
130 void AnnotateMethods (MethodDefinition @base, MethodDefinition @override)
132 Annotations.AddBaseMethod (@override, @base);
133 Annotations.AddOverride (@base, @override);
136 static MethodDefinition GetBaseMethodInTypeHierarchy (MethodDefinition method)
138 return GetBaseMethodInTypeHierarchy (method.DeclaringType, method);
141 static MethodDefinition GetBaseMethodInTypeHierarchy (TypeDefinition type, MethodDefinition method)
143 TypeDefinition @base = GetBaseType (type);
144 while (@base != null) {
145 MethodDefinition base_method = TryMatchMethod (@base, method);
146 if (base_method != null)
149 @base = GetBaseType (@base);
155 static MethodDefinition GetBaseMethodInInterfaceHierarchy (MethodDefinition method)
157 return GetBaseMethodInInterfaceHierarchy (method.DeclaringType, method);
160 static MethodDefinition GetBaseMethodInInterfaceHierarchy (TypeDefinition type, MethodDefinition method)
162 if (!type.HasInterfaces)
165 foreach (TypeReference interface_ref in type.Interfaces) {
166 TypeDefinition @interface = interface_ref.Resolve ();
167 if (@interface == null)
170 MethodDefinition base_method = TryMatchMethod (@interface, method);
171 if (base_method != null)
174 base_method = GetBaseMethodInInterfaceHierarchy (@interface, method);
175 if (base_method != null)
182 static MethodDefinition TryMatchMethod (TypeDefinition type, MethodDefinition method)
184 if (!type.HasMethods)
187 foreach (MethodDefinition candidate in type.Methods)
188 if (MethodMatch (candidate, method))
194 static bool MethodMatch (MethodDefinition candidate, MethodDefinition method)
196 if (!candidate.IsVirtual)
199 if (candidate.Name != method.Name)
202 if (!TypeMatch (candidate.ReturnType, method.ReturnType))
205 if (candidate.Parameters.Count != method.Parameters.Count)
208 for (int i = 0; i < candidate.Parameters.Count; i++)
209 if (!TypeMatch (candidate.Parameters [i].ParameterType, method.Parameters [i].ParameterType))
215 static bool TypeMatch (IModifierType a, IModifierType b)
217 if (!TypeMatch (a.ModifierType, b.ModifierType))
220 return TypeMatch (a.ElementType, b.ElementType);
223 static bool TypeMatch (TypeSpecification a, TypeSpecification b)
225 if (a is GenericInstanceType)
226 return TypeMatch ((GenericInstanceType) a, (GenericInstanceType) b);
228 if (a is IModifierType)
229 return TypeMatch ((IModifierType) a, (IModifierType) b);
231 return TypeMatch (a.ElementType, b.ElementType);
234 static bool TypeMatch (GenericInstanceType a, GenericInstanceType b)
236 if (!TypeMatch (a.ElementType, b.ElementType))
239 if (a.GenericArguments.Count != b.GenericArguments.Count)
242 if (a.GenericArguments.Count == 0)
245 for (int i = 0; i < a.GenericArguments.Count; i++)
246 if (!TypeMatch (a.GenericArguments [i], b.GenericArguments [i]))
252 static bool TypeMatch (TypeReference a, TypeReference b)
254 if (a is GenericParameter)
257 if (a is TypeSpecification || b is TypeSpecification) {
258 if (a.GetType () != b.GetType ())
261 return TypeMatch ((TypeSpecification) a, (TypeSpecification) b);
264 return a.FullName == b.FullName;
267 static TypeDefinition GetBaseType (TypeDefinition type)
269 if (type == null || type.BaseType == null)
272 return type.BaseType.Resolve ();