update Mono.Cecil
[mono.git] / mcs / class / Mono.Cecil / Mono.Cecil / MetadataResolver.cs
1 //
2 // MetadataResolver.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@gmail.com)
6 //
7 // Copyright (c) 2008 - 2011 Jb Evain
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.Generic;
31
32 using Mono.Collections.Generic;
33
34 namespace Mono.Cecil {
35
36         public interface IAssemblyResolver {
37                 AssemblyDefinition Resolve (AssemblyNameReference name);
38                 AssemblyDefinition Resolve (AssemblyNameReference name, ReaderParameters parameters);
39
40                 AssemblyDefinition Resolve (string fullName);
41                 AssemblyDefinition Resolve (string fullName, ReaderParameters parameters);
42         }
43
44         public class ResolutionException : Exception {
45
46                 readonly MemberReference member;
47
48                 public MemberReference Member {
49                         get { return member; }
50                 }
51
52                 public ResolutionException (MemberReference member)
53                         : base ("Failed to resolve " + member.FullName)
54                 {
55                         this.member = member;
56                 }
57         }
58
59         static class MetadataResolver {
60
61                 public static TypeDefinition Resolve (IAssemblyResolver resolver, TypeReference type)
62                 {
63                         type = type.GetElementType ();
64
65                         var scope = type.Scope;
66                         switch (scope.MetadataScopeType) {
67                         case MetadataScopeType.AssemblyNameReference:
68                                 var assembly = resolver.Resolve ((AssemblyNameReference) scope);
69                                 if (assembly == null)
70                                         return null;
71
72                                 return GetType (resolver, assembly.MainModule, type);
73                         case MetadataScopeType.ModuleDefinition:
74                                 return GetType (resolver, (ModuleDefinition) scope, type);
75                         case MetadataScopeType.ModuleReference:
76                                 var modules = type.Module.Assembly.Modules;
77                                 var module_ref = (ModuleReference) scope;
78                                 for (int i = 0; i < modules.Count; i++) {
79                                         var netmodule = modules [i];
80                                         if (netmodule.Name == module_ref.Name)
81                                                 return GetType (resolver, netmodule, type);
82                                 }
83                                 break;
84                         }
85
86                         throw new NotSupportedException ();
87                 }
88
89                 static TypeDefinition GetType (IAssemblyResolver resolver, ModuleDefinition module, TypeReference reference)
90                 {
91                         var type = GetType (module, reference);
92                         if (type != null)
93                                 return type;
94
95                         if (!module.HasExportedTypes)
96                                 return null;
97
98                         var exported_types = module.ExportedTypes;
99
100                         for (int i = 0; i < exported_types.Count; i++) {
101                                 var exported_type = exported_types [i];
102                                 if (exported_type.Name != reference.Name)
103                                         continue;
104
105                                 if (exported_type.Namespace != reference.Namespace)
106                                         continue;
107
108                                 return exported_type.Resolve ();
109                         }
110
111                         return null;
112                 }
113
114                 static TypeDefinition GetType (ModuleDefinition module, TypeReference type)
115                 {
116                         if (!type.IsNested)
117                                 return module.GetType (type.Namespace, type.Name);
118
119                         var declaring_type = type.DeclaringType.Resolve ();
120                         if (declaring_type == null)
121                                 return null;
122
123                         return declaring_type.GetNestedType (type.Name);
124                 }
125
126                 public static FieldDefinition Resolve (IAssemblyResolver resolver, FieldReference field)
127                 {
128                         var type = Resolve (resolver, field.DeclaringType);
129                         if (type == null)
130                                 return null;
131
132                         if (!type.HasFields)
133                                 return null;
134
135                         return GetField (resolver, type, field);
136                 }
137
138                 static FieldDefinition GetField (IAssemblyResolver resolver, TypeDefinition type, FieldReference reference)
139                 {
140                         while (type != null) {
141                                 var field = GetField (type.Fields, reference);
142                                 if (field != null)
143                                         return field;
144
145                                 if (type.BaseType == null)
146                                         return null;
147
148                                 type = Resolve (resolver, type.BaseType);
149                         }
150
151                         return null;
152                 }
153
154                 static FieldDefinition GetField (IList<FieldDefinition> fields, FieldReference reference)
155                 {
156                         for (int i = 0; i < fields.Count; i++) {
157                                 var field = fields [i];
158
159                                 if (field.Name != reference.Name)
160                                         continue;
161
162                                 if (!AreSame (field.FieldType, reference.FieldType))
163                                         continue;
164
165                                 return field;
166                         }
167
168                         return null;
169                 }
170
171                 public static MethodDefinition Resolve (IAssemblyResolver resolver, MethodReference method)
172                 {
173                         var type = Resolve (resolver, method.DeclaringType);
174                         if (type == null)
175                                 return null;
176
177                         method = method.GetElementMethod ();
178
179                         if (!type.HasMethods)
180                                 return null;
181
182                         return GetMethod (resolver, type, method);
183                 }
184
185                 static MethodDefinition GetMethod (IAssemblyResolver resolver, TypeDefinition type, MethodReference reference)
186                 {
187                         while (type != null) {
188                                 var method = GetMethod (type.Methods, reference);
189                                 if (method != null)
190                                         return method;
191
192                                 if (type.BaseType == null)
193                                         return null;
194
195                                 type = Resolve (resolver, type.BaseType);
196                         }
197
198                         return null;
199                 }
200
201                 public static MethodDefinition GetMethod (IList<MethodDefinition> methods, MethodReference reference)
202                 {
203                         for (int i = 0; i < methods.Count; i++) {
204                                 var method = methods [i];
205
206                                 if (method.Name != reference.Name)
207                                         continue;
208
209                                 if (method.HasGenericParameters != reference.HasGenericParameters)
210                                         continue;
211
212                                 if (method.HasGenericParameters && method.GenericParameters.Count != reference.GenericParameters.Count)
213                                         continue;
214
215                                 if (!AreSame (method.ReturnType, reference.ReturnType))
216                                         continue;
217
218                                 if (method.HasParameters != reference.HasParameters)
219                                         continue;
220
221                                 if (!method.HasParameters && !reference.HasParameters)
222                                         return method;
223
224                                 if (!AreSame (method.Parameters, reference.Parameters))
225                                         continue;
226
227                                 return method;
228                         }
229
230                         return null;
231                 }
232
233                 static bool AreSame (Collection<ParameterDefinition> a, Collection<ParameterDefinition> b)
234                 {
235                         var count = a.Count;
236
237                         if (count != b.Count)
238                                 return false;
239
240                         if (count == 0)
241                                 return true;
242
243                         for (int i = 0; i < count; i++)
244                                 if (!AreSame (a [i].ParameterType, b [i].ParameterType))
245                                         return false;
246
247                         return true;
248                 }
249
250                 static bool AreSame (TypeSpecification a, TypeSpecification b)
251                 {
252                         if (!AreSame (a.ElementType, b.ElementType))
253                                 return false;
254
255                         if (a.IsGenericInstance)
256                                 return AreSame ((GenericInstanceType) a, (GenericInstanceType) b);
257
258                         if (a.IsRequiredModifier || a.IsOptionalModifier)
259                                 return AreSame ((IModifierType) a, (IModifierType) b);
260
261                         if (a.IsArray)
262                                 return AreSame ((ArrayType) a, (ArrayType) b);
263
264                         return true;
265                 }
266
267                 static bool AreSame (ArrayType a, ArrayType b)
268                 {
269                         if (a.Rank != b.Rank)
270                                 return false;
271
272                         // TODO: dimensions
273
274                         return true;
275                 }
276
277                 static bool AreSame (IModifierType a, IModifierType b)
278                 {
279                         return AreSame (a.ModifierType, b.ModifierType);
280                 }
281
282                 static bool AreSame (GenericInstanceType a, GenericInstanceType b)
283                 {
284                         if (a.GenericArguments.Count != b.GenericArguments.Count)
285                                 return false;
286
287                         for (int i = 0; i < a.GenericArguments.Count; i++)
288                                 if (!AreSame (a.GenericArguments [i], b.GenericArguments [i]))
289                                         return false;
290
291                         return true;
292                 }
293
294                 static bool AreSame (GenericParameter a, GenericParameter b)
295                 {
296                         return a.Position == b.Position;
297                 }
298
299                 static bool AreSame (TypeReference a, TypeReference b)
300                 {
301                         if (ReferenceEquals (a, b))
302                                 return true;
303
304                         if (a == null || b == null)
305                                 return false;
306
307                         if (a.etype != b.etype)
308                                 return false;
309
310                         if (a.IsGenericParameter)
311                                 return AreSame ((GenericParameter) a, (GenericParameter) b);
312
313                         if (a.IsTypeSpecification ())
314                                 return AreSame ((TypeSpecification) a, (TypeSpecification) b);
315
316                         if (a.Name != b.Name || a.Namespace != b.Namespace)
317                                 return false;
318
319                         //TODO: check scope
320
321                         return AreSame (a.DeclaringType, b.DeclaringType);
322                 }
323         }
324 }