Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / IKVM.Reflection / Reader / Method.cs
1 /*
2   Copyright (C) 2009-2012 Jeroen Frijters
3
4   This software is provided 'as-is', without any express or implied
5   warranty.  In no event will the authors be held liable for any damages
6   arising from the use of this software.
7
8   Permission is granted to anyone to use this software for any purpose,
9   including commercial applications, and to alter it and redistribute it
10   freely, subject to the following restrictions:
11
12   1. The origin of this software must not be misrepresented; you must not
13      claim that you wrote the original software. If you use this software
14      in a product, an acknowledgment in the product documentation would be
15      appreciated but is not required.
16   2. Altered source versions must be plainly marked as such, and must not be
17      misrepresented as being the original software.
18   3. This notice may not be removed or altered from any source distribution.
19
20   Jeroen Frijters
21   jeroen@frijters.net
22   
23 */
24 using System;
25 using System.Collections.Generic;
26 using System.Text;
27 using IKVM.Reflection.Metadata;
28
29 namespace IKVM.Reflection.Reader
30 {
31         sealed class MethodDefImpl : MethodInfo
32         {
33                 private readonly ModuleReader module;
34                 private readonly int index;
35                 private readonly TypeDefImpl declaringType;
36                 private MethodSignature lazyMethodSignature;
37                 private ParameterInfo returnParameter;
38                 private ParameterInfo[] parameters;
39                 private Type[] typeArgs;
40
41                 internal MethodDefImpl(ModuleReader module, TypeDefImpl declaringType, int index)
42                 {
43                         this.module = module;
44                         this.index = index;
45                         this.declaringType = declaringType;
46                 }
47
48                 public override MethodBody GetMethodBody()
49                 {
50                         return GetMethodBody(this);
51                 }
52
53                 internal MethodBody GetMethodBody(IGenericContext context)
54                 {
55                         if ((GetMethodImplementationFlags() & MethodImplAttributes.CodeTypeMask) != MethodImplAttributes.IL)
56                         {
57                                 // method is not IL
58                                 return null;
59                         }
60                         int rva = module.MethodDef.records[index].RVA;
61                         return rva == 0 ? null : new MethodBody(module, rva, context);
62                 }
63
64                 public override int __MethodRVA
65                 {
66                         get { return module.MethodDef.records[index].RVA; }
67                 }
68
69                 public override CallingConventions CallingConvention
70                 {
71                         get { return this.MethodSignature.CallingConvention; }
72                 }
73
74                 public override MethodAttributes Attributes
75                 {
76                         get { return (MethodAttributes)module.MethodDef.records[index].Flags; }
77                 }
78
79                 public override MethodImplAttributes GetMethodImplementationFlags()
80                 {
81                         return (MethodImplAttributes)module.MethodDef.records[index].ImplFlags;
82                 }
83
84                 public override ParameterInfo[] GetParameters()
85                 {
86                         PopulateParameters();
87                         return (ParameterInfo[])parameters.Clone();
88                 }
89
90                 private void PopulateParameters()
91                 {
92                         if (parameters == null)
93                         {
94                                 MethodSignature methodSignature = this.MethodSignature;
95                                 parameters = new ParameterInfo[methodSignature.GetParameterCount()];
96                                 int parameter = module.MethodDef.records[index].ParamList - 1;
97                                 int end = module.MethodDef.records.Length > index + 1 ? module.MethodDef.records[index + 1].ParamList - 1 : module.Param.records.Length;
98                                 for (; parameter < end; parameter++)
99                                 {
100                                         int seq = module.Param.records[parameter].Sequence - 1;
101                                         if (seq == -1)
102                                         {
103                                                 returnParameter = new ParameterInfoImpl(this, seq, parameter);
104                                         }
105                                         else
106                                         {
107                                                 parameters[seq] = new ParameterInfoImpl(this, seq, parameter);
108                                         }
109                                 }
110                                 for (int i = 0; i < parameters.Length; i++)
111                                 {
112                                         if (parameters[i] == null)
113                                         {
114                                                 parameters[i] = new ParameterInfoImpl(this, i, -1);
115                                         }
116                                 }
117                                 if (returnParameter == null)
118                                 {
119                                         returnParameter = new ParameterInfoImpl(this, -1, -1);
120                                 }
121                         }
122                 }
123
124                 internal override int ParameterCount
125                 {
126                         get { return this.MethodSignature.GetParameterCount(); }
127                 }
128
129                 public override ParameterInfo ReturnParameter
130                 {
131                         get
132                         {
133                                 PopulateParameters();
134                                 return returnParameter;
135                         }
136                 }
137
138                 public override Type ReturnType
139                 {
140                         get
141                         {
142                                 return this.ReturnParameter.ParameterType;
143                         }
144                 }
145
146                 public override Type DeclaringType
147                 {
148                         get { return declaringType.IsModulePseudoType ? null : declaringType; }
149                 }
150
151                 public override string Name
152                 {
153                         get { return module.GetString(module.MethodDef.records[index].Name); }
154                 }
155
156                 public override int MetadataToken
157                 {
158                         get { return (MethodDefTable.Index << 24) + index + 1; }
159                 }
160
161                 public override bool IsGenericMethodDefinition
162                 {
163                         get
164                         {
165                                 PopulateGenericArguments();
166                                 return typeArgs.Length > 0;
167                         }
168                 }
169
170                 public override bool IsGenericMethod
171                 {
172                         get { return IsGenericMethodDefinition; }
173                 }
174
175                 public override Type[] GetGenericArguments()
176                 {
177                         PopulateGenericArguments();
178                         return Util.Copy(typeArgs);
179                 }
180
181                 private void PopulateGenericArguments()
182                 {
183                         if (typeArgs == null)
184                         {
185                                 int token = this.MetadataToken;
186                                 int first = module.GenericParam.FindFirstByOwner(token);
187                                 if (first == -1)
188                                 {
189                                         typeArgs = Type.EmptyTypes;
190                                 }
191                                 else
192                                 {
193                                         List<Type> list = new List<Type>();
194                                         int len = module.GenericParam.records.Length;
195                                         for (int i = first; i < len && module.GenericParam.records[i].Owner == token; i++)
196                                         {
197                                                 list.Add(new GenericTypeParameter(module, i));
198                                         }
199                                         typeArgs = list.ToArray();
200                                 }
201                         }
202                 }
203
204                 internal override Type GetGenericMethodArgument(int index)
205                 {
206                         PopulateGenericArguments();
207                         return typeArgs[index];
208                 }
209
210                 internal override int GetGenericMethodArgumentCount()
211                 {
212                         PopulateGenericArguments();
213                         return typeArgs.Length;
214                 }
215
216                 public override MethodInfo GetGenericMethodDefinition()
217                 {
218                         if (this.IsGenericMethodDefinition)
219                         {
220                                 return this;
221                         }
222                         throw new InvalidOperationException();
223                 }
224
225                 public override MethodInfo MakeGenericMethod(params Type[] typeArguments)
226                 {
227                         return new GenericMethodInstance(declaringType, this, typeArguments);
228                 }
229
230                 public override Module Module
231                 {
232                         get { return module; }
233                 }
234
235                 internal override MethodSignature MethodSignature
236                 {
237                         get { return lazyMethodSignature ?? (lazyMethodSignature = MethodSignature.ReadSig(module, module.GetBlob(module.MethodDef.records[index].Signature), this)); }
238                 }
239
240                 internal override int ImportTo(Emit.ModuleBuilder module)
241                 {
242                         return module.ImportMethodOrField(declaringType, this.Name, this.MethodSignature);
243                 }
244
245                 public override MethodInfo[] __GetMethodImpls()
246                 {
247                         Type[] typeArgs = null;
248                         List<MethodInfo> list = null;
249                         foreach (int i in module.MethodImpl.Filter(declaringType.MetadataToken))
250                         {
251                                 if (module.MethodImpl.records[i].MethodBody == this.MetadataToken)
252                                 {
253                                         if (typeArgs == null)
254                                         {
255                                                 typeArgs = declaringType.GetGenericArguments();
256                                         }
257                                         if (list == null)
258                                         {
259                                                 list = new List<MethodInfo>();
260                                         }
261                                         list.Add((MethodInfo)module.ResolveMethod(module.MethodImpl.records[i].MethodDeclaration, typeArgs, null));
262                                 }
263                         }
264                         return Util.ToArray(list, Empty<MethodInfo>.Array);
265                 }
266
267                 internal override int GetCurrentToken()
268                 {
269                         return this.MetadataToken;
270                 }
271
272                 internal override bool IsBaked
273                 {
274                         get { return true; }
275                 }
276         }
277
278         sealed class ParameterInfoImpl : ParameterInfo
279         {
280                 private readonly MethodDefImpl method;
281                 private readonly int position;
282                 private readonly int index;
283
284                 internal ParameterInfoImpl(MethodDefImpl method, int position, int index)
285                 {
286                         this.method = method;
287                         this.position = position;
288                         this.index = index;
289                 }
290
291                 public override string Name
292                 {
293                         get { return index == -1 ? null : ((ModuleReader)this.Module).GetString(this.Module.Param.records[index].Name); }
294                 }
295
296                 public override Type ParameterType
297                 {
298                         get { return position == -1 ? method.MethodSignature.GetReturnType(method) : method.MethodSignature.GetParameterType(method, position); }
299                 }
300
301                 public override ParameterAttributes Attributes
302                 {
303                         get { return index == -1 ? ParameterAttributes.None : (ParameterAttributes)this.Module.Param.records[index].Flags; }
304                 }
305
306                 public override int Position
307                 {
308                         get { return position; }
309                 }
310
311                 public override object RawDefaultValue
312                 {
313                         get
314                         {
315                                 if ((this.Attributes & ParameterAttributes.HasDefault) != 0)
316                                 {
317                                         return this.Module.Constant.GetRawConstantValue(this.Module, this.MetadataToken);
318                                 }
319                                 Universe universe = this.Module.universe;
320                                 if (this.ParameterType == universe.System_Decimal)
321                                 {
322                                         Type attr = universe.System_Runtime_CompilerServices_DecimalConstantAttribute;
323                                         if (attr != null)
324                                         {
325                                                 foreach (CustomAttributeData cad in CustomAttributeData.__GetCustomAttributes(this, attr, false))
326                                                 {
327                                                         IList<CustomAttributeTypedArgument> args = cad.ConstructorArguments;
328                                                         if (args.Count == 5)
329                                                         {
330                                                                 if (args[0].ArgumentType == universe.System_Byte
331                                                                         && args[1].ArgumentType == universe.System_Byte
332                                                                         && args[2].ArgumentType == universe.System_Int32
333                                                                         && args[3].ArgumentType == universe.System_Int32
334                                                                         && args[4].ArgumentType == universe.System_Int32)
335                                                                 {
336                                                                         return new Decimal((int)args[4].Value, (int)args[3].Value, (int)args[2].Value, (byte)args[1].Value != 0, (byte)args[0].Value);
337                                                                 }
338                                                                 else if (args[0].ArgumentType == universe.System_Byte
339                                                                         && args[1].ArgumentType == universe.System_Byte
340                                                                         && args[2].ArgumentType == universe.System_UInt32
341                                                                         && args[3].ArgumentType == universe.System_UInt32
342                                                                         && args[4].ArgumentType == universe.System_UInt32)
343                                                                 {
344                                                                         return new Decimal(unchecked((int)(uint)args[4].Value), unchecked((int)(uint)args[3].Value), unchecked((int)(uint)args[2].Value), (byte)args[1].Value != 0, (byte)args[0].Value);
345                                                                 }
346                                                         }
347                                                 }
348                                         }
349                                 }
350                                 if ((this.Attributes & ParameterAttributes.Optional) != 0)
351                                 {
352                                         return Missing.Value;
353                                 }
354                                 return null;
355                         }
356                 }
357
358                 public override CustomModifiers __GetCustomModifiers()
359                 {
360                         return position == -1
361                                 ? method.MethodSignature.GetReturnTypeCustomModifiers(method)
362                                 : method.MethodSignature.GetParameterCustomModifiers(method, position);
363                 }
364
365                 public override bool __TryGetFieldMarshal(out FieldMarshal fieldMarshal)
366                 {
367                         return FieldMarshal.ReadFieldMarshal(this.Module, this.MetadataToken, out fieldMarshal);
368                 }
369
370                 public override MemberInfo Member
371                 {
372                         get
373                         {
374                                 // return the right ConstructorInfo wrapper
375                                 return method.Module.ResolveMethod(method.MetadataToken);
376                         }
377                 }
378
379                 public override int MetadataToken
380                 {
381                         get
382                         {
383                                 // for parameters that don't have a row in the Param table, we return 0x08000000 (because index is -1 in that case),
384                                 // just like .NET
385                                 return (ParamTable.Index << 24) + index + 1;
386                         }
387                 }
388
389                 internal override Module Module
390                 {
391                         get { return method.Module; }
392                 }
393         }
394 }