do not check order sequence if option /order was not used
[mono.git] / mcs / class / IKVM.Reflection / CustomAttributeData.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 System.IO;
28 using IKVM.Reflection.Reader;
29 using IKVM.Reflection.Emit;
30 using IKVM.Reflection.Metadata;
31
32 namespace IKVM.Reflection
33 {
34         public sealed class CustomAttributeData
35         {
36                 internal static readonly IList<CustomAttributeData> EmptyList = new List<CustomAttributeData>(0).AsReadOnly();
37
38                 /*
39                  * There are several states a CustomAttributeData object can be in:
40                  * 
41                  * 1) Unresolved Custom Attribute
42                  *    - customAttributeIndex >= 0
43                  *    - declSecurityIndex == -1
44                  *    - declSecurityBlob == null
45                  *    - lazyConstructor = null
46                  *    - lazyConstructorArguments = null
47                  *    - lazyNamedArguments = null
48                  * 
49                  * 2) Resolved Custom Attribute
50                  *    - customAttributeIndex >= 0
51                  *    - declSecurityIndex == -1
52                  *    - declSecurityBlob == null
53                  *    - lazyConstructor != null
54                  *    - lazyConstructorArguments != null
55                  *    - lazyNamedArguments != null
56                  *    
57                  * 3) Pre-resolved Custom Attribute
58                  *    - customAttributeIndex = -1
59                  *    - declSecurityIndex == -1
60                  *    - declSecurityBlob == null
61                  *    - lazyConstructor != null
62                  *    - lazyConstructorArguments != null
63                  *    - lazyNamedArguments != null
64                  *    
65                  * 4) Pseudo Custom Attribute, .NET 1.x declarative security or result of CustomAttributeBuilder.ToData()
66                  *    - customAttributeIndex = -1
67                  *    - declSecurityIndex == -1
68                  *    - declSecurityBlob == null
69                  *    - lazyConstructor != null
70                  *    - lazyConstructorArguments != null
71                  *    - lazyNamedArguments != null
72                  *    
73                  * 5) Unresolved declarative security
74                  *    - customAttributeIndex = -1
75                  *    - declSecurityIndex >= 0
76                  *    - declSecurityBlob != null
77                  *    - lazyConstructor != null
78                  *    - lazyConstructorArguments != null
79                  *    - lazyNamedArguments == null
80                  * 
81                  * 6) Resolved declarative security
82                  *    - customAttributeIndex = -1
83                  *    - declSecurityIndex >= 0
84                  *    - declSecurityBlob == null
85                  *    - lazyConstructor != null
86                  *    - lazyConstructorArguments != null
87                  *    - lazyNamedArguments != null
88                  * 
89                  */
90                 private readonly Module module;
91                 private readonly int customAttributeIndex;
92                 private readonly int declSecurityIndex;
93                 private readonly byte[] declSecurityBlob;
94                 private ConstructorInfo lazyConstructor;
95                 private IList<CustomAttributeTypedArgument> lazyConstructorArguments;
96                 private IList<CustomAttributeNamedArgument> lazyNamedArguments;
97
98                 // 1) Unresolved Custom Attribute
99                 internal CustomAttributeData(Module module, int index)
100                 {
101                         this.module = module;
102                         this.customAttributeIndex = index;
103                         this.declSecurityIndex = -1;
104                 }
105
106                 // 4) Pseudo Custom Attribute, .NET 1.x declarative security
107                 internal CustomAttributeData(Module module, ConstructorInfo constructor, object[] args, List<CustomAttributeNamedArgument> namedArguments)
108                         : this(module, constructor, WrapConstructorArgs(args, constructor.MethodSignature), namedArguments)
109                 {
110                 }
111
112                 private static List<CustomAttributeTypedArgument> WrapConstructorArgs(object[] args, MethodSignature sig)
113                 {
114                         List<CustomAttributeTypedArgument> list = new List<CustomAttributeTypedArgument>();
115                         for (int i = 0; i < args.Length; i++)
116                         {
117                                 list.Add(new CustomAttributeTypedArgument(sig.GetParameterType(i), args[i]));
118                         }
119                         return list;
120                 }
121
122                 // 4) Pseudo Custom Attribute, .NET 1.x declarative security or result of CustomAttributeBuilder.ToData()
123                 internal CustomAttributeData(Module module, ConstructorInfo constructor, List<CustomAttributeTypedArgument> constructorArgs, List<CustomAttributeNamedArgument> namedArguments)
124                 {
125                         this.module = module;
126                         this.customAttributeIndex = -1;
127                         this.declSecurityIndex = -1;
128                         this.lazyConstructor = constructor;
129                         lazyConstructorArguments = constructorArgs.AsReadOnly();
130                         if (namedArguments == null)
131                         {
132                                 this.lazyNamedArguments = Empty<CustomAttributeNamedArgument>.Array;
133                         }
134                         else
135                         {
136                                 this.lazyNamedArguments = namedArguments.AsReadOnly();
137                         }
138                 }
139
140                 // 3) Pre-resolved Custom Attribute
141                 internal CustomAttributeData(Assembly asm, ConstructorInfo constructor, ByteReader br)
142                 {
143                         this.module = asm.ManifestModule;
144                         this.customAttributeIndex = -1;
145                         this.declSecurityIndex = -1;
146                         this.lazyConstructor = constructor;
147                         if (br.Length == 0)
148                         {
149                                 // it's legal to have an empty blob
150                                 lazyConstructorArguments = Empty<CustomAttributeTypedArgument>.Array;
151                                 lazyNamedArguments = Empty<CustomAttributeNamedArgument>.Array;
152                         }
153                         else
154                         {
155                                 if (br.ReadUInt16() != 1)
156                                 {
157                                         throw new BadImageFormatException();
158                                 }
159                                 lazyConstructorArguments = ReadConstructorArguments(asm, br, constructor);
160                                 lazyNamedArguments = ReadNamedArguments(asm, br, br.ReadUInt16(), constructor.DeclaringType);
161                         }
162                 }
163
164                 public override string ToString()
165                 {
166                         StringBuilder sb = new StringBuilder();
167                         sb.Append('[');
168                         sb.Append(Constructor.DeclaringType.FullName);
169                         sb.Append('(');
170                         string sep = "";
171                         ParameterInfo[] parameters = Constructor.GetParameters();
172                         IList<CustomAttributeTypedArgument> args = ConstructorArguments;
173                         for (int i = 0; i < parameters.Length; i++)
174                         {
175                                 sb.Append(sep);
176                                 sep = ", ";
177                                 AppendValue(sb, parameters[i].ParameterType, args[i]);
178                         }
179                         foreach (CustomAttributeNamedArgument named in NamedArguments)
180                         {
181                                 sb.Append(sep);
182                                 sep = ", ";
183                                 sb.Append(named.MemberInfo.Name);
184                                 sb.Append(" = ");
185                                 FieldInfo fi = named.MemberInfo as FieldInfo;
186                                 Type type = fi != null ? fi.FieldType : ((PropertyInfo)named.MemberInfo).PropertyType;
187                                 AppendValue(sb, type, named.TypedValue);
188                         }
189                         sb.Append(')');
190                         sb.Append(']');
191                         return sb.ToString();
192                 }
193
194                 private static void AppendValue(StringBuilder sb, Type type, CustomAttributeTypedArgument arg)
195                 {
196                         if (arg.ArgumentType == arg.ArgumentType.Module.universe.System_String)
197                         {
198                                 sb.Append('"').Append(arg.Value).Append('"');
199                         }
200                         else if (arg.ArgumentType.IsArray)
201                         {
202                                 Type elementType = arg.ArgumentType.GetElementType();
203                                 string elementTypeName;
204                                 if (elementType.IsPrimitive
205                                         || elementType == type.Module.universe.System_Object
206                                         || elementType == type.Module.universe.System_String
207                                         || elementType == type.Module.universe.System_Type)
208                                 {
209                                         elementTypeName = elementType.Name;
210                                 }
211                                 else
212                                 {
213                                         elementTypeName = elementType.FullName;
214                                 }
215                                 sb.Append("new ").Append(elementTypeName).Append("[").Append(((Array)arg.Value).Length).Append("] { ");
216                                 string sep = "";
217                                 foreach (CustomAttributeTypedArgument elem in (CustomAttributeTypedArgument[])arg.Value)
218                                 {
219                                         sb.Append(sep);
220                                         sep = ", ";
221                                         AppendValue(sb, elementType, elem);
222                                 }
223                                 sb.Append(" }");
224                         }
225                         else
226                         {
227                                 if (arg.ArgumentType != type || (type.IsEnum && !arg.Value.Equals(0)))
228                                 {
229                                         sb.Append('(');
230                                         sb.Append(arg.ArgumentType.FullName);
231                                         sb.Append(')');
232                                 }
233                                 sb.Append(arg.Value);
234                         }
235                 }
236
237                 internal static void ReadDeclarativeSecurity(Module module, int index, List<CustomAttributeData> list)
238                 {
239                         Universe u = module.universe;
240                         Assembly asm = module.Assembly;
241                         int action = module.DeclSecurity.records[index].Action;
242                         ByteReader br = module.GetBlob(module.DeclSecurity.records[index].PermissionSet);
243                         if (br.PeekByte() == '.')
244                         {
245                                 br.ReadByte();
246                                 int count = br.ReadCompressedInt();
247                                 for (int j = 0; j < count; j++)
248                                 {
249                                         Type type = ReadType(asm, br);
250                                         ConstructorInfo constructor = type.GetPseudoCustomAttributeConstructor(u.System_Security_Permissions_SecurityAction);
251                                         // LAMESPEC there is an additional length here (probably of the named argument list)
252                                         byte[] blob = br.ReadBytes(br.ReadCompressedInt());
253                                         list.Add(new CustomAttributeData(asm, constructor, action, blob, index));
254                                 }
255                         }
256                         else
257                         {
258                                 // .NET 1.x format (xml)
259                                 char[] buf = new char[br.Length / 2];
260                                 for (int i = 0; i < buf.Length; i++)
261                                 {
262                                         buf[i] = br.ReadChar();
263                                 }
264                                 string xml = new String(buf);
265                                 ConstructorInfo constructor = u.System_Security_Permissions_PermissionSetAttribute.GetPseudoCustomAttributeConstructor(u.System_Security_Permissions_SecurityAction);
266                                 List<CustomAttributeNamedArgument> args = new List<CustomAttributeNamedArgument>();
267                                 args.Add(new CustomAttributeNamedArgument(GetProperty(u.System_Security_Permissions_PermissionSetAttribute, "XML", u.System_String),
268                                         new CustomAttributeTypedArgument(u.System_String, xml)));
269                                 list.Add(new CustomAttributeData(asm.ManifestModule, constructor, new object[] { action }, args));
270                         }
271                 }
272
273                 // 5) Unresolved declarative security
274                 internal CustomAttributeData(Assembly asm, ConstructorInfo constructor, int securityAction, byte[] blob, int index)
275                 {
276                         this.module = asm.ManifestModule;
277                         this.customAttributeIndex = -1;
278                         this.declSecurityIndex = index;
279                         Universe u = constructor.Module.universe;
280                         this.lazyConstructor = constructor;
281                         List<CustomAttributeTypedArgument> list = new List<CustomAttributeTypedArgument>();
282                         list.Add(new CustomAttributeTypedArgument(u.System_Security_Permissions_SecurityAction, securityAction));
283                         this.lazyConstructorArguments =  list.AsReadOnly();
284                         this.declSecurityBlob = blob;
285                 }
286
287                 private static Type ReadFieldOrPropType(Assembly asm, ByteReader br)
288                 {
289                         Universe u = asm.universe;
290                         switch (br.ReadByte())
291                         {
292                                 case Signature.ELEMENT_TYPE_BOOLEAN:
293                                         return u.System_Boolean;
294                                 case Signature.ELEMENT_TYPE_CHAR:
295                                         return u.System_Char;
296                                 case Signature.ELEMENT_TYPE_I1:
297                                         return u.System_SByte;
298                                 case Signature.ELEMENT_TYPE_U1:
299                                         return u.System_Byte;
300                                 case Signature.ELEMENT_TYPE_I2:
301                                         return u.System_Int16;
302                                 case Signature.ELEMENT_TYPE_U2:
303                                         return u.System_UInt16;
304                                 case Signature.ELEMENT_TYPE_I4:
305                                         return u.System_Int32;
306                                 case Signature.ELEMENT_TYPE_U4:
307                                         return u.System_UInt32;
308                                 case Signature.ELEMENT_TYPE_I8:
309                                         return u.System_Int64;
310                                 case Signature.ELEMENT_TYPE_U8:
311                                         return u.System_UInt64;
312                                 case Signature.ELEMENT_TYPE_R4:
313                                         return u.System_Single;
314                                 case Signature.ELEMENT_TYPE_R8:
315                                         return u.System_Double;
316                                 case Signature.ELEMENT_TYPE_STRING:
317                                         return u.System_String;
318                                 case Signature.ELEMENT_TYPE_SZARRAY:
319                                         return ReadFieldOrPropType(asm, br).MakeArrayType();
320                                 case 0x55:
321                                         return ReadType(asm, br);
322                                 case 0x50:
323                                         return u.System_Type;
324                                 case 0x51:
325                                         return u.System_Object;
326                                 default:
327                                         throw new BadImageFormatException();
328                         }
329                 }
330
331                 private static CustomAttributeTypedArgument ReadFixedArg(Assembly asm, ByteReader br, Type type)
332                 {
333                         Universe u = asm.universe;
334                         if (type == u.System_String)
335                         {
336                                 return new CustomAttributeTypedArgument(type, br.ReadString());
337                         }
338                         else if (type == u.System_Boolean)
339                         {
340                                 return new CustomAttributeTypedArgument(type, br.ReadByte() != 0);
341                         }
342                         else if (type == u.System_Char)
343                         {
344                                 return new CustomAttributeTypedArgument(type, br.ReadChar());
345                         }
346                         else if (type == u.System_Single)
347                         {
348                                 return new CustomAttributeTypedArgument(type, br.ReadSingle());
349                         }
350                         else if (type == u.System_Double)
351                         {
352                                 return new CustomAttributeTypedArgument(type, br.ReadDouble());
353                         }
354                         else if (type == u.System_SByte)
355                         {
356                                 return new CustomAttributeTypedArgument(type, br.ReadSByte());
357                         }
358                         else if (type == u.System_Int16)
359                         {
360                                 return new CustomAttributeTypedArgument(type, br.ReadInt16());
361                         }
362                         else if (type == u.System_Int32)
363                         {
364                                 return new CustomAttributeTypedArgument(type, br.ReadInt32());
365                         }
366                         else if (type == u.System_Int64)
367                         {
368                                 return new CustomAttributeTypedArgument(type, br.ReadInt64());
369                         }
370                         else if (type == u.System_Byte)
371                         {
372                                 return new CustomAttributeTypedArgument(type, br.ReadByte());
373                         }
374                         else if (type == u.System_UInt16)
375                         {
376                                 return new CustomAttributeTypedArgument(type, br.ReadUInt16());
377                         }
378                         else if (type == u.System_UInt32)
379                         {
380                                 return new CustomAttributeTypedArgument(type, br.ReadUInt32());
381                         }
382                         else if (type == u.System_UInt64)
383                         {
384                                 return new CustomAttributeTypedArgument(type, br.ReadUInt64());
385                         }
386                         else if (type == u.System_Type)
387                         {
388                                 return new CustomAttributeTypedArgument(type, ReadType(asm, br));
389                         }
390                         else if (type == u.System_Object)
391                         {
392                                 return ReadFixedArg(asm, br, ReadFieldOrPropType(asm, br));
393                         }
394                         else if (type.IsArray)
395                         {
396                                 int length = br.ReadInt32();
397                                 if (length == -1)
398                                 {
399                                         return new CustomAttributeTypedArgument(type, null);
400                                 }
401                                 Type elementType = type.GetElementType();
402                                 CustomAttributeTypedArgument[] array = new CustomAttributeTypedArgument[length];
403                                 for (int i = 0; i < length; i++)
404                                 {
405                                         array[i] = ReadFixedArg(asm, br, elementType);
406                                 }
407                                 return new CustomAttributeTypedArgument(type, array);
408                         }
409                         else if (type.IsEnum)
410                         {
411                                 return new CustomAttributeTypedArgument(type, ReadFixedArg(asm, br, type.GetEnumUnderlyingTypeImpl()).Value);
412                         }
413                         else
414                         {
415                                 throw new InvalidOperationException();
416                         }
417                 }
418
419                 private static Type ReadType(Assembly asm, ByteReader br)
420                 {
421                         string typeName = br.ReadString();
422                         if (typeName == null)
423                         {
424                                 return null;
425                         }
426                         if (typeName.Length > 0 && typeName[typeName.Length - 1] == 0)
427                         {
428                                 // there are broken compilers that emit an extra NUL character after the type name
429                                 typeName = typeName.Substring(0, typeName.Length - 1);
430                         }
431                         return TypeNameParser.Parse(typeName, true).GetType(asm.universe, asm, true, typeName, true, false);
432                 }
433
434                 private static IList<CustomAttributeTypedArgument> ReadConstructorArguments(Assembly asm, ByteReader br, ConstructorInfo constructor)
435                 {
436                         MethodSignature sig = constructor.MethodSignature;
437                         int count = sig.GetParameterCount();
438                         List<CustomAttributeTypedArgument> list = new List<CustomAttributeTypedArgument>(count);
439                         for (int i = 0; i < count; i++)
440                         {
441                                 list.Add(ReadFixedArg(asm, br, sig.GetParameterType(i)));
442                         }
443                         return list.AsReadOnly();
444                 }
445
446                 private static IList<CustomAttributeNamedArgument> ReadNamedArguments(Assembly asm, ByteReader br, int named, Type type)
447                 {
448                         List<CustomAttributeNamedArgument> list = new List<CustomAttributeNamedArgument>(named);
449                         for (int i = 0; i < named; i++)
450                         {
451                                 byte fieldOrProperty = br.ReadByte();
452                                 Type fieldOrPropertyType = ReadFieldOrPropType(asm, br);
453                                 string name = br.ReadString();
454                                 CustomAttributeTypedArgument value = ReadFixedArg(asm, br, fieldOrPropertyType);
455                                 MemberInfo member;
456                                 switch (fieldOrProperty)
457                                 {
458                                         case 0x53:
459                                                 member = GetField(type, name, fieldOrPropertyType);
460                                                 break;
461                                         case 0x54:
462                                                 member = GetProperty(type, name, fieldOrPropertyType);
463                                                 break;
464                                         default:
465                                                 throw new BadImageFormatException();
466                                 }
467                                 list.Add(new CustomAttributeNamedArgument(member, value));
468                         }
469                         return list.AsReadOnly();
470                 }
471
472                 private static FieldInfo GetField(Type type, string name, Type fieldType)
473                 {
474                         Type org = type;
475                         for (; type != null && !type.__IsMissing; type = type.BaseType)
476                         {
477                                 foreach (FieldInfo field in type.__GetDeclaredFields())
478                                 {
479                                         if (field.IsPublic && !field.IsStatic && field.Name == name)
480                                         {
481                                                 return field;
482                                         }
483                                 }
484                         }
485                         // if the field is missing, we stick the missing field on the first missing base type
486                         if (type == null)
487                         {
488                                 type = org;
489                         }
490                         FieldSignature sig = FieldSignature.Create(fieldType, new CustomModifiers());
491                         return type.FindField(name, sig)
492                                 ?? type.Module.universe.GetMissingFieldOrThrow(type, name, sig);
493                 }
494
495                 private static PropertyInfo GetProperty(Type type, string name, Type propertyType)
496                 {
497                         Type org = type;
498                         for (; type != null && !type.__IsMissing; type = type.BaseType)
499                         {
500                                 foreach (PropertyInfo property in type.__GetDeclaredProperties())
501                                 {
502                                         if (property.IsPublic && !property.IsStatic && property.Name == name)
503                                         {
504                                                 return property;
505                                         }
506                                 }
507                         }
508                         // if the property is missing, we stick the missing property on the first missing base type
509                         if (type == null)
510                         {
511                                 type = org;
512                         }
513                         return type.Module.universe.GetMissingPropertyOrThrow(type, name, PropertySignature.Create(CallingConventions.Standard | CallingConventions.HasThis, propertyType, null, new PackedCustomModifiers()));
514                 }
515
516                 [Obsolete("Use AttributeType property instead.")]
517                 internal bool __TryReadTypeName(out string ns, out string name)
518                 {
519                         if (Constructor.DeclaringType.IsNested)
520                         {
521                                 ns = null;
522                                 name = null;
523                                 return false;
524                         }
525                         ns = Constructor.DeclaringType.__Namespace;
526                         name = Constructor.DeclaringType.__Name;
527                         return true;
528                 }
529
530                 public byte[] __GetBlob()
531                 {
532                         if (declSecurityBlob != null)
533                         {
534                                 return (byte[])declSecurityBlob.Clone();
535                         }
536                         else if (customAttributeIndex == -1)
537                         {
538                                 return __ToBuilder().GetBlob(module.Assembly);
539                         }
540                         else
541                         {
542                                 return ((ModuleReader)module).GetBlobCopy(module.CustomAttribute.records[customAttributeIndex].Value);
543                         }
544                 }
545
546                 public int __Parent
547                 {
548                         get
549                         {
550                                 return customAttributeIndex >= 0
551                                         ? module.CustomAttribute.records[customAttributeIndex].Parent
552                                         : declSecurityIndex >= 0
553                                                 ? module.DeclSecurity.records[declSecurityIndex].Parent
554                                                 : 0;
555                         }
556                 }
557
558                 // .NET 4.5 API
559                 public Type AttributeType
560                 {
561                         get { return Constructor.DeclaringType; }
562                 }
563
564                 public ConstructorInfo Constructor
565                 {
566                         get
567                         {
568                                 if (lazyConstructor == null)
569                                 {
570                                         lazyConstructor = (ConstructorInfo)module.ResolveMethod(module.CustomAttribute.records[customAttributeIndex].Type);
571                                 }
572                                 return lazyConstructor;
573                         }
574                 }
575
576                 public IList<CustomAttributeTypedArgument> ConstructorArguments
577                 {
578                         get
579                         {
580                                 if (lazyConstructorArguments == null)
581                                 {
582                                         LazyParseArguments();
583                                 }
584                                 return lazyConstructorArguments;
585                         }
586                 }
587
588                 public IList<CustomAttributeNamedArgument> NamedArguments
589                 {
590                         get
591                         {
592                                 if (lazyNamedArguments == null)
593                                 {
594                                         if (customAttributeIndex >= 0)
595                                         {
596                                                 // 1) Unresolved Custom Attribute
597                                                 LazyParseArguments();
598                                         }
599                                         else
600                                         {
601                                                 // 5) Unresolved declarative security
602                                                 ByteReader br = new ByteReader(declSecurityBlob, 0, declSecurityBlob.Length);
603                                                 // LAMESPEC the count of named arguments is a compressed integer (instead of UInt16 as NumNamed in custom attributes)
604                                                 lazyNamedArguments = ReadNamedArguments(module.Assembly, br, br.ReadCompressedInt(), Constructor.DeclaringType);
605                                         }
606                                 }
607                                 return lazyNamedArguments;
608                         }
609                 }
610
611                 private void LazyParseArguments()
612                 {
613                         ByteReader br = module.GetBlob(module.CustomAttribute.records[customAttributeIndex].Value);
614                         if (br.Length == 0)
615                         {
616                                 // it's legal to have an empty blob
617                                 lazyConstructorArguments = Empty<CustomAttributeTypedArgument>.Array;
618                                 lazyNamedArguments = Empty<CustomAttributeNamedArgument>.Array;
619                         }
620                         else
621                         {
622                                 if (br.ReadUInt16() != 1)
623                                 {
624                                         throw new BadImageFormatException();
625                                 }
626                                 lazyConstructorArguments = ReadConstructorArguments(module.Assembly, br, Constructor);
627                                 lazyNamedArguments = ReadNamedArguments(module.Assembly, br, br.ReadUInt16(), Constructor.DeclaringType);
628                         }
629                 }
630
631                 public CustomAttributeBuilder __ToBuilder()
632                 {
633                         ParameterInfo[] parameters = Constructor.GetParameters();
634                         object[] args = new object[ConstructorArguments.Count];
635                         for (int i = 0; i < args.Length; i++)
636                         {
637                                 args[i] = RewrapArray(parameters[i].ParameterType, ConstructorArguments[i]);
638                         }
639                         List<PropertyInfo> namedProperties = new List<PropertyInfo>();
640                         List<object> propertyValues = new List<object>();
641                         List<FieldInfo> namedFields = new List<FieldInfo>();
642                         List<object> fieldValues = new List<object>();
643                         foreach (CustomAttributeNamedArgument named in NamedArguments)
644                         {
645                                 PropertyInfo pi = named.MemberInfo as PropertyInfo;
646                                 if (pi != null)
647                                 {
648                                         namedProperties.Add(pi);
649                                         propertyValues.Add(RewrapArray(pi.PropertyType, named.TypedValue));
650                                 }
651                                 else
652                                 {
653                                         FieldInfo fi = (FieldInfo)named.MemberInfo;
654                                         namedFields.Add(fi);
655                                         fieldValues.Add(RewrapArray(fi.FieldType, named.TypedValue));
656                                 }
657                         }
658                         return new CustomAttributeBuilder(Constructor, args, namedProperties.ToArray(), propertyValues.ToArray(), namedFields.ToArray(), fieldValues.ToArray());
659                 }
660
661                 private static object RewrapArray(Type type, CustomAttributeTypedArgument arg)
662                 {
663                         IList<CustomAttributeTypedArgument> list = arg.Value as IList<CustomAttributeTypedArgument>;
664                         if (list != null)
665                         {
666                                 Type elementType = arg.ArgumentType.GetElementType();
667                                 object[] arr = new object[list.Count];
668                                 for (int i = 0; i < arr.Length; i++)
669                                 {
670                                         arr[i] = RewrapArray(elementType, list[i]);
671                                 }
672                                 if (type == type.Module.universe.System_Object)
673                                 {
674                                         return CustomAttributeBuilder.__MakeTypedArgument(arg.ArgumentType, arr);
675                                 }
676                                 return arr;
677                         }
678                         else
679                         {
680                                 return arg.Value;
681                         }
682                 }
683
684                 public static IList<CustomAttributeData> GetCustomAttributes(MemberInfo member)
685                 {
686                         return __GetCustomAttributes(member, null, false);
687                 }
688
689                 public static IList<CustomAttributeData> GetCustomAttributes(Assembly assembly)
690                 {
691                         return assembly.GetCustomAttributesData(null);
692                 }
693
694                 public static IList<CustomAttributeData> GetCustomAttributes(Module module)
695                 {
696                         return __GetCustomAttributes(module, null, false);
697                 }
698
699                 public static IList<CustomAttributeData> GetCustomAttributes(ParameterInfo parameter)
700                 {
701                         return __GetCustomAttributes(parameter, null, false);
702                 }
703
704                 public static IList<CustomAttributeData> __GetCustomAttributes(Assembly assembly, Type attributeType, bool inherit)
705                 {
706                         return assembly.GetCustomAttributesData(attributeType);
707                 }
708
709                 public static IList<CustomAttributeData> __GetCustomAttributes(Module module, Type attributeType, bool inherit)
710                 {
711                         if (module.__IsMissing)
712                         {
713                                 throw new MissingModuleException((MissingModule)module);
714                         }
715                         return GetCustomAttributesImpl(null, module, 0x00000001, attributeType) ?? EmptyList;
716                 }
717
718                 public static IList<CustomAttributeData> __GetCustomAttributes(ParameterInfo parameter, Type attributeType, bool inherit)
719                 {
720                         Module module = parameter.Module;
721                         List<CustomAttributeData> list = null;
722                         if (module.universe.ReturnPseudoCustomAttributes)
723                         {
724                                 if (attributeType == null || attributeType.IsAssignableFrom(parameter.Module.universe.System_Runtime_InteropServices_MarshalAsAttribute))
725                                 {
726                                         FieldMarshal spec;
727                                         if (parameter.__TryGetFieldMarshal(out spec))
728                                         {
729                                                 if (list == null)
730                                                 {
731                                                         list = new List<CustomAttributeData>();
732                                                 }
733                                                 list.Add(CustomAttributeData.CreateMarshalAsPseudoCustomAttribute(parameter.Module, spec));
734                                         }
735                                 }
736                         }
737                         ModuleBuilder mb = module as ModuleBuilder;
738                         int token = parameter.MetadataToken;
739                         if (mb != null && mb.IsSaved && mb.IsPseudoToken(token))
740                         {
741                                 token = mb.ResolvePseudoToken(token);
742                         }
743                         return GetCustomAttributesImpl(list, module, token, attributeType) ?? EmptyList;
744                 }
745
746                 public static IList<CustomAttributeData> __GetCustomAttributes(MemberInfo member, Type attributeType, bool inherit)
747                 {
748                         if (!member.IsBaked)
749                         {
750                                 // like .NET we we don't return custom attributes for unbaked members
751                                 throw new NotImplementedException();
752                         }
753                         if (!inherit || !IsInheritableAttribute(attributeType))
754                         {
755                                 return GetCustomAttributesImpl(null, member, attributeType) ?? EmptyList;
756                         }
757                         List<CustomAttributeData> list = new List<CustomAttributeData>();
758                         for (; ; )
759                         {
760                                 GetCustomAttributesImpl(list, member, attributeType);
761                                 Type type = member as Type;
762                                 if (type != null)
763                                 {
764                                         type = type.BaseType;
765                                         if (type == null)
766                                         {
767                                                 return list;
768                                         }
769                                         member = type;
770                                         continue;
771                                 }
772                                 MethodInfo method = member as MethodInfo;
773                                 if (method != null)
774                                 {
775                                         MemberInfo prev = member;
776                                         method = method.GetBaseDefinition();
777                                         if (method == null || method == prev)
778                                         {
779                                                 return list;
780                                         }
781                                         member = method;
782                                         continue;
783                                 }
784                                 return list;
785                         }
786                 }
787
788                 private static List<CustomAttributeData> GetCustomAttributesImpl(List<CustomAttributeData> list, MemberInfo member, Type attributeType)
789                 {
790                         if (member.Module.universe.ReturnPseudoCustomAttributes)
791                         {
792                                 List<CustomAttributeData> pseudo = member.GetPseudoCustomAttributes(attributeType);
793                                 if (list == null)
794                                 {
795                                         list = pseudo;
796                                 }
797                                 else if (pseudo != null)
798                                 {
799                                         list.AddRange(pseudo);
800                                 }
801                         }
802                         return GetCustomAttributesImpl(list, member.Module, member.GetCurrentToken(), attributeType);
803                 }
804
805                 internal static List<CustomAttributeData> GetCustomAttributesImpl(List<CustomAttributeData> list, Module module, int token, Type attributeType)
806                 {
807                         foreach (int i in module.CustomAttribute.Filter(token))
808                         {
809                                 if (attributeType == null)
810                                 {
811                                         if (list == null)
812                                         {
813                                                 list = new List<CustomAttributeData>();
814                                         }
815                                         list.Add(new CustomAttributeData(module, i));
816                                 }
817                                 else
818                                 {
819                                         if (attributeType.IsAssignableFrom(module.ResolveMethod(module.CustomAttribute.records[i].Type).DeclaringType))
820                                         {
821                                                 if (list == null)
822                                                 {
823                                                         list = new List<CustomAttributeData>();
824                                                 }
825                                                 list.Add(new CustomAttributeData(module, i));
826                                         }
827                                 }
828                         }
829                         return list;
830                 }
831
832                 public static IList<CustomAttributeData> __GetCustomAttributes(Type type, Type interfaceType, Type attributeType, bool inherit)
833                 {
834                         Module module = type.Module;
835                         foreach (int i in module.InterfaceImpl.Filter(type.MetadataToken))
836                         {
837                                 if (module.ResolveType(module.InterfaceImpl.records[i].Interface, type) == interfaceType)
838                                 {
839                                         return GetCustomAttributesImpl(null, module, (InterfaceImplTable.Index << 24) | (i + 1), attributeType) ?? EmptyList;
840                                 }
841                         }
842                         return EmptyList;
843                 }
844
845                 public static IList<CustomAttributeData> __GetDeclarativeSecurity(Assembly assembly)
846                 {
847                         if (assembly.__IsMissing)
848                         {
849                                 throw new MissingAssemblyException((MissingAssembly)assembly);
850                         }
851                         return assembly.ManifestModule.GetDeclarativeSecurity(0x20000001);
852                 }
853
854                 public static IList<CustomAttributeData> __GetDeclarativeSecurity(Type type)
855                 {
856                         if ((type.Attributes & TypeAttributes.HasSecurity) != 0)
857                         {
858                                 return type.Module.GetDeclarativeSecurity(type.MetadataToken);
859                         }
860                         else
861                         {
862                                 return EmptyList;
863                         }
864                 }
865
866                 public static IList<CustomAttributeData> __GetDeclarativeSecurity(MethodBase method)
867                 {
868                         if ((method.Attributes & MethodAttributes.HasSecurity) != 0)
869                         {
870                                 return method.Module.GetDeclarativeSecurity(method.MetadataToken);
871                         }
872                         else
873                         {
874                                 return EmptyList;
875                         }
876                 }
877
878                 private static bool IsInheritableAttribute(Type attribute)
879                 {
880                         Type attributeUsageAttribute = attribute.Module.universe.System_AttributeUsageAttribute;
881                         IList<CustomAttributeData> attr = __GetCustomAttributes(attribute, attributeUsageAttribute, false);
882                         if (attr.Count != 0)
883                         {
884                                 foreach (CustomAttributeNamedArgument named in attr[0].NamedArguments)
885                                 {
886                                         if (named.MemberInfo.Name == "Inherited")
887                                         {
888                                                 return (bool)named.TypedValue.Value;
889                                         }
890                                 }
891                         }
892                         return true;
893                 }
894
895                 internal static CustomAttributeData CreateDllImportPseudoCustomAttribute(Module module, ImplMapFlags flags, string entryPoint, string dllName, MethodImplAttributes attr)
896                 {
897                         Type type = module.universe.System_Runtime_InteropServices_DllImportAttribute;
898                         ConstructorInfo constructor = type.GetPseudoCustomAttributeConstructor(module.universe.System_String);
899                         List<CustomAttributeNamedArgument> list = new List<CustomAttributeNamedArgument>();
900                         System.Runtime.InteropServices.CharSet charSet;
901                         switch (flags & ImplMapFlags.CharSetMask)
902                         {
903                                 case ImplMapFlags.CharSetAnsi:
904                                         charSet = System.Runtime.InteropServices.CharSet.Ansi;
905                                         break;
906                                 case ImplMapFlags.CharSetUnicode:
907                                         charSet = System.Runtime.InteropServices.CharSet.Unicode;
908                                         break;
909                                 case ImplMapFlags.CharSetAuto:
910                                         charSet = System.Runtime.InteropServices.CharSet.Auto;
911                                         break;
912                                 case ImplMapFlags.CharSetNotSpec:
913                                 default:
914                                         charSet = System.Runtime.InteropServices.CharSet.None;
915                                         break;
916                         }
917                         System.Runtime.InteropServices.CallingConvention callingConvention;
918                         switch (flags & ImplMapFlags.CallConvMask)
919                         {
920                                 case ImplMapFlags.CallConvCdecl:
921                                         callingConvention = System.Runtime.InteropServices.CallingConvention.Cdecl;
922                                         break;
923                                 case ImplMapFlags.CallConvFastcall:
924                                         callingConvention = System.Runtime.InteropServices.CallingConvention.FastCall;
925                                         break;
926                                 case ImplMapFlags.CallConvStdcall:
927                                         callingConvention = System.Runtime.InteropServices.CallingConvention.StdCall;
928                                         break;
929                                 case ImplMapFlags.CallConvThiscall:
930                                         callingConvention = System.Runtime.InteropServices.CallingConvention.ThisCall;
931                                         break;
932                                 case ImplMapFlags.CallConvWinapi:
933                                         callingConvention = System.Runtime.InteropServices.CallingConvention.Winapi;
934                                         break;
935                                 default:
936                                         callingConvention = 0;
937                                         break;
938                         }
939                         AddNamedArgument(list, type, "EntryPoint", entryPoint);
940                         AddNamedArgument(list, type, "CharSet", module.universe.System_Runtime_InteropServices_CharSet, (int)charSet);
941                         AddNamedArgument(list, type, "ExactSpelling", (int)flags, (int)ImplMapFlags.NoMangle);
942                         AddNamedArgument(list, type, "SetLastError", (int)flags, (int)ImplMapFlags.SupportsLastError);
943                         AddNamedArgument(list, type, "PreserveSig", (int)attr, (int)MethodImplAttributes.PreserveSig);
944                         AddNamedArgument(list, type, "CallingConvention", module.universe.System_Runtime_InteropServices_CallingConvention, (int)callingConvention);
945                         AddNamedArgument(list, type, "BestFitMapping", (int)flags, (int)ImplMapFlags.BestFitOn);
946                         AddNamedArgument(list, type, "ThrowOnUnmappableChar", (int)flags, (int)ImplMapFlags.CharMapErrorOn);
947                         return new CustomAttributeData(module, constructor, new object[] { dllName }, list);
948                 }
949
950                 internal static CustomAttributeData CreateMarshalAsPseudoCustomAttribute(Module module, FieldMarshal fm)
951                 {
952                         Type typeofMarshalAs = module.universe.System_Runtime_InteropServices_MarshalAsAttribute;
953                         Type typeofUnmanagedType = module.universe.System_Runtime_InteropServices_UnmanagedType;
954                         Type typeofVarEnum = module.universe.System_Runtime_InteropServices_VarEnum;
955                         Type typeofType = module.universe.System_Type;
956                         List<CustomAttributeNamedArgument> named = new List<CustomAttributeNamedArgument>();
957                         AddNamedArgument(named, typeofMarshalAs, "ArraySubType", typeofUnmanagedType, (int)(fm.ArraySubType ?? 0));
958                         AddNamedArgument(named, typeofMarshalAs, "SizeParamIndex", module.universe.System_Int16, fm.SizeParamIndex ?? 0);
959                         AddNamedArgument(named, typeofMarshalAs, "SizeConst", module.universe.System_Int32, fm.SizeConst ?? 0);
960                         AddNamedArgument(named, typeofMarshalAs, "IidParameterIndex", module.universe.System_Int32, fm.IidParameterIndex ?? 0);
961                         AddNamedArgument(named, typeofMarshalAs, "SafeArraySubType", typeofVarEnum, (int)(fm.SafeArraySubType ?? 0));
962                         if (fm.SafeArrayUserDefinedSubType != null)
963                         {
964                                 AddNamedArgument(named, typeofMarshalAs, "SafeArrayUserDefinedSubType", typeofType, fm.SafeArrayUserDefinedSubType);
965                         }
966                         if (fm.MarshalType != null)
967                         {
968                                 AddNamedArgument(named, typeofMarshalAs, "MarshalType", module.universe.System_String, fm.MarshalType);
969                         }
970                         if (fm.MarshalTypeRef != null)
971                         {
972                                 AddNamedArgument(named, typeofMarshalAs, "MarshalTypeRef", module.universe.System_Type, fm.MarshalTypeRef);
973                         }
974                         if (fm.MarshalCookie != null)
975                         {
976                                 AddNamedArgument(named, typeofMarshalAs, "MarshalCookie", module.universe.System_String, fm.MarshalCookie);
977                         }
978                         ConstructorInfo constructor = typeofMarshalAs.GetPseudoCustomAttributeConstructor(typeofUnmanagedType);
979                         return new CustomAttributeData(module, constructor, new object[] { (int)fm.UnmanagedType }, named);
980                 }
981
982                 private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type type, string fieldName, string value)
983                 {
984                         AddNamedArgument(list, type, fieldName, type.Module.universe.System_String, value);
985                 }
986
987                 private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type type, string fieldName, int flags, int flagMask)
988                 {
989                         AddNamedArgument(list, type, fieldName, type.Module.universe.System_Boolean, (flags & flagMask) != 0);
990                 }
991
992                 private static void AddNamedArgument(List<CustomAttributeNamedArgument> list, Type attributeType, string fieldName, Type valueType, object value)
993                 {
994                         // some fields are not available on the .NET Compact Framework version of DllImportAttribute/MarshalAsAttribute
995                         FieldInfo field = attributeType.FindField(fieldName, FieldSignature.Create(valueType, new CustomModifiers()));
996                         if (field != null)
997                         {
998                                 list.Add(new CustomAttributeNamedArgument(field, new CustomAttributeTypedArgument(valueType, value)));
999                         }
1000                 }
1001
1002                 internal static CustomAttributeData CreateFieldOffsetPseudoCustomAttribute(Module module, int offset)
1003                 {
1004                         Type type = module.universe.System_Runtime_InteropServices_FieldOffsetAttribute;
1005                         ConstructorInfo constructor = type.GetPseudoCustomAttributeConstructor(module.universe.System_Int32);
1006                         return new CustomAttributeData(module, constructor, new object[] { offset }, null);
1007                 }
1008
1009                 internal static CustomAttributeData CreatePreserveSigPseudoCustomAttribute(Module module)
1010                 {
1011                         Type type = module.universe.System_Runtime_InteropServices_PreserveSigAttribute;
1012                         ConstructorInfo constructor = type.GetPseudoCustomAttributeConstructor();
1013                         return new CustomAttributeData(module, constructor, Empty<object>.Array, null);
1014                 }
1015         }
1016 }