Fix GetCustomAttribute API for DllImportAttribute pseudo custom attribute
[platform/upstream/coreclr.git] / src / mscorlib / src / System / Reflection / CustomAttribute.cs
1 // Licensed to the .NET Foundation under one or more agreements.
2 // The .NET Foundation licenses this file to you under the MIT license.
3 // See the LICENSE file in the project root for more information.
4
5 // 
6
7 using System;
8 using System.Runtime.CompilerServices;
9 using System.Runtime.InteropServices;
10 using System.Collections;
11 using System.Collections.Generic;
12 using System.Resources;
13 using System.Diagnostics;
14 using System.Diagnostics.Tracing;
15 using System.Globalization;
16 using System.Security;
17 using System.Runtime.ConstrainedExecution;
18 using System.Runtime.Versioning;
19
20 namespace System.Reflection
21 {
22     public class CustomAttributeData
23     {
24         #region Public Static Members
25         public static IList<CustomAttributeData> GetCustomAttributes(MemberInfo target)
26         {
27             if (target == null)
28                 throw new ArgumentNullException(nameof(target));
29
30             return target.GetCustomAttributesData();
31         }
32
33         public static IList<CustomAttributeData> GetCustomAttributes(Module target)
34         {
35             if (target == null)
36                 throw new ArgumentNullException(nameof(target));
37
38             return target.GetCustomAttributesData();
39         }
40
41         public static IList<CustomAttributeData> GetCustomAttributes(Assembly target)
42         {
43             if (target == null)
44                 throw new ArgumentNullException(nameof(target));
45
46             return target.GetCustomAttributesData();
47         }
48
49         public static IList<CustomAttributeData> GetCustomAttributes(ParameterInfo target)
50         {
51             if (target == null)
52                 throw new ArgumentNullException(nameof(target));
53
54             return target.GetCustomAttributesData();
55         }
56         #endregion
57
58         #region Internal Static Members
59         internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeType target)
60         {
61             Debug.Assert(target != null);
62
63             IList<CustomAttributeData> cad = GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
64
65             int pcaCount = 0;
66             Attribute[] a = PseudoCustomAttribute.GetCustomAttributes((RuntimeType)target, typeof(object) as RuntimeType, out pcaCount);
67
68             if (pcaCount == 0)
69                 return cad;
70
71             CustomAttributeData[] pca = new CustomAttributeData[cad.Count + pcaCount];
72             cad.CopyTo(pca, pcaCount);
73             for (int i = 0; i < pcaCount; i++)
74             {
75                 pca[i] = new CustomAttributeData(a[i]);
76             }
77
78             return Array.AsReadOnly(pca);
79         }
80
81         internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeFieldInfo target)
82         {
83             Debug.Assert(target != null);
84
85             IList<CustomAttributeData> cad = GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
86
87             int pcaCount = 0;
88             Attribute[] a = PseudoCustomAttribute.GetCustomAttributes((RuntimeFieldInfo)target, typeof(object) as RuntimeType, out pcaCount);
89
90             if (pcaCount == 0)
91                 return cad;
92
93             CustomAttributeData[] pca = new CustomAttributeData[cad.Count + pcaCount];
94             cad.CopyTo(pca, pcaCount);
95             for (int i = 0; i < pcaCount; i++)
96             {
97                 pca[i] = new CustomAttributeData(a[i]);
98             }
99
100             return Array.AsReadOnly(pca);
101         }
102
103         internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeMethodInfo target)
104         {
105             Debug.Assert(target != null);
106
107             IList<CustomAttributeData> cad = GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
108
109             int pcaCount = 0;
110             Attribute[] a = PseudoCustomAttribute.GetCustomAttributes((RuntimeMethodInfo)target, typeof(object) as RuntimeType, out pcaCount);
111
112             if (pcaCount == 0)
113                 return cad;
114
115             CustomAttributeData[] pca = new CustomAttributeData[cad.Count + pcaCount];
116             cad.CopyTo(pca, pcaCount);
117             for (int i = 0; i < pcaCount; i++)
118             {
119                 pca[i] = new CustomAttributeData(a[i]);
120             }
121
122             return Array.AsReadOnly(pca);
123         }
124
125         internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeConstructorInfo target)
126         {
127             Debug.Assert(target != null);
128
129             return GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
130         }
131
132         internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeEventInfo target)
133         {
134             Debug.Assert(target != null);
135
136             return GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
137         }
138
139         internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimePropertyInfo target)
140         {
141             Debug.Assert(target != null);
142
143             return GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
144         }
145
146         internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeModule target)
147         {
148             Debug.Assert(target != null);
149
150             if (target.IsResource())
151                 return new List<CustomAttributeData>();
152
153             return GetCustomAttributes(target, target.MetadataToken);
154         }
155
156         internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeAssembly target)
157         {
158             Debug.Assert(target != null);
159
160             IList<CustomAttributeData> cad = GetCustomAttributes((RuntimeModule)target.ManifestModule, RuntimeAssembly.GetToken(target.GetNativeHandle()));
161
162             int pcaCount = 0;
163             Attribute[] a = PseudoCustomAttribute.GetCustomAttributes(target, typeof(object) as RuntimeType, out pcaCount);
164
165             if (pcaCount == 0)
166                 return cad;
167
168             CustomAttributeData[] pca = new CustomAttributeData[cad.Count + pcaCount];
169             cad.CopyTo(pca, pcaCount);
170             for (int i = 0; i < pcaCount; i++)
171             {
172                 pca[i] = new CustomAttributeData(a[i]);
173             }
174
175             return Array.AsReadOnly(pca);
176         }
177
178         internal static IList<CustomAttributeData> GetCustomAttributesInternal(RuntimeParameterInfo target)
179         {
180             Debug.Assert(target != null);
181
182             IList<CustomAttributeData> cad = GetCustomAttributes(target.GetRuntimeModule(), target.MetadataToken);
183
184             int pcaCount = 0;
185             Attribute[] a = PseudoCustomAttribute.GetCustomAttributes(target, typeof(object) as RuntimeType, out pcaCount);
186
187             if (pcaCount == 0)
188                 return cad;
189
190             CustomAttributeData[] pca = new CustomAttributeData[cad.Count + pcaCount];
191             cad.CopyTo(pca, pcaCount);
192             for (int i = 0; i < pcaCount; i++)
193                 pca[i] = new CustomAttributeData(a[i]);
194
195             return Array.AsReadOnly(pca);
196         }
197         #endregion
198
199         #region Private Static Methods
200         private static CustomAttributeEncoding TypeToCustomAttributeEncoding(RuntimeType type)
201         {
202             if (type == (RuntimeType)typeof(int))
203                 return CustomAttributeEncoding.Int32;
204
205             if (type.IsEnum)
206                 return CustomAttributeEncoding.Enum;
207
208             if (type == (RuntimeType)typeof(string))
209                 return CustomAttributeEncoding.String;
210
211             if (type == (RuntimeType)typeof(Type))
212                 return CustomAttributeEncoding.Type;
213
214             if (type == (RuntimeType)typeof(object))
215                 return CustomAttributeEncoding.Object;
216
217             if (type.IsArray)
218                 return CustomAttributeEncoding.Array;
219
220             if (type == (RuntimeType)typeof(char))
221                 return CustomAttributeEncoding.Char;
222
223             if (type == (RuntimeType)typeof(bool))
224                 return CustomAttributeEncoding.Boolean;
225
226             if (type == (RuntimeType)typeof(byte))
227                 return CustomAttributeEncoding.Byte;
228
229             if (type == (RuntimeType)typeof(sbyte))
230                 return CustomAttributeEncoding.SByte;
231
232             if (type == (RuntimeType)typeof(short))
233                 return CustomAttributeEncoding.Int16;
234
235             if (type == (RuntimeType)typeof(ushort))
236                 return CustomAttributeEncoding.UInt16;
237
238             if (type == (RuntimeType)typeof(uint))
239                 return CustomAttributeEncoding.UInt32;
240
241             if (type == (RuntimeType)typeof(long))
242                 return CustomAttributeEncoding.Int64;
243
244             if (type == (RuntimeType)typeof(ulong))
245                 return CustomAttributeEncoding.UInt64;
246
247             if (type == (RuntimeType)typeof(float))
248                 return CustomAttributeEncoding.Float;
249
250             if (type == (RuntimeType)typeof(double))
251                 return CustomAttributeEncoding.Double;
252
253             // System.Enum is neither an Enum nor a Class
254             if (type == (RuntimeType)typeof(Enum))
255                 return CustomAttributeEncoding.Object;
256
257             if (type.IsClass)
258                 return CustomAttributeEncoding.Object;
259
260             if (type.IsInterface)
261                 return CustomAttributeEncoding.Object;
262
263             if (type.IsValueType)
264                 return CustomAttributeEncoding.Undefined;
265
266             throw new ArgumentException(SR.Argument_InvalidKindOfTypeForCA, nameof(type));
267         }
268         private static CustomAttributeType InitCustomAttributeType(RuntimeType parameterType)
269         {
270             CustomAttributeEncoding encodedType = CustomAttributeData.TypeToCustomAttributeEncoding(parameterType);
271             CustomAttributeEncoding encodedArrayType = CustomAttributeEncoding.Undefined;
272             CustomAttributeEncoding encodedEnumType = CustomAttributeEncoding.Undefined;
273             string enumName = null;
274
275             if (encodedType == CustomAttributeEncoding.Array)
276             {
277                 parameterType = (RuntimeType)parameterType.GetElementType();
278                 encodedArrayType = CustomAttributeData.TypeToCustomAttributeEncoding(parameterType);
279             }
280
281             if (encodedType == CustomAttributeEncoding.Enum || encodedArrayType == CustomAttributeEncoding.Enum)
282             {
283                 encodedEnumType = TypeToCustomAttributeEncoding((RuntimeType)Enum.GetUnderlyingType(parameterType));
284                 enumName = parameterType.AssemblyQualifiedName;
285             }
286
287             return new CustomAttributeType(encodedType, encodedArrayType, encodedEnumType, enumName);
288         }
289         private static IList<CustomAttributeData> GetCustomAttributes(RuntimeModule module, int tkTarget)
290         {
291             CustomAttributeRecord[] records = GetCustomAttributeRecords(module, tkTarget);
292
293             CustomAttributeData[] customAttributes = new CustomAttributeData[records.Length];
294             for (int i = 0; i < records.Length; i++)
295                 customAttributes[i] = new CustomAttributeData(module, records[i]);
296
297             return Array.AsReadOnly(customAttributes);
298         }
299         #endregion
300
301         #region Internal Static Members
302         internal unsafe static CustomAttributeRecord[] GetCustomAttributeRecords(RuntimeModule module, int targetToken)
303         {
304             MetadataImport scope = module.MetadataImport;
305
306             MetadataEnumResult tkCustomAttributeTokens;
307             scope.EnumCustomAttributes(targetToken, out tkCustomAttributeTokens);
308
309             if (tkCustomAttributeTokens.Length == 0)
310             {
311                 return Array.Empty<CustomAttributeRecord>();
312             }
313
314             CustomAttributeRecord[] records = new CustomAttributeRecord[tkCustomAttributeTokens.Length];
315
316             for (int i = 0; i < records.Length; i++)
317             {
318                 scope.GetCustomAttributeProps(
319                     tkCustomAttributeTokens[i], out records[i].tkCtor.Value, out records[i].blob);
320             }
321
322             return records;
323         }
324
325         internal static CustomAttributeTypedArgument Filter(IList<CustomAttributeData> attrs, Type caType, int parameter)
326         {
327             for (int i = 0; i < attrs.Count; i++)
328             {
329                 if (attrs[i].Constructor.DeclaringType == caType)
330                 {
331                     return attrs[i].ConstructorArguments[parameter];
332                 }
333             }
334
335             return new CustomAttributeTypedArgument();
336         }
337         #endregion
338
339         #region Private Data Members
340         private ConstructorInfo m_ctor;
341         private RuntimeModule m_scope;
342         private MemberInfo[] m_members;
343         private CustomAttributeCtorParameter[] m_ctorParams;
344         private CustomAttributeNamedParameter[] m_namedParams;
345         private IList<CustomAttributeTypedArgument> m_typedCtorArgs;
346         private IList<CustomAttributeNamedArgument> m_namedArgs;
347         #endregion
348
349         #region Constructor
350         protected CustomAttributeData()
351         {
352         }
353
354         private CustomAttributeData(RuntimeModule scope, CustomAttributeRecord caRecord)
355         {
356             m_scope = scope;
357             m_ctor = (RuntimeConstructorInfo)RuntimeType.GetMethodBase(scope, caRecord.tkCtor);
358
359             ParameterInfo[] parameters = m_ctor.GetParametersNoCopy();
360             m_ctorParams = new CustomAttributeCtorParameter[parameters.Length];
361             for (int i = 0; i < parameters.Length; i++)
362                 m_ctorParams[i] = new CustomAttributeCtorParameter(InitCustomAttributeType((RuntimeType)parameters[i].ParameterType));
363
364             FieldInfo[] fields = m_ctor.DeclaringType.GetFields(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
365             PropertyInfo[] properties = m_ctor.DeclaringType.GetProperties(BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
366             m_namedParams = new CustomAttributeNamedParameter[properties.Length + fields.Length];
367             for (int i = 0; i < fields.Length; i++)
368                 m_namedParams[i] = new CustomAttributeNamedParameter(
369                     fields[i].Name, CustomAttributeEncoding.Field, InitCustomAttributeType((RuntimeType)fields[i].FieldType));
370             for (int i = 0; i < properties.Length; i++)
371                 m_namedParams[i + fields.Length] = new CustomAttributeNamedParameter(
372                     properties[i].Name, CustomAttributeEncoding.Property, InitCustomAttributeType((RuntimeType)properties[i].PropertyType));
373
374             m_members = new MemberInfo[fields.Length + properties.Length];
375             fields.CopyTo(m_members, 0);
376             properties.CopyTo(m_members, fields.Length);
377
378             CustomAttributeEncodedArgument.ParseAttributeArguments(caRecord.blob, ref m_ctorParams, ref m_namedParams, m_scope);
379         }
380         #endregion
381
382         #region Pseudo Custom Attribute Constructor
383         internal CustomAttributeData(Attribute attribute)
384         {
385             if (attribute is DllImportAttribute)
386                 Init((DllImportAttribute)attribute);
387             else if (attribute is FieldOffsetAttribute)
388                 Init((FieldOffsetAttribute)attribute);
389             else if (attribute is MarshalAsAttribute)
390                 Init((MarshalAsAttribute)attribute);
391             else if (attribute is TypeForwardedToAttribute)
392                 Init((TypeForwardedToAttribute)attribute);
393             else
394                 Init(attribute);
395         }
396         private void Init(DllImportAttribute dllImport)
397         {
398             Type type = typeof(DllImportAttribute);
399             m_ctor = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance)[0];
400             m_typedCtorArgs = Array.AsReadOnly(new CustomAttributeTypedArgument[]
401             {
402                 new CustomAttributeTypedArgument(dllImport.Value),
403             });
404
405             m_namedArgs = Array.AsReadOnly(new CustomAttributeNamedArgument[]
406             {
407                 new CustomAttributeNamedArgument(type.GetField("EntryPoint"), dllImport.EntryPoint),
408                 new CustomAttributeNamedArgument(type.GetField("CharSet"), dllImport.CharSet),
409                 new CustomAttributeNamedArgument(type.GetField("ExactSpelling"), dllImport.ExactSpelling),
410                 new CustomAttributeNamedArgument(type.GetField("SetLastError"), dllImport.SetLastError),
411                 new CustomAttributeNamedArgument(type.GetField("PreserveSig"), dllImport.PreserveSig),
412                 new CustomAttributeNamedArgument(type.GetField("CallingConvention"), dllImport.CallingConvention),
413                 new CustomAttributeNamedArgument(type.GetField("BestFitMapping"), dllImport.BestFitMapping),
414                 new CustomAttributeNamedArgument(type.GetField("ThrowOnUnmappableChar"), dllImport.ThrowOnUnmappableChar)
415 });
416         }
417         private void Init(FieldOffsetAttribute fieldOffset)
418         {
419             m_ctor = typeof(FieldOffsetAttribute).GetConstructors(BindingFlags.Public | BindingFlags.Instance)[0];
420             m_typedCtorArgs = Array.AsReadOnly(new CustomAttributeTypedArgument[] {
421                 new CustomAttributeTypedArgument(fieldOffset.Value)
422             });
423             m_namedArgs = Array.AsReadOnly(Array.Empty<CustomAttributeNamedArgument>());
424         }
425         private void Init(MarshalAsAttribute marshalAs)
426         {
427             Type type = typeof(MarshalAsAttribute);
428             m_ctor = type.GetConstructors(BindingFlags.Public | BindingFlags.Instance)[0];
429             m_typedCtorArgs = Array.AsReadOnly(new CustomAttributeTypedArgument[]
430             {
431                 new CustomAttributeTypedArgument(marshalAs.Value),
432             });
433
434             int i = 3; // ArraySubType, SizeParamIndex, SizeConst
435             if (marshalAs.MarshalType != null) i++;
436             if (marshalAs.MarshalTypeRef != null) i++;
437             if (marshalAs.MarshalCookie != null) i++;
438             i++; // IidParameterIndex
439             i++; // SafeArraySubType
440             if (marshalAs.SafeArrayUserDefinedSubType != null) i++;
441             CustomAttributeNamedArgument[] namedArgs = new CustomAttributeNamedArgument[i];
442
443             // For compatibility with previous runtimes, we always include the following 5 attributes, regardless
444             // of if they apply to the UnmanagedType being marshaled or not.
445             i = 0;
446             namedArgs[i++] = new CustomAttributeNamedArgument(type.GetField("ArraySubType"), marshalAs.ArraySubType);
447             namedArgs[i++] = new CustomAttributeNamedArgument(type.GetField("SizeParamIndex"), marshalAs.SizeParamIndex);
448             namedArgs[i++] = new CustomAttributeNamedArgument(type.GetField("SizeConst"), marshalAs.SizeConst);
449             namedArgs[i++] = new CustomAttributeNamedArgument(type.GetField("IidParameterIndex"), marshalAs.IidParameterIndex);
450             namedArgs[i++] = new CustomAttributeNamedArgument(type.GetField("SafeArraySubType"), marshalAs.SafeArraySubType);
451             if (marshalAs.MarshalType != null)
452                 namedArgs[i++] = new CustomAttributeNamedArgument(type.GetField("MarshalType"), marshalAs.MarshalType);
453             if (marshalAs.MarshalTypeRef != null)
454                 namedArgs[i++] = new CustomAttributeNamedArgument(type.GetField("MarshalTypeRef"), marshalAs.MarshalTypeRef);
455             if (marshalAs.MarshalCookie != null)
456                 namedArgs[i++] = new CustomAttributeNamedArgument(type.GetField("MarshalCookie"), marshalAs.MarshalCookie);
457             if (marshalAs.SafeArrayUserDefinedSubType != null)
458                 namedArgs[i++] = new CustomAttributeNamedArgument(type.GetField("SafeArrayUserDefinedSubType"), marshalAs.SafeArrayUserDefinedSubType);
459
460             m_namedArgs = Array.AsReadOnly(namedArgs);
461         }
462         private void Init(TypeForwardedToAttribute forwardedTo)
463         {
464             Type type = typeof(TypeForwardedToAttribute);
465
466             Type[] sig = new Type[] { typeof(Type) };
467             m_ctor = type.GetConstructor(BindingFlags.Public | BindingFlags.Instance, null, sig, null);
468
469             CustomAttributeTypedArgument[] typedArgs = new CustomAttributeTypedArgument[1];
470             typedArgs[0] = new CustomAttributeTypedArgument(typeof(Type), forwardedTo.Destination);
471             m_typedCtorArgs = Array.AsReadOnly(typedArgs);
472
473             CustomAttributeNamedArgument[] namedArgs = Array.Empty<CustomAttributeNamedArgument>();
474             m_namedArgs = Array.AsReadOnly(namedArgs);
475         }
476         private void Init(object pca)
477         {
478             m_ctor = pca.GetType().GetConstructors(BindingFlags.Public | BindingFlags.Instance)[0];
479             m_typedCtorArgs = Array.AsReadOnly(Array.Empty<CustomAttributeTypedArgument>());
480             m_namedArgs = Array.AsReadOnly(Array.Empty<CustomAttributeNamedArgument>());
481         }
482         #endregion
483
484         #region Object Override
485         public override string ToString()
486         {
487             string ctorArgs = "";
488             for (int i = 0; i < ConstructorArguments.Count; i++)
489                 ctorArgs += String.Format(CultureInfo.CurrentCulture, i == 0 ? "{0}" : ", {0}", ConstructorArguments[i]);
490
491             string namedArgs = "";
492             for (int i = 0; i < NamedArguments.Count; i++)
493                 namedArgs += String.Format(CultureInfo.CurrentCulture, i == 0 && ctorArgs.Length == 0 ? "{0}" : ", {0}", NamedArguments[i]);
494
495             return String.Format(CultureInfo.CurrentCulture, "[{0}({1}{2})]", Constructor.DeclaringType.FullName, ctorArgs, namedArgs);
496         }
497         public override int GetHashCode()
498         {
499             return base.GetHashCode();
500         }
501         public override bool Equals(object obj)
502         {
503             return obj == (object)this;
504         }
505         #endregion
506
507         #region Public Members
508         public Type AttributeType { get { return Constructor.DeclaringType; } }
509
510         public virtual ConstructorInfo Constructor { get { return m_ctor; } }
511
512         public virtual IList<CustomAttributeTypedArgument> ConstructorArguments
513         {
514             get
515             {
516                 if (m_typedCtorArgs == null)
517                 {
518                     CustomAttributeTypedArgument[] typedCtorArgs = new CustomAttributeTypedArgument[m_ctorParams.Length];
519
520                     for (int i = 0; i < typedCtorArgs.Length; i++)
521                     {
522                         CustomAttributeEncodedArgument encodedArg = m_ctorParams[i].CustomAttributeEncodedArgument;
523
524                         typedCtorArgs[i] = new CustomAttributeTypedArgument(m_scope, m_ctorParams[i].CustomAttributeEncodedArgument);
525                     }
526
527                     m_typedCtorArgs = Array.AsReadOnly(typedCtorArgs);
528                 }
529
530                 return m_typedCtorArgs;
531             }
532         }
533
534         public virtual IList<CustomAttributeNamedArgument> NamedArguments
535         {
536             get
537             {
538                 if (m_namedArgs == null)
539                 {
540                     if (m_namedParams == null)
541                         return null;
542
543                     int cNamedArgs = 0;
544                     for (int i = 0; i < m_namedParams.Length; i++)
545                     {
546                         if (m_namedParams[i].EncodedArgument.CustomAttributeType.EncodedType != CustomAttributeEncoding.Undefined)
547                             cNamedArgs++;
548                     }
549
550                     CustomAttributeNamedArgument[] namedArgs = new CustomAttributeNamedArgument[cNamedArgs];
551
552                     for (int i = 0, j = 0; i < m_namedParams.Length; i++)
553                     {
554                         if (m_namedParams[i].EncodedArgument.CustomAttributeType.EncodedType != CustomAttributeEncoding.Undefined)
555                             namedArgs[j++] = new CustomAttributeNamedArgument(
556                                 m_members[i], new CustomAttributeTypedArgument(m_scope, m_namedParams[i].EncodedArgument));
557                     }
558
559                     m_namedArgs = Array.AsReadOnly(namedArgs);
560                 }
561
562                 return m_namedArgs;
563             }
564         }
565         #endregion
566     }
567
568     public struct CustomAttributeNamedArgument
569     {
570         #region Public Static Members
571         public static bool operator ==(CustomAttributeNamedArgument left, CustomAttributeNamedArgument right)
572         {
573             return left.Equals(right);
574         }
575         public static bool operator !=(CustomAttributeNamedArgument left, CustomAttributeNamedArgument right)
576         {
577             return !left.Equals(right);
578         }
579         #endregion
580
581         #region Private Data Members
582         private MemberInfo m_memberInfo;
583         private CustomAttributeTypedArgument m_value;
584         #endregion
585
586         #region Constructor
587         public CustomAttributeNamedArgument(MemberInfo memberInfo, object value)
588         {
589             if (memberInfo == null)
590                 throw new ArgumentNullException(nameof(memberInfo));
591
592             Type type = null;
593             FieldInfo field = memberInfo as FieldInfo;
594             PropertyInfo property = memberInfo as PropertyInfo;
595
596             if (field != null)
597                 type = field.FieldType;
598             else if (property != null)
599                 type = property.PropertyType;
600             else
601                 throw new ArgumentException(SR.Argument_InvalidMemberForNamedArgument);
602
603             m_memberInfo = memberInfo;
604             m_value = new CustomAttributeTypedArgument(type, value);
605         }
606
607         public CustomAttributeNamedArgument(MemberInfo memberInfo, CustomAttributeTypedArgument typedArgument)
608         {
609             if (memberInfo == null)
610                 throw new ArgumentNullException(nameof(memberInfo));
611
612             m_memberInfo = memberInfo;
613             m_value = typedArgument;
614         }
615         #endregion
616
617         #region Object Override
618         public override string ToString()
619         {
620             if (m_memberInfo == null)
621                 return base.ToString();
622
623             return String.Format(CultureInfo.CurrentCulture, "{0} = {1}", MemberInfo.Name, TypedValue.ToString(ArgumentType != typeof(object)));
624         }
625         public override int GetHashCode()
626         {
627             return base.GetHashCode();
628         }
629         public override bool Equals(object obj)
630         {
631             return obj == (object)this;
632         }
633         #endregion
634
635         #region Internal Members
636         internal Type ArgumentType
637         {
638             get
639             {
640                 return m_memberInfo is FieldInfo ?
641                     ((FieldInfo)m_memberInfo).FieldType :
642                     ((PropertyInfo)m_memberInfo).PropertyType;
643             }
644         }
645         #endregion
646
647         #region Public Members
648         public MemberInfo MemberInfo { get { return m_memberInfo; } }
649         public CustomAttributeTypedArgument TypedValue { get { return m_value; } }
650         public string MemberName { get { return MemberInfo.Name; } }
651         public bool IsField { get { return MemberInfo is FieldInfo; } }
652         #endregion
653
654     }
655
656     public struct CustomAttributeTypedArgument
657     {
658         #region Public Static Members
659         public static bool operator ==(CustomAttributeTypedArgument left, CustomAttributeTypedArgument right)
660         {
661             return left.Equals(right);
662         }
663         public static bool operator !=(CustomAttributeTypedArgument left, CustomAttributeTypedArgument right)
664         {
665             return !left.Equals(right);
666         }
667         #endregion
668
669         #region Private Static Methods
670         private static Type CustomAttributeEncodingToType(CustomAttributeEncoding encodedType)
671         {
672             switch (encodedType)
673             {
674                 case (CustomAttributeEncoding.Enum):
675                     return typeof(Enum);
676
677                 case (CustomAttributeEncoding.Int32):
678                     return typeof(int);
679
680                 case (CustomAttributeEncoding.String):
681                     return typeof(string);
682
683                 case (CustomAttributeEncoding.Type):
684                     return typeof(Type);
685
686                 case (CustomAttributeEncoding.Array):
687                     return typeof(Array);
688
689                 case (CustomAttributeEncoding.Char):
690                     return typeof(char);
691
692                 case (CustomAttributeEncoding.Boolean):
693                     return typeof(bool);
694
695                 case (CustomAttributeEncoding.SByte):
696                     return typeof(sbyte);
697
698                 case (CustomAttributeEncoding.Byte):
699                     return typeof(byte);
700
701                 case (CustomAttributeEncoding.Int16):
702                     return typeof(short);
703
704                 case (CustomAttributeEncoding.UInt16):
705                     return typeof(ushort);
706
707                 case (CustomAttributeEncoding.UInt32):
708                     return typeof(uint);
709
710                 case (CustomAttributeEncoding.Int64):
711                     return typeof(long);
712
713                 case (CustomAttributeEncoding.UInt64):
714                     return typeof(ulong);
715
716                 case (CustomAttributeEncoding.Float):
717                     return typeof(float);
718
719                 case (CustomAttributeEncoding.Double):
720                     return typeof(double);
721
722                 case (CustomAttributeEncoding.Object):
723                     return typeof(object);
724
725                 default:
726                     throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)encodedType), nameof(encodedType));
727             }
728         }
729
730         private static object EncodedValueToRawValue(long val, CustomAttributeEncoding encodedType)
731         {
732             switch (encodedType)
733             {
734                 case CustomAttributeEncoding.Boolean:
735                     return (byte)val != 0;
736
737                 case CustomAttributeEncoding.Char:
738                     return (char)val;
739
740                 case CustomAttributeEncoding.Byte:
741                     return (byte)val;
742
743                 case CustomAttributeEncoding.SByte:
744                     return (sbyte)val;
745
746                 case CustomAttributeEncoding.Int16:
747                     return (short)val;
748
749                 case CustomAttributeEncoding.UInt16:
750                     return (ushort)val;
751
752                 case CustomAttributeEncoding.Int32:
753                     return (int)val;
754
755                 case CustomAttributeEncoding.UInt32:
756                     return (uint)val;
757
758                 case CustomAttributeEncoding.Int64:
759                     return (long)val;
760
761                 case CustomAttributeEncoding.UInt64:
762                     return (ulong)val;
763
764                 case CustomAttributeEncoding.Float:
765                     unsafe { return *(float*)&val; }
766
767                 case CustomAttributeEncoding.Double:
768                     unsafe { return *(double*)&val; }
769
770                 default:
771                     throw new ArgumentException(SR.Format(SR.Arg_EnumIllegalVal, (int)val), nameof(val));
772             }
773         }
774         private static RuntimeType ResolveType(RuntimeModule scope, string typeName)
775         {
776             RuntimeType type = RuntimeTypeHandle.GetTypeByNameUsingCARules(typeName, scope);
777
778             if (type == null)
779                 throw new InvalidOperationException(
780                     String.Format(CultureInfo.CurrentUICulture, SR.Arg_CATypeResolutionFailed, typeName));
781
782             return type;
783         }
784         #endregion
785
786         #region Private Data Members
787         private object m_value;
788         private Type m_argumentType;
789         #endregion
790
791         #region Constructor
792         public CustomAttributeTypedArgument(Type argumentType, object value)
793         {
794             // value can be null.
795             if (argumentType == null)
796                 throw new ArgumentNullException(nameof(argumentType));
797
798             m_value = (value == null) ? null : CanonicalizeValue(value);
799             m_argumentType = argumentType;
800         }
801
802         public CustomAttributeTypedArgument(object value)
803         {
804             // value cannot be null.
805             if (value == null)
806                 throw new ArgumentNullException(nameof(value));
807
808             m_value = CanonicalizeValue(value);
809             m_argumentType = value.GetType();
810         }
811
812         private static object CanonicalizeValue(object value)
813         {
814             Debug.Assert(value != null);
815
816             if (value.GetType().IsEnum)
817             {
818                 return ((Enum)value).GetValue();
819             }
820             return value;
821         }
822
823         internal CustomAttributeTypedArgument(RuntimeModule scope, CustomAttributeEncodedArgument encodedArg)
824         {
825             CustomAttributeEncoding encodedType = encodedArg.CustomAttributeType.EncodedType;
826
827             if (encodedType == CustomAttributeEncoding.Undefined)
828                 throw new ArgumentException(null, nameof(encodedArg));
829
830             else if (encodedType == CustomAttributeEncoding.Enum)
831             {
832                 m_argumentType = ResolveType(scope, encodedArg.CustomAttributeType.EnumName);
833                 m_value = EncodedValueToRawValue(encodedArg.PrimitiveValue, encodedArg.CustomAttributeType.EncodedEnumType);
834             }
835             else if (encodedType == CustomAttributeEncoding.String)
836             {
837                 m_argumentType = typeof(string);
838                 m_value = encodedArg.StringValue;
839             }
840             else if (encodedType == CustomAttributeEncoding.Type)
841             {
842                 m_argumentType = typeof(Type);
843
844                 m_value = null;
845
846                 if (encodedArg.StringValue != null)
847                     m_value = ResolveType(scope, encodedArg.StringValue);
848             }
849             else if (encodedType == CustomAttributeEncoding.Array)
850             {
851                 encodedType = encodedArg.CustomAttributeType.EncodedArrayType;
852                 Type elementType;
853
854                 if (encodedType == CustomAttributeEncoding.Enum)
855                 {
856                     elementType = ResolveType(scope, encodedArg.CustomAttributeType.EnumName);
857                 }
858                 else
859                 {
860                     elementType = CustomAttributeEncodingToType(encodedType);
861                 }
862
863                 m_argumentType = elementType.MakeArrayType();
864
865                 if (encodedArg.ArrayValue == null)
866                 {
867                     m_value = null;
868                 }
869                 else
870                 {
871                     CustomAttributeTypedArgument[] arrayValue = new CustomAttributeTypedArgument[encodedArg.ArrayValue.Length];
872                     for (int i = 0; i < arrayValue.Length; i++)
873                         arrayValue[i] = new CustomAttributeTypedArgument(scope, encodedArg.ArrayValue[i]);
874
875                     m_value = Array.AsReadOnly(arrayValue);
876                 }
877             }
878             else
879             {
880                 m_argumentType = CustomAttributeEncodingToType(encodedType);
881                 m_value = EncodedValueToRawValue(encodedArg.PrimitiveValue, encodedType);
882             }
883         }
884         #endregion
885
886         #region Object Overrides
887         public override string ToString() { return ToString(false); }
888
889         internal string ToString(bool typed)
890         {
891             if (m_argumentType == null)
892                 return base.ToString();
893
894             if (ArgumentType.IsEnum)
895                 return String.Format(CultureInfo.CurrentCulture, typed ? "{0}" : "({1}){0}", Value, ArgumentType.FullName);
896
897             else if (Value == null)
898                 return String.Format(CultureInfo.CurrentCulture, typed ? "null" : "({0})null", ArgumentType.Name);
899
900             else if (ArgumentType == typeof(string))
901                 return String.Format(CultureInfo.CurrentCulture, "\"{0}\"", Value);
902
903             else if (ArgumentType == typeof(char))
904                 return String.Format(CultureInfo.CurrentCulture, "'{0}'", Value);
905
906             else if (ArgumentType == typeof(Type))
907                 return String.Format(CultureInfo.CurrentCulture, "typeof({0})", ((Type)Value).FullName);
908
909             else if (ArgumentType.IsArray)
910             {
911                 string result = null;
912                 IList<CustomAttributeTypedArgument> array = Value as IList<CustomAttributeTypedArgument>;
913
914                 Type elementType = ArgumentType.GetElementType();
915                 result = String.Format(CultureInfo.CurrentCulture, @"new {0}[{1}] {{ ", elementType.IsEnum ? elementType.FullName : elementType.Name, array.Count);
916
917                 for (int i = 0; i < array.Count; i++)
918                     result += String.Format(CultureInfo.CurrentCulture, i == 0 ? "{0}" : ", {0}", array[i].ToString(elementType != typeof(object)));
919
920                 return result += " }";
921             }
922
923             return String.Format(CultureInfo.CurrentCulture, typed ? "{0}" : "({1}){0}", Value, ArgumentType.Name);
924         }
925
926         public override int GetHashCode()
927         {
928             return base.GetHashCode();
929         }
930         public override bool Equals(object obj)
931         {
932             return obj == (object)this;
933         }
934         #endregion
935
936         #region Public Members
937         public Type ArgumentType
938         {
939             get
940             {
941                 return m_argumentType;
942             }
943         }
944         public object Value
945         {
946             get
947             {
948                 return m_value;
949             }
950         }
951         #endregion
952     }
953
954     internal struct CustomAttributeRecord
955     {
956         internal ConstArray blob;
957         internal MetadataToken tkCtor;
958     }
959
960     internal enum CustomAttributeEncoding : int
961     {
962         Undefined = 0,
963         Boolean = CorElementType.Boolean,
964         Char = CorElementType.Char,
965         SByte = CorElementType.I1,
966         Byte = CorElementType.U1,
967         Int16 = CorElementType.I2,
968         UInt16 = CorElementType.U2,
969         Int32 = CorElementType.I4,
970         UInt32 = CorElementType.U4,
971         Int64 = CorElementType.I8,
972         UInt64 = CorElementType.U8,
973         Float = CorElementType.R4,
974         Double = CorElementType.R8,
975         String = CorElementType.String,
976         Array = CorElementType.SzArray,
977         Type = 0x50,
978         Object = 0x51,
979         Field = 0x53,
980         Property = 0x54,
981         Enum = 0x55
982     }
983
984     [StructLayout(LayoutKind.Auto)]
985     internal struct CustomAttributeEncodedArgument
986     {
987         #region Parser
988         [MethodImplAttribute(MethodImplOptions.InternalCall)]
989         private static extern void ParseAttributeArguments(
990             IntPtr pCa,
991             int cCa,
992             ref CustomAttributeCtorParameter[] CustomAttributeCtorParameters,
993             ref CustomAttributeNamedParameter[] CustomAttributeTypedArgument,
994             RuntimeAssembly assembly);
995
996         internal static void ParseAttributeArguments(ConstArray attributeBlob,
997             ref CustomAttributeCtorParameter[] customAttributeCtorParameters,
998             ref CustomAttributeNamedParameter[] customAttributeNamedParameters,
999             RuntimeModule customAttributeModule)
1000         {
1001             if (customAttributeModule == null)
1002                 throw new ArgumentNullException(nameof(customAttributeModule));
1003
1004             Debug.Assert(customAttributeCtorParameters != null);
1005             Debug.Assert(customAttributeNamedParameters != null);
1006
1007             if (customAttributeCtorParameters.Length != 0 || customAttributeNamedParameters.Length != 0)
1008             {
1009                 unsafe
1010                 {
1011                     ParseAttributeArguments(
1012                         attributeBlob.Signature,
1013                         (int)attributeBlob.Length,
1014                         ref customAttributeCtorParameters,
1015                         ref customAttributeNamedParameters,
1016                         (RuntimeAssembly)customAttributeModule.Assembly);
1017                 }
1018             }
1019         }
1020         #endregion
1021
1022         #region Private Data Members
1023         private long m_primitiveValue;
1024         private CustomAttributeEncodedArgument[] m_arrayValue;
1025         private string m_stringValue;
1026         private CustomAttributeType m_type;
1027         #endregion
1028
1029         #region Public Members
1030         public CustomAttributeType CustomAttributeType { get { return m_type; } }
1031         public long PrimitiveValue { get { return m_primitiveValue; } }
1032         public CustomAttributeEncodedArgument[] ArrayValue { get { return m_arrayValue; } }
1033         public string StringValue { get { return m_stringValue; } }
1034         #endregion
1035     }
1036
1037     [StructLayout(LayoutKind.Auto)]
1038     internal struct CustomAttributeNamedParameter
1039     {
1040         #region Private Data Members
1041         private string m_argumentName;
1042         private CustomAttributeEncoding m_fieldOrProperty;
1043         private CustomAttributeEncoding m_padding;
1044         private CustomAttributeType m_type;
1045         private CustomAttributeEncodedArgument m_encodedArgument;
1046         #endregion
1047
1048         #region Constructor
1049         public CustomAttributeNamedParameter(string argumentName, CustomAttributeEncoding fieldOrProperty, CustomAttributeType type)
1050         {
1051             if (argumentName == null)
1052                 throw new ArgumentNullException(nameof(argumentName));
1053
1054             m_argumentName = argumentName;
1055             m_fieldOrProperty = fieldOrProperty;
1056             m_padding = fieldOrProperty;
1057             m_type = type;
1058             m_encodedArgument = new CustomAttributeEncodedArgument();
1059         }
1060         #endregion
1061
1062         #region Public Members
1063         public CustomAttributeEncodedArgument EncodedArgument { get { return m_encodedArgument; } }
1064         #endregion
1065     }
1066
1067     [StructLayout(LayoutKind.Auto)]
1068     internal struct CustomAttributeCtorParameter
1069     {
1070         #region Private Data Members
1071         private CustomAttributeType m_type;
1072         private CustomAttributeEncodedArgument m_encodedArgument;
1073         #endregion
1074
1075         #region Constructor
1076         public CustomAttributeCtorParameter(CustomAttributeType type)
1077         {
1078             m_type = type;
1079             m_encodedArgument = new CustomAttributeEncodedArgument();
1080         }
1081         #endregion
1082
1083         #region Public Members
1084         public CustomAttributeEncodedArgument CustomAttributeEncodedArgument { get { return m_encodedArgument; } }
1085         #endregion
1086     }
1087
1088     [StructLayout(LayoutKind.Auto)]
1089     internal struct CustomAttributeType
1090     {
1091         #region Private Data Members
1092         /// The most complicated type is an enum[] in which case...
1093         private string m_enumName; // ...enum name
1094         private CustomAttributeEncoding m_encodedType; // ...array
1095         private CustomAttributeEncoding m_encodedEnumType; // ...enum
1096         private CustomAttributeEncoding m_encodedArrayType; // ...enum type
1097         private CustomAttributeEncoding m_padding;
1098         #endregion
1099
1100         #region Constructor
1101         public CustomAttributeType(CustomAttributeEncoding encodedType, CustomAttributeEncoding encodedArrayType,
1102             CustomAttributeEncoding encodedEnumType, string enumName)
1103         {
1104             m_encodedType = encodedType;
1105             m_encodedArrayType = encodedArrayType;
1106             m_encodedEnumType = encodedEnumType;
1107             m_enumName = enumName;
1108             m_padding = m_encodedType;
1109         }
1110         #endregion
1111
1112         #region Public Members
1113         public CustomAttributeEncoding EncodedType { get { return m_encodedType; } }
1114         public CustomAttributeEncoding EncodedEnumType { get { return m_encodedEnumType; } }
1115         public CustomAttributeEncoding EncodedArrayType { get { return m_encodedArrayType; } }
1116         public string EnumName { get { return m_enumName; } }
1117         #endregion
1118     }
1119
1120     internal unsafe static class CustomAttribute
1121     {
1122         #region Private Data Members
1123         private static RuntimeType Type_RuntimeType = (RuntimeType)typeof(RuntimeType);
1124         private static RuntimeType Type_Type = (RuntimeType)typeof(Type);
1125         #endregion
1126
1127         #region Internal Static Members
1128         internal static bool IsDefined(RuntimeType type, RuntimeType caType, bool inherit)
1129         {
1130             Debug.Assert(type != null);
1131
1132             if (type.GetElementType() != null)
1133                 return false;
1134
1135             if (PseudoCustomAttribute.IsDefined(type, caType))
1136                 return true;
1137
1138             if (IsCustomAttributeDefined(type.GetRuntimeModule(), type.MetadataToken, caType))
1139                 return true;
1140
1141             if (!inherit)
1142                 return false;
1143
1144             type = type.BaseType as RuntimeType;
1145
1146             while (type != null)
1147             {
1148                 if (IsCustomAttributeDefined(type.GetRuntimeModule(), type.MetadataToken, caType, 0, inherit))
1149                     return true;
1150
1151                 type = type.BaseType as RuntimeType;
1152             }
1153
1154             return false;
1155         }
1156
1157         internal static bool IsDefined(RuntimeMethodInfo method, RuntimeType caType, bool inherit)
1158         {
1159             Debug.Assert(method != null);
1160             Debug.Assert(caType != null);
1161
1162             if (PseudoCustomAttribute.IsDefined(method, caType))
1163                 return true;
1164
1165             if (IsCustomAttributeDefined(method.GetRuntimeModule(), method.MetadataToken, caType))
1166                 return true;
1167
1168             if (!inherit)
1169                 return false;
1170
1171             method = method.GetParentDefinition();
1172
1173             while (method != null)
1174             {
1175                 if (IsCustomAttributeDefined(method.GetRuntimeModule(), method.MetadataToken, caType, 0, inherit))
1176                     return true;
1177
1178                 method = method.GetParentDefinition();
1179             }
1180
1181             return false;
1182         }
1183
1184         internal static bool IsDefined(RuntimeConstructorInfo ctor, RuntimeType caType)
1185         {
1186             Debug.Assert(ctor != null);
1187             Debug.Assert(caType != null);
1188
1189             if (PseudoCustomAttribute.IsDefined(ctor, caType))
1190                 return true;
1191
1192             return IsCustomAttributeDefined(ctor.GetRuntimeModule(), ctor.MetadataToken, caType);
1193         }
1194
1195         internal static bool IsDefined(RuntimePropertyInfo property, RuntimeType caType)
1196         {
1197             Debug.Assert(property != null);
1198             Debug.Assert(caType != null);
1199
1200             if (PseudoCustomAttribute.IsDefined(property, caType))
1201                 return true;
1202
1203             return IsCustomAttributeDefined(property.GetRuntimeModule(), property.MetadataToken, caType);
1204         }
1205
1206         internal static bool IsDefined(RuntimeEventInfo e, RuntimeType caType)
1207         {
1208             Debug.Assert(e != null);
1209             Debug.Assert(caType != null);
1210
1211             if (PseudoCustomAttribute.IsDefined(e, caType))
1212                 return true;
1213
1214             return IsCustomAttributeDefined(e.GetRuntimeModule(), e.MetadataToken, caType);
1215         }
1216
1217         internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType caType)
1218         {
1219             Debug.Assert(field != null);
1220             Debug.Assert(caType != null);
1221
1222             if (PseudoCustomAttribute.IsDefined(field, caType))
1223                 return true;
1224
1225             return IsCustomAttributeDefined(field.GetRuntimeModule(), field.MetadataToken, caType);
1226         }
1227
1228         internal static bool IsDefined(RuntimeParameterInfo parameter, RuntimeType caType)
1229         {
1230             Debug.Assert(parameter != null);
1231             Debug.Assert(caType != null);
1232
1233             if (PseudoCustomAttribute.IsDefined(parameter, caType))
1234                 return true;
1235
1236             return IsCustomAttributeDefined(parameter.GetRuntimeModule(), parameter.MetadataToken, caType);
1237         }
1238
1239         internal static bool IsDefined(RuntimeAssembly assembly, RuntimeType caType)
1240         {
1241             Debug.Assert(assembly != null);
1242             Debug.Assert(caType != null);
1243
1244             if (PseudoCustomAttribute.IsDefined(assembly, caType))
1245                 return true;
1246
1247             return IsCustomAttributeDefined(assembly.ManifestModule as RuntimeModule, RuntimeAssembly.GetToken(assembly.GetNativeHandle()), caType);
1248         }
1249
1250         internal static bool IsDefined(RuntimeModule module, RuntimeType caType)
1251         {
1252             Debug.Assert(module != null);
1253             Debug.Assert(caType != null);
1254
1255             if (PseudoCustomAttribute.IsDefined(module, caType))
1256                 return true;
1257
1258             return IsCustomAttributeDefined(module, module.MetadataToken, caType);
1259         }
1260
1261         internal static Object[] GetCustomAttributes(RuntimeType type, RuntimeType caType, bool inherit)
1262         {
1263             Debug.Assert(type != null);
1264             Debug.Assert(caType != null);
1265
1266             if (type.GetElementType() != null)
1267                 return (caType.IsValueType) ? Array.Empty<Object>() : CreateAttributeArrayHelper(caType, 0);
1268
1269             if (type.IsGenericType && !type.IsGenericTypeDefinition)
1270                 type = type.GetGenericTypeDefinition() as RuntimeType;
1271
1272             int pcaCount = 0;
1273             Attribute[] pca = PseudoCustomAttribute.GetCustomAttributes(type, caType, out pcaCount);
1274
1275             // if we are asked to go up the hierarchy chain we have to do it now and regardless of the
1276             // attribute usage for the specific attribute because a derived attribute may override the usage...           
1277             // ... however if the attribute is sealed we can rely on the attribute usage
1278             if (!inherit || (caType.IsSealed && !CustomAttribute.GetAttributeUsage(caType).Inherited))
1279             {
1280                 object[] attributes = GetCustomAttributes(type.GetRuntimeModule(), type.MetadataToken, pcaCount, caType);
1281                 if (pcaCount > 0) Array.Copy(pca, 0, attributes, attributes.Length - pcaCount, pcaCount);
1282                 return attributes;
1283             }
1284
1285             List<object> result = new List<object>();
1286             bool mustBeInheritable = false;
1287             bool useObjectArray = (caType == null || caType.IsValueType || caType.ContainsGenericParameters);
1288             Type arrayType = useObjectArray ? typeof(object) : caType;
1289
1290             while (pcaCount > 0)
1291                 result.Add(pca[--pcaCount]);
1292
1293             while (type != (RuntimeType)typeof(object) && type != null)
1294             {
1295                 object[] attributes = GetCustomAttributes(type.GetRuntimeModule(), type.MetadataToken, 0, caType, mustBeInheritable, result);
1296                 mustBeInheritable = true;
1297                 for (int i = 0; i < attributes.Length; i++)
1298                     result.Add(attributes[i]);
1299
1300                 type = type.BaseType as RuntimeType;
1301             }
1302
1303             object[] typedResult = CreateAttributeArrayHelper(arrayType, result.Count);
1304             Array.Copy(result.ToArray(), 0, typedResult, 0, result.Count);
1305             return typedResult;
1306         }
1307
1308         internal static Object[] GetCustomAttributes(RuntimeMethodInfo method, RuntimeType caType, bool inherit)
1309         {
1310             Debug.Assert(method != null);
1311             Debug.Assert(caType != null);
1312
1313             if (method.IsGenericMethod && !method.IsGenericMethodDefinition)
1314                 method = method.GetGenericMethodDefinition() as RuntimeMethodInfo;
1315
1316             int pcaCount = 0;
1317             Attribute[] pca = PseudoCustomAttribute.GetCustomAttributes(method, caType, out pcaCount);
1318
1319             // if we are asked to go up the hierarchy chain we have to do it now and regardless of the
1320             // attribute usage for the specific attribute because a derived attribute may override the usage...           
1321             // ... however if the attribute is sealed we can rely on the attribute usage
1322             if (!inherit || (caType.IsSealed && !CustomAttribute.GetAttributeUsage(caType).Inherited))
1323             {
1324                 object[] attributes = GetCustomAttributes(method.GetRuntimeModule(), method.MetadataToken, pcaCount, caType);
1325                 if (pcaCount > 0) Array.Copy(pca, 0, attributes, attributes.Length - pcaCount, pcaCount);
1326                 return attributes;
1327             }
1328
1329             List<object> result = new List<object>();
1330             bool mustBeInheritable = false;
1331             bool useObjectArray = (caType == null || caType.IsValueType || caType.ContainsGenericParameters);
1332             Type arrayType = useObjectArray ? typeof(object) : caType;
1333
1334             while (pcaCount > 0)
1335                 result.Add(pca[--pcaCount]);
1336
1337             while (method != null)
1338             {
1339                 object[] attributes = GetCustomAttributes(method.GetRuntimeModule(), method.MetadataToken, 0, caType, mustBeInheritable, result);
1340                 mustBeInheritable = true;
1341                 for (int i = 0; i < attributes.Length; i++)
1342                     result.Add(attributes[i]);
1343
1344                 method = method.GetParentDefinition();
1345             }
1346
1347             object[] typedResult = CreateAttributeArrayHelper(arrayType, result.Count);
1348             Array.Copy(result.ToArray(), 0, typedResult, 0, result.Count);
1349             return typedResult;
1350         }
1351
1352         internal static Object[] GetCustomAttributes(RuntimeConstructorInfo ctor, RuntimeType caType)
1353         {
1354             Debug.Assert(ctor != null);
1355             Debug.Assert(caType != null);
1356
1357             int pcaCount = 0;
1358             Attribute[] pca = PseudoCustomAttribute.GetCustomAttributes(ctor, caType, out pcaCount);
1359             object[] attributes = GetCustomAttributes(ctor.GetRuntimeModule(), ctor.MetadataToken, pcaCount, caType);
1360             if (pcaCount > 0) Array.Copy(pca, 0, attributes, attributes.Length - pcaCount, pcaCount);
1361             return attributes;
1362         }
1363
1364         internal static Object[] GetCustomAttributes(RuntimePropertyInfo property, RuntimeType caType)
1365         {
1366             Debug.Assert(property != null);
1367             Debug.Assert(caType != null);
1368
1369             int pcaCount = 0;
1370             Attribute[] pca = PseudoCustomAttribute.GetCustomAttributes(property, caType, out pcaCount);
1371
1372             object[] attributes = GetCustomAttributes(property.GetRuntimeModule(), property.MetadataToken, pcaCount, caType);
1373             if (pcaCount > 0) Array.Copy(pca, 0, attributes, attributes.Length - pcaCount, pcaCount);
1374             return attributes;
1375         }
1376
1377         internal static Object[] GetCustomAttributes(RuntimeEventInfo e, RuntimeType caType)
1378         {
1379             Debug.Assert(e != null);
1380             Debug.Assert(caType != null);
1381
1382             int pcaCount = 0;
1383             Attribute[] pca = PseudoCustomAttribute.GetCustomAttributes(e, caType, out pcaCount);
1384             object[] attributes = GetCustomAttributes(e.GetRuntimeModule(), e.MetadataToken, pcaCount, caType);
1385             if (pcaCount > 0) Array.Copy(pca, 0, attributes, attributes.Length - pcaCount, pcaCount);
1386             return attributes;
1387         }
1388
1389         internal static Object[] GetCustomAttributes(RuntimeFieldInfo field, RuntimeType caType)
1390         {
1391             Debug.Assert(field != null);
1392             Debug.Assert(caType != null);
1393
1394             int pcaCount = 0;
1395             Attribute[] pca = PseudoCustomAttribute.GetCustomAttributes(field, caType, out pcaCount);
1396             object[] attributes = GetCustomAttributes(field.GetRuntimeModule(), field.MetadataToken, pcaCount, caType);
1397             if (pcaCount > 0) Array.Copy(pca, 0, attributes, attributes.Length - pcaCount, pcaCount);
1398             return attributes;
1399         }
1400
1401         internal static Object[] GetCustomAttributes(RuntimeParameterInfo parameter, RuntimeType caType)
1402         {
1403             Debug.Assert(parameter != null);
1404             Debug.Assert(caType != null);
1405
1406             int pcaCount = 0;
1407             Attribute[] pca = PseudoCustomAttribute.GetCustomAttributes(parameter, caType, out pcaCount);
1408             object[] attributes = GetCustomAttributes(parameter.GetRuntimeModule(), parameter.MetadataToken, pcaCount, caType);
1409             if (pcaCount > 0) Array.Copy(pca, 0, attributes, attributes.Length - pcaCount, pcaCount);
1410             return attributes;
1411         }
1412
1413         internal static Object[] GetCustomAttributes(RuntimeAssembly assembly, RuntimeType caType)
1414         {
1415             Debug.Assert(assembly != null);
1416             Debug.Assert(caType != null);
1417
1418             int pcaCount = 0;
1419             Attribute[] pca = PseudoCustomAttribute.GetCustomAttributes(assembly, caType, out pcaCount);
1420             int assemblyToken = RuntimeAssembly.GetToken(assembly.GetNativeHandle());
1421             object[] attributes = GetCustomAttributes(assembly.ManifestModule as RuntimeModule, assemblyToken, pcaCount, caType);
1422             if (pcaCount > 0) Array.Copy(pca, 0, attributes, attributes.Length - pcaCount, pcaCount);
1423             return attributes;
1424         }
1425
1426         internal static Object[] GetCustomAttributes(RuntimeModule module, RuntimeType caType)
1427         {
1428             Debug.Assert(module != null);
1429             Debug.Assert(caType != null);
1430
1431             int pcaCount = 0;
1432             Attribute[] pca = PseudoCustomAttribute.GetCustomAttributes(module, caType, out pcaCount);
1433             object[] attributes = GetCustomAttributes(module, module.MetadataToken, pcaCount, caType);
1434             if (pcaCount > 0) Array.Copy(pca, 0, attributes, attributes.Length - pcaCount, pcaCount);
1435             return attributes;
1436         }
1437
1438         internal static bool IsAttributeDefined(RuntimeModule decoratedModule, int decoratedMetadataToken, int attributeCtorToken)
1439         {
1440             return IsCustomAttributeDefined(decoratedModule, decoratedMetadataToken, null, attributeCtorToken, false);
1441         }
1442
1443         private static bool IsCustomAttributeDefined(
1444             RuntimeModule decoratedModule, int decoratedMetadataToken, RuntimeType attributeFilterType)
1445         {
1446             return IsCustomAttributeDefined(decoratedModule, decoratedMetadataToken, attributeFilterType, 0, false);
1447         }
1448
1449         private static bool IsCustomAttributeDefined(
1450             RuntimeModule decoratedModule, int decoratedMetadataToken, RuntimeType attributeFilterType, int attributeCtorToken, bool mustBeInheritable)
1451         {
1452             if (decoratedModule.Assembly.ReflectionOnly)
1453                 throw new InvalidOperationException(SR.Arg_ReflectionOnlyCA);
1454
1455             CustomAttributeRecord[] car = CustomAttributeData.GetCustomAttributeRecords(decoratedModule, decoratedMetadataToken);
1456
1457             if (attributeFilterType != null)
1458             {
1459                 Debug.Assert(attributeCtorToken == 0);
1460
1461                 MetadataImport scope = decoratedModule.MetadataImport;
1462                 RuntimeType attributeType;
1463                 IRuntimeMethodInfo ctor;
1464                 bool ctorHasParameters, isVarArg;
1465
1466                 // Optimization for the case where attributes decorate entities in the same assembly in which case 
1467                 // we can cache the successful APTCA check between the decorated and the declared assembly.
1468                 Assembly lastAptcaOkAssembly = null;
1469
1470                 for (int i = 0; i < car.Length; i++)
1471                 {
1472                     CustomAttributeRecord caRecord = car[i];
1473
1474                     if (FilterCustomAttributeRecord(caRecord, scope, ref lastAptcaOkAssembly,
1475                         decoratedModule, decoratedMetadataToken, attributeFilterType, mustBeInheritable, null, null,
1476                         out attributeType, out ctor, out ctorHasParameters, out isVarArg))
1477                         return true;
1478                 }
1479             }
1480             else
1481             {
1482                 Debug.Assert(attributeFilterType == null);
1483                 Debug.Assert(!MetadataToken.IsNullToken(attributeCtorToken));
1484
1485                 for (int i = 0; i < car.Length; i++)
1486                 {
1487                     CustomAttributeRecord caRecord = car[i];
1488
1489                     if (caRecord.tkCtor == attributeCtorToken)
1490                         return true;
1491                 }
1492             }
1493
1494             return false;
1495         }
1496
1497         private unsafe static object[] GetCustomAttributes(
1498             RuntimeModule decoratedModule, int decoratedMetadataToken, int pcaCount, RuntimeType attributeFilterType)
1499         {
1500             return GetCustomAttributes(decoratedModule, decoratedMetadataToken, pcaCount, attributeFilterType, false, null);
1501         }
1502
1503         private unsafe static object[] GetCustomAttributes(
1504             RuntimeModule decoratedModule, int decoratedMetadataToken, int pcaCount,
1505             RuntimeType attributeFilterType, bool mustBeInheritable, IList derivedAttributes)
1506         {
1507             if (decoratedModule.Assembly.ReflectionOnly)
1508                 throw new InvalidOperationException(SR.Arg_ReflectionOnlyCA);
1509
1510             MetadataImport scope = decoratedModule.MetadataImport;
1511             CustomAttributeRecord[] car = CustomAttributeData.GetCustomAttributeRecords(decoratedModule, decoratedMetadataToken);
1512
1513             bool useObjectArray = (attributeFilterType == null || attributeFilterType.IsValueType || attributeFilterType.ContainsGenericParameters);
1514             Type arrayType = useObjectArray ? typeof(object) : attributeFilterType;
1515
1516             if (attributeFilterType == null && car.Length == 0)
1517                 return CreateAttributeArrayHelper(arrayType, 0);
1518
1519             object[] attributes = CreateAttributeArrayHelper(arrayType, car.Length);
1520             int cAttributes = 0;
1521
1522             // Optimization for the case where attributes decorate entities in the same assembly in which case 
1523             // we can cache the successful APTCA check between the decorated and the declared assembly.
1524             Assembly lastAptcaOkAssembly = null;
1525
1526             for (int i = 0; i < car.Length; i++)
1527             {
1528                 object attribute = null;
1529                 CustomAttributeRecord caRecord = car[i];
1530
1531                 IRuntimeMethodInfo ctor = null;
1532                 RuntimeType attributeType = null;
1533                 bool ctorHasParameters, isVarArg;
1534                 int cNamedArgs = 0;
1535
1536                 IntPtr blobStart = caRecord.blob.Signature;
1537                 IntPtr blobEnd = (IntPtr)((byte*)blobStart + caRecord.blob.Length);
1538                 int blobLen = (int)((byte*)blobEnd - (byte*)blobStart);
1539
1540                 if (!FilterCustomAttributeRecord(caRecord, scope, ref lastAptcaOkAssembly,
1541                                                  decoratedModule, decoratedMetadataToken, attributeFilterType, mustBeInheritable,
1542                                                  attributes, derivedAttributes,
1543                                                  out attributeType, out ctor, out ctorHasParameters, out isVarArg))
1544                     continue;
1545
1546                 // Leverage RuntimeConstructorInfo standard .ctor verfication
1547                 RuntimeConstructorInfo.CheckCanCreateInstance(attributeType, isVarArg);
1548
1549                 // Create custom attribute object
1550                 if (ctorHasParameters)
1551                 {
1552                     attribute = CreateCaObject(decoratedModule, ctor, ref blobStart, blobEnd, out cNamedArgs);
1553                 }
1554                 else
1555                 {
1556                     attribute = RuntimeTypeHandle.CreateCaInstance(attributeType, ctor);
1557
1558                     // It is allowed by the ECMA spec to have an empty signature blob
1559                     if (blobLen == 0)
1560                         cNamedArgs = 0;
1561                     else
1562                     {
1563                         // Metadata is always written in little-endian format. Must account for this on
1564                         // big-endian platforms.
1565 #if BIGENDIAN
1566                         const int CustomAttributeVersion = 0x0100;
1567 #else
1568                         const int CustomAttributeVersion = 0x0001;
1569 #endif
1570                         if (Marshal.ReadInt16(blobStart) != CustomAttributeVersion)
1571                             throw new CustomAttributeFormatException();
1572                         blobStart = (IntPtr)((byte*)blobStart + 2); // skip version prefix
1573
1574                         cNamedArgs = Marshal.ReadInt16(blobStart);
1575                         blobStart = (IntPtr)((byte*)blobStart + 2); // skip namedArgs count
1576 #if BIGENDIAN
1577                         cNamedArgs = ((cNamedArgs & 0xff00) >> 8) | ((cNamedArgs & 0x00ff) << 8);
1578 #endif
1579                     }
1580                 }
1581
1582                 for (int j = 0; j < cNamedArgs; j++)
1583                 {
1584                     #region // Initialize named properties and fields
1585                     string name;
1586                     bool isProperty;
1587                     RuntimeType type;
1588                     object value;
1589
1590                     IntPtr blobItr = caRecord.blob.Signature;
1591
1592                     GetPropertyOrFieldData(decoratedModule, ref blobStart, blobEnd, out name, out isProperty, out type, out value);
1593
1594                     try
1595                     {
1596                         if (isProperty)
1597                         {
1598                             #region // Initialize property
1599                             if (type == null && value != null)
1600                             {
1601                                 type = (RuntimeType)value.GetType();
1602                                 if (type == Type_RuntimeType)
1603                                     type = Type_Type;
1604                             }
1605
1606                             RuntimePropertyInfo property = null;
1607
1608                             if (type == null)
1609                                 property = attributeType.GetProperty(name) as RuntimePropertyInfo;
1610                             else
1611                                 property = attributeType.GetProperty(name, type, Type.EmptyTypes) as RuntimePropertyInfo;
1612
1613                             // Did we get a valid property reference?
1614                             if (property == null)
1615                             {
1616                                 throw new CustomAttributeFormatException(
1617                                     String.Format(CultureInfo.CurrentUICulture, 
1618                                         isProperty ? SR.RFLCT_InvalidPropFail : SR.RFLCT_InvalidFieldFail, name));
1619                             }
1620
1621                             RuntimeMethodInfo setMethod = property.GetSetMethod(true) as RuntimeMethodInfo;
1622
1623                             // Public properties may have non-public setter methods
1624                             if (!setMethod.IsPublic)
1625                                 continue;
1626
1627                             setMethod.UnsafeInvoke(attribute, BindingFlags.Default, null, new object[] { value }, null);
1628                             #endregion
1629                         }
1630                         else
1631                         {
1632                             RtFieldInfo field = attributeType.GetField(name) as RtFieldInfo;
1633
1634                             field.CheckConsistency(attribute);
1635                             field.UnsafeSetValue(attribute, value, BindingFlags.Default, Type.DefaultBinder, null);
1636                         }
1637                     }
1638                     catch (Exception e)
1639                     {
1640                         throw new CustomAttributeFormatException(
1641                             String.Format(CultureInfo.CurrentUICulture,
1642                                 isProperty ? SR.RFLCT_InvalidPropFail : SR.RFLCT_InvalidFieldFail, name), e);
1643                     }
1644                     #endregion
1645                 }
1646
1647                 if (blobStart != blobEnd)
1648                     throw new CustomAttributeFormatException();
1649
1650                 attributes[cAttributes++] = attribute;
1651             }
1652
1653             if (cAttributes == car.Length && pcaCount == 0)
1654                 return attributes;
1655
1656             object[] result = CreateAttributeArrayHelper(arrayType, cAttributes + pcaCount);
1657             Array.Copy(attributes, 0, result, 0, cAttributes);
1658             return result;
1659         }
1660
1661         private unsafe static bool FilterCustomAttributeRecord(
1662             CustomAttributeRecord caRecord,
1663             MetadataImport scope,
1664             ref Assembly lastAptcaOkAssembly,
1665             RuntimeModule decoratedModule,
1666             MetadataToken decoratedToken,
1667             RuntimeType attributeFilterType,
1668             bool mustBeInheritable,
1669             object[] attributes,
1670             IList derivedAttributes,
1671             out RuntimeType attributeType,
1672             out IRuntimeMethodInfo ctor,
1673             out bool ctorHasParameters,
1674             out bool isVarArg)
1675         {
1676             ctor = null;
1677             attributeType = null;
1678             ctorHasParameters = false;
1679             isVarArg = false;
1680
1681             IntPtr blobStart = caRecord.blob.Signature;
1682             IntPtr blobEnd = (IntPtr)((byte*)blobStart + caRecord.blob.Length);
1683
1684             // Resolve attribute type from ctor parent token found in decorated decoratedModule scope
1685             attributeType = decoratedModule.ResolveType(scope.GetParentToken(caRecord.tkCtor), null, null) as RuntimeType;
1686
1687
1688             // Test attribute type against user provided attribute type filter
1689             if (!(attributeFilterType.IsAssignableFrom(attributeType)))
1690                 return false;
1691
1692             // Ensure if attribute type must be inheritable that it is inhertiable
1693             // Ensure that to consider a duplicate attribute type AllowMultiple is true
1694             if (!AttributeUsageCheck(attributeType, mustBeInheritable, attributes, derivedAttributes))
1695                 return false;
1696
1697             // Windows Runtime attributes aren't real types - they exist to be read as metadata only, and as such
1698             // should be filtered out of the GetCustomAttributes path.
1699             if ((attributeType.Attributes & TypeAttributes.WindowsRuntime) == TypeAttributes.WindowsRuntime)
1700             {
1701                 return false;
1702             }
1703
1704             // Resolve the attribute ctor
1705             ConstArray ctorSig = scope.GetMethodSignature(caRecord.tkCtor);
1706             isVarArg = (ctorSig[0] & 0x05) != 0;
1707             ctorHasParameters = ctorSig[1] != 0;
1708
1709             if (ctorHasParameters)
1710             {
1711                 // Resolve method ctor token found in decorated decoratedModule scope
1712                 ctor = ModuleHandle.ResolveMethodHandleInternal(decoratedModule.GetNativeHandle(), caRecord.tkCtor);
1713             }
1714             else
1715             {
1716                 // Resolve method ctor token from decorated decoratedModule scope
1717                 ctor = attributeType.GetTypeHandleInternal().GetDefaultConstructor();
1718
1719                 if (ctor == null && !attributeType.IsValueType)
1720                     throw new MissingMethodException(".ctor");
1721             }
1722
1723             // Visibility checks
1724             MetadataToken tkParent = new MetadataToken();
1725
1726             if (decoratedToken.IsParamDef)
1727             {
1728                 tkParent = new MetadataToken(scope.GetParentToken(decoratedToken));
1729                 tkParent = new MetadataToken(scope.GetParentToken(tkParent));
1730             }
1731             else if (decoratedToken.IsMethodDef || decoratedToken.IsProperty || decoratedToken.IsEvent || decoratedToken.IsFieldDef)
1732             {
1733                 tkParent = new MetadataToken(scope.GetParentToken(decoratedToken));
1734             }
1735             else if (decoratedToken.IsTypeDef)
1736             {
1737                 tkParent = decoratedToken;
1738             }
1739             else if (decoratedToken.IsGenericPar)
1740             {
1741                 tkParent = new MetadataToken(scope.GetParentToken(decoratedToken));
1742
1743                 // decoratedToken is a generic parameter on a method. Get the declaring Type of the method.
1744                 if (tkParent.IsMethodDef)
1745                     tkParent = new MetadataToken(scope.GetParentToken(tkParent));
1746             }
1747             else
1748             {
1749                 // We need to relax this when we add support for other types of decorated tokens.
1750                 Debug.Assert(decoratedToken.IsModule || decoratedToken.IsAssembly,
1751                                 "The decoratedToken must be either an assembly, a module, a type, or a member.");
1752             }
1753
1754             // If the attribute is on a type, member, or parameter we check access against the (declaring) type,
1755             // otherwise we check access against the module.
1756             RuntimeTypeHandle parentTypeHandle = tkParent.IsTypeDef ?
1757                                                     decoratedModule.ModuleHandle.ResolveTypeHandle(tkParent) :
1758                                                     new RuntimeTypeHandle();
1759
1760             return RuntimeMethodHandle.IsCAVisibleFromDecoratedType(attributeType.TypeHandle, ctor, parentTypeHandle, decoratedModule);
1761         }
1762         #endregion
1763
1764         #region Private Static Methods
1765         private static bool AttributeUsageCheck(
1766             RuntimeType attributeType, bool mustBeInheritable, object[] attributes, IList derivedAttributes)
1767         {
1768             AttributeUsageAttribute attributeUsageAttribute = null;
1769
1770             if (mustBeInheritable)
1771             {
1772                 attributeUsageAttribute = CustomAttribute.GetAttributeUsage(attributeType);
1773
1774                 if (!attributeUsageAttribute.Inherited)
1775                     return false;
1776             }
1777
1778             // Legacy: AllowMultiple ignored for none inheritable attributes
1779
1780             if (derivedAttributes == null)
1781                 return true;
1782
1783             for (int i = 0; i < derivedAttributes.Count; i++)
1784             {
1785                 if (derivedAttributes[i].GetType() == attributeType)
1786                 {
1787                     if (attributeUsageAttribute == null)
1788                         attributeUsageAttribute = CustomAttribute.GetAttributeUsage(attributeType);
1789
1790                     return attributeUsageAttribute.AllowMultiple;
1791                 }
1792             }
1793
1794             return true;
1795         }
1796
1797         internal static AttributeUsageAttribute GetAttributeUsage(RuntimeType decoratedAttribute)
1798         {
1799             RuntimeModule decoratedModule = decoratedAttribute.GetRuntimeModule();
1800             MetadataImport scope = decoratedModule.MetadataImport;
1801             CustomAttributeRecord[] car = CustomAttributeData.GetCustomAttributeRecords(decoratedModule, decoratedAttribute.MetadataToken);
1802
1803             AttributeUsageAttribute attributeUsageAttribute = null;
1804
1805             for (int i = 0; i < car.Length; i++)
1806             {
1807                 CustomAttributeRecord caRecord = car[i];
1808                 RuntimeType attributeType = decoratedModule.ResolveType(scope.GetParentToken(caRecord.tkCtor), null, null) as RuntimeType;
1809
1810                 if (attributeType != (RuntimeType)typeof(AttributeUsageAttribute))
1811                     continue;
1812
1813                 if (attributeUsageAttribute != null)
1814                     throw new FormatException(String.Format(
1815                         CultureInfo.CurrentUICulture, SR.Format_AttributeUsage, attributeType));
1816
1817                 AttributeTargets targets;
1818                 bool inherited, allowMultiple;
1819                 ParseAttributeUsageAttribute(caRecord.blob, out targets, out inherited, out allowMultiple);
1820                 attributeUsageAttribute = new AttributeUsageAttribute(targets, allowMultiple, inherited);
1821             }
1822
1823             if (attributeUsageAttribute == null)
1824                 return AttributeUsageAttribute.Default;
1825
1826             return attributeUsageAttribute;
1827         }
1828         #endregion
1829
1830         #region Private Static FCalls
1831         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1832         private static extern void _ParseAttributeUsageAttribute(
1833             IntPtr pCa, int cCa, out int targets, out bool inherited, out bool allowMultiple);
1834         private static void ParseAttributeUsageAttribute(
1835             ConstArray ca, out AttributeTargets targets, out bool inherited, out bool allowMultiple)
1836         {
1837             int _targets;
1838             _ParseAttributeUsageAttribute(ca.Signature, ca.Length, out _targets, out inherited, out allowMultiple);
1839             targets = (AttributeTargets)_targets;
1840         }
1841
1842         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1843         private static unsafe extern Object _CreateCaObject(RuntimeModule pModule, IRuntimeMethodInfo pCtor, byte** ppBlob, byte* pEndBlob, int* pcNamedArgs);
1844         private static unsafe Object CreateCaObject(RuntimeModule module, IRuntimeMethodInfo ctor, ref IntPtr blob, IntPtr blobEnd, out int namedArgs)
1845         {
1846             byte* pBlob = (byte*)blob;
1847             byte* pBlobEnd = (byte*)blobEnd;
1848             int cNamedArgs;
1849             object ca = _CreateCaObject(module, ctor, &pBlob, pBlobEnd, &cNamedArgs);
1850             blob = (IntPtr)pBlob;
1851             namedArgs = cNamedArgs;
1852             return ca;
1853         }
1854
1855         [MethodImplAttribute(MethodImplOptions.InternalCall)]
1856         private unsafe extern static void _GetPropertyOrFieldData(
1857             RuntimeModule pModule, byte** ppBlobStart, byte* pBlobEnd, out string name, out bool bIsProperty, out RuntimeType type, out object value);
1858         private unsafe static void GetPropertyOrFieldData(
1859             RuntimeModule module, ref IntPtr blobStart, IntPtr blobEnd, out string name, out bool isProperty, out RuntimeType type, out object value)
1860         {
1861             byte* pBlobStart = (byte*)blobStart;
1862             _GetPropertyOrFieldData(
1863                 module.GetNativeHandle(), &pBlobStart, (byte*)blobEnd, out name, out isProperty, out type, out value);
1864             blobStart = (IntPtr)pBlobStart;
1865         }
1866
1867         private static object[] CreateAttributeArrayHelper(Type elementType, int elementCount)
1868         {
1869             return (object[])Array.UnsafeCreateInstance(elementType, elementCount);
1870         }
1871         #endregion
1872     }
1873
1874     internal static class PseudoCustomAttribute
1875     {
1876         #region Private Static Data Members
1877         // Here we can avoid the need to take a lock when using Dictionary by rearranging
1878         // the only method that adds values to the Dictionary. For more details on 
1879         // Dictionary versus Hashtable thread safety:
1880         // See code:Dictionary#DictionaryVersusHashtableThreadSafety
1881         private static readonly Dictionary<RuntimeType, RuntimeType> s_pca = CreatePseudoCustomAttributeDictionary();
1882         #endregion
1883
1884         #region Static Constructor
1885         static Dictionary<RuntimeType, RuntimeType> CreatePseudoCustomAttributeDictionary()
1886         {
1887             Type[] pcas = new Type[]
1888             {
1889                 // See https://github.com/dotnet/coreclr/blob/master/src/md/compiler/custattr_emit.cpp
1890                 typeof(FieldOffsetAttribute), // field
1891                 typeof(SerializableAttribute), // class, struct, enum, delegate
1892                 typeof(MarshalAsAttribute), // parameter, field, return-value
1893                 typeof(ComImportAttribute), // class, interface 
1894                 typeof(NonSerializedAttribute), // field, inherited
1895                 typeof(InAttribute), // parameter
1896                 typeof(OutAttribute), // parameter
1897                 typeof(OptionalAttribute), // parameter
1898                 typeof(DllImportAttribute), // method
1899                 typeof(PreserveSigAttribute), // method
1900                 typeof(TypeForwardedToAttribute), // assembly
1901             };
1902
1903             Dictionary<RuntimeType, RuntimeType> dict = new Dictionary<RuntimeType, RuntimeType>(pcas.Length);
1904             foreach (RuntimeType runtimeType in pcas)
1905             {
1906                 VerifyPseudoCustomAttribute(runtimeType);
1907                 dict[runtimeType] = runtimeType;
1908             }
1909             return dict;
1910         }
1911
1912         [Conditional("DEBUG")]
1913         private static void VerifyPseudoCustomAttribute(RuntimeType pca)
1914         {
1915             // If any of these are invariants are no longer true will have to 
1916             // re-architect the PCA product logic and test cases -- you've been warned!
1917             Debug.Assert(pca.BaseType == (RuntimeType)typeof(Attribute), "Pseudo CA Error");
1918             AttributeUsageAttribute usage = CustomAttribute.GetAttributeUsage(pca);
1919             Debug.Assert(usage.Inherited == false, "Pseudo CA Error");
1920             //AllowMultiple is true for TypeForwardedToAttribute
1921             //Debug.Assert(usage.AllowMultiple == false, "Pseudo CA Error");
1922         }
1923         #endregion
1924
1925         #region Internal Static
1926         internal static Attribute[] GetCustomAttributes(RuntimeType type, RuntimeType caType, out int count)
1927         {
1928             Debug.Assert(type != null);
1929             Debug.Assert(caType != null);
1930
1931             count = 0;
1932
1933             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
1934             if (!all && !s_pca.ContainsKey(caType))
1935                 return null;
1936
1937             Attribute[] pcas = new Attribute[all ? 2 : 1];
1938
1939             if (all || caType == (RuntimeType)typeof(SerializableAttribute))
1940             {
1941                 if ((type.Attributes & TypeAttributes.Serializable) != 0)
1942                     pcas[count++] = new SerializableAttribute();
1943             }
1944             if (all || caType == (RuntimeType)typeof(ComImportAttribute))
1945             {
1946                 if ((type.Attributes & TypeAttributes.Import) != 0)
1947                     pcas[count++] = new ComImportAttribute();
1948             }
1949
1950             return pcas;
1951         }
1952         internal static bool IsDefined(RuntimeType type, RuntimeType caType)
1953         {
1954             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
1955             if (!all && !s_pca.ContainsKey(caType))
1956                 return false;
1957
1958             if (all || caType == (RuntimeType)typeof(SerializableAttribute))
1959             {
1960                 if ((type.Attributes & TypeAttributes.Serializable) != 0)
1961                     return true;
1962             }
1963             if (all || caType == (RuntimeType)typeof(ComImportAttribute))
1964             {
1965                 if ((type.Attributes & TypeAttributes.Import) != 0)
1966                     return true;
1967             }
1968
1969             return false;
1970         }
1971
1972         internal static Attribute[] GetCustomAttributes(RuntimeMethodInfo method, RuntimeType caType, out int count)
1973         {
1974             Debug.Assert(method != null);
1975             Debug.Assert(caType != null);
1976
1977             count = 0;
1978
1979             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
1980             if (!all && !s_pca.ContainsKey(caType))
1981                 return null;
1982
1983             Attribute[] pcas = new Attribute[all ? 2 : 1];
1984             Attribute pca;
1985
1986             if (all || caType == (RuntimeType)typeof(DllImportAttribute))
1987             {
1988                 pca = GetDllImportCustomAttribute(method);
1989                 if (pca != null) pcas[count++] = pca;
1990             }
1991             if (all || caType == (RuntimeType)typeof(PreserveSigAttribute))
1992             {
1993                 if ((method.GetMethodImplementationFlags() & MethodImplAttributes.PreserveSig) != 0)
1994                     pcas[count++] = new PreserveSigAttribute();
1995             }
1996
1997             return pcas;
1998         }
1999         internal static bool IsDefined(RuntimeMethodInfo method, RuntimeType caType)
2000         {
2001             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2002             if (!all && !s_pca.ContainsKey(caType))
2003                 return false;
2004
2005             if (all || caType == (RuntimeType)typeof(DllImportAttribute))
2006             {
2007                 if ((method.Attributes & MethodAttributes.PinvokeImpl) != 0)
2008                     return true;
2009             }
2010             if (all || caType == (RuntimeType)typeof(PreserveSigAttribute))
2011             {
2012                 if ((method.GetMethodImplementationFlags() & MethodImplAttributes.PreserveSig) != 0)
2013                     return true;
2014             }
2015
2016             return false;
2017         }
2018
2019         internal static Attribute[] GetCustomAttributes(RuntimeParameterInfo parameter, RuntimeType caType, out int count)
2020         {
2021             Debug.Assert(parameter != null);
2022             Debug.Assert(caType != null);
2023
2024             count = 0;
2025
2026             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2027             if (!all && !s_pca.ContainsKey(caType))
2028                 return null;
2029
2030             Attribute[] pcas = new Attribute[all ? 4 : 1];
2031             Attribute pca;
2032
2033             if (all || caType == (RuntimeType)typeof(InAttribute))
2034             {
2035                 if (parameter.IsIn)
2036                     pcas[count++] = new InAttribute();
2037             }
2038             if (all || caType == (RuntimeType)typeof(OutAttribute))
2039             {
2040                 if (parameter.IsOut)
2041                     pcas[count++] = new OutAttribute();
2042             }
2043             if (all || caType == (RuntimeType)typeof(OptionalAttribute))
2044             {
2045                 if (parameter.IsOptional)
2046                     pcas[count++] = new OptionalAttribute();
2047             }
2048             if (all || caType == (RuntimeType)typeof(MarshalAsAttribute))
2049             {
2050                 pca = GetMarshalAsCustomAttribute(parameter);
2051                 if (pca != null) pcas[count++] = pca;
2052             }
2053             return pcas;
2054         }
2055         internal static bool IsDefined(RuntimeParameterInfo parameter, RuntimeType caType)
2056         {
2057             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2058             if (!all && !s_pca.ContainsKey(caType))
2059                 return false;
2060
2061             if (all || caType == (RuntimeType)typeof(InAttribute))
2062             {
2063                 if (parameter.IsIn) return true;
2064             }
2065             if (all || caType == (RuntimeType)typeof(OutAttribute))
2066             {
2067                 if (parameter.IsOut) return true;
2068             }
2069             if (all || caType == (RuntimeType)typeof(OptionalAttribute))
2070             {
2071                 if (parameter.IsOptional) return true;
2072             }
2073             if (all || caType == (RuntimeType)typeof(MarshalAsAttribute))
2074             {
2075                 if (GetMarshalAsCustomAttribute(parameter) != null) return true;
2076             }
2077
2078             return false;
2079         }
2080
2081         internal static Attribute[] GetCustomAttributes(RuntimeAssembly assembly, RuntimeType caType, out int count)
2082         {
2083             count = 0;
2084             return null;
2085         }
2086         internal static bool IsDefined(RuntimeAssembly assembly, RuntimeType caType)
2087         {
2088             return false;
2089         }
2090
2091         internal static Attribute[] GetCustomAttributes(RuntimeModule module, RuntimeType caType, out int count)
2092         {
2093             count = 0;
2094             return null;
2095         }
2096         internal static bool IsDefined(RuntimeModule module, RuntimeType caType)
2097         {
2098             return false;
2099         }
2100
2101         internal static Attribute[] GetCustomAttributes(RuntimeFieldInfo field, RuntimeType caType, out int count)
2102         {
2103             Debug.Assert(field != null);
2104             Debug.Assert(caType != null);
2105
2106             count = 0;
2107
2108             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2109             if (!all && !s_pca.ContainsKey(caType))
2110                 return null;
2111
2112             Attribute[] pcas = new Attribute[all ? 3 : 1];
2113             Attribute pca;
2114
2115             if (all || caType == (RuntimeType)typeof(MarshalAsAttribute))
2116             {
2117                 pca = GetMarshalAsCustomAttribute(field);
2118                 if (pca != null) pcas[count++] = pca;
2119             }
2120             if (all || caType == (RuntimeType)typeof(FieldOffsetAttribute))
2121             {
2122                 pca = GetFieldOffsetCustomAttribute(field);
2123                 if (pca != null) pcas[count++] = pca;
2124             }
2125             if (all || caType == (RuntimeType)typeof(NonSerializedAttribute))
2126             {
2127                 if ((field.Attributes & FieldAttributes.NotSerialized) != 0)
2128                     pcas[count++] = new NonSerializedAttribute();
2129             }
2130             return pcas;
2131         }
2132         internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType caType)
2133         {
2134             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2135             if (!all && !s_pca.ContainsKey(caType))
2136                 return false;
2137
2138             if (all || caType == (RuntimeType)typeof(MarshalAsAttribute))
2139             {
2140                 if (GetMarshalAsCustomAttribute(field) != null) return true;
2141             }
2142             if (all || caType == (RuntimeType)typeof(FieldOffsetAttribute))
2143             {
2144                 if (GetFieldOffsetCustomAttribute(field) != null) return true;
2145             }
2146             if (all || caType == (RuntimeType)typeof(NonSerializedAttribute))
2147             {
2148                 if ((field.Attributes & FieldAttributes.NotSerialized) != 0)
2149                     return true;
2150             }
2151
2152             return false;
2153         }
2154
2155         internal static Attribute[] GetCustomAttributes(RuntimeConstructorInfo ctor, RuntimeType caType, out int count)
2156         {
2157             count = 0;
2158             return null;
2159         }
2160         internal static bool IsDefined(RuntimeConstructorInfo ctor, RuntimeType caType)
2161         {
2162             return false;
2163         }
2164
2165         internal static Attribute[] GetCustomAttributes(RuntimePropertyInfo property, RuntimeType caType, out int count)
2166         {
2167             count = 0;
2168             return null;
2169         }
2170         internal static bool IsDefined(RuntimePropertyInfo property, RuntimeType caType)
2171         {
2172             return false;
2173         }
2174
2175         internal static Attribute[] GetCustomAttributes(RuntimeEventInfo e, RuntimeType caType, out int count)
2176         {
2177             count = 0;
2178             return null;
2179         }
2180         internal static bool IsDefined(RuntimeEventInfo e, RuntimeType caType)
2181         {
2182             return false;
2183         }
2184         #endregion
2185
2186         private static DllImportAttribute GetDllImportCustomAttribute(RuntimeMethodInfo method)
2187         {
2188             if ((method.Attributes & MethodAttributes.PinvokeImpl) == 0)
2189                 return null;
2190
2191             MetadataImport scope = ModuleHandle.GetMetadataImport(method.Module.ModuleHandle.GetRuntimeModule());
2192             string entryPoint, dllName = null;
2193             int token = method.MetadataToken;
2194             PInvokeAttributes flags = 0;
2195
2196             scope.GetPInvokeMap(token, out flags, out entryPoint, out dllName);
2197
2198             CharSet charSet = CharSet.None;
2199
2200             switch (flags & PInvokeAttributes.CharSetMask)
2201             {
2202                 case PInvokeAttributes.CharSetNotSpec: charSet = CharSet.None; break;
2203                 case PInvokeAttributes.CharSetAnsi: charSet = CharSet.Ansi; break;
2204                 case PInvokeAttributes.CharSetUnicode: charSet = CharSet.Unicode; break;
2205                 case PInvokeAttributes.CharSetAuto: charSet = CharSet.Auto; break;
2206
2207                 // Invalid: default to CharSet.None
2208                 default: break;
2209             }
2210
2211             CallingConvention callingConvention = CallingConvention.Cdecl;
2212
2213             switch (flags & PInvokeAttributes.CallConvMask)
2214             {
2215                 case PInvokeAttributes.CallConvWinapi: callingConvention = CallingConvention.Winapi; break;
2216                 case PInvokeAttributes.CallConvCdecl: callingConvention = CallingConvention.Cdecl; break;
2217                 case PInvokeAttributes.CallConvStdcall: callingConvention = CallingConvention.StdCall; break;
2218                 case PInvokeAttributes.CallConvThiscall: callingConvention = CallingConvention.ThisCall; break;
2219                 case PInvokeAttributes.CallConvFastcall: callingConvention = CallingConvention.FastCall; break;
2220
2221                 // Invalid: default to CallingConvention.Cdecl
2222                 default: break;
2223             }
2224
2225             DllImportAttribute attribute = new DllImportAttribute(dllName);
2226
2227             attribute.EntryPoint = entryPoint;
2228             attribute.CharSet = charSet;
2229             attribute.SetLastError = (flags & PInvokeAttributes.SupportsLastError) != 0;
2230             attribute.ExactSpelling = (flags & PInvokeAttributes.NoMangle) != 0;
2231             attribute.PreserveSig = (method.GetMethodImplementationFlags() & MethodImplAttributes.PreserveSig) != 0;
2232             attribute.CallingConvention = callingConvention;
2233             attribute.BestFitMapping = (flags & PInvokeAttributes.BestFitMask) == PInvokeAttributes.BestFitEnabled;
2234             attribute.ThrowOnUnmappableChar = (flags & PInvokeAttributes.ThrowOnUnmappableCharMask) == PInvokeAttributes.ThrowOnUnmappableCharEnabled;
2235
2236             return attribute;
2237         }
2238
2239
2240         private static MarshalAsAttribute GetMarshalAsCustomAttribute(RuntimeParameterInfo parameter)
2241         {
2242             return GetMarshalAsCustomAttribute(parameter.MetadataToken, parameter.GetRuntimeModule());
2243         }
2244         private static MarshalAsAttribute GetMarshalAsCustomAttribute(RuntimeFieldInfo field)
2245         {
2246             return GetMarshalAsCustomAttribute(field.MetadataToken, field.GetRuntimeModule());
2247         }
2248
2249         private static MarshalAsAttribute GetMarshalAsCustomAttribute(int token, RuntimeModule scope)
2250         {
2251             UnmanagedType unmanagedType, arraySubType;
2252             VarEnum safeArraySubType;
2253             int sizeParamIndex = 0, sizeConst = 0;
2254             string marshalTypeName = null, marshalCookie = null, safeArrayUserDefinedTypeName = null;
2255             int iidParamIndex = 0;
2256             ConstArray nativeType = ModuleHandle.GetMetadataImport(scope.GetNativeHandle()).GetFieldMarshal(token);
2257
2258             if (nativeType.Length == 0)
2259                 return null;
2260
2261             MetadataImport.GetMarshalAs(nativeType,
2262                 out unmanagedType, out safeArraySubType, out safeArrayUserDefinedTypeName, out arraySubType, out sizeParamIndex,
2263                 out sizeConst, out marshalTypeName, out marshalCookie, out iidParamIndex);
2264
2265             RuntimeType safeArrayUserDefinedType = safeArrayUserDefinedTypeName == null || safeArrayUserDefinedTypeName.Length == 0 ? null :
2266                 RuntimeTypeHandle.GetTypeByNameUsingCARules(safeArrayUserDefinedTypeName, scope);
2267             RuntimeType marshalTypeRef = null;
2268
2269             try
2270             {
2271                 marshalTypeRef = marshalTypeName == null ? null : RuntimeTypeHandle.GetTypeByNameUsingCARules(marshalTypeName, scope);
2272             }
2273             catch (System.TypeLoadException)
2274             {
2275                 // The user may have supplied a bad type name string causing this TypeLoadException
2276                 // Regardless, we return the bad type name
2277                 Debug.Assert(marshalTypeName != null);
2278             }
2279
2280             MarshalAsAttribute attribute = new MarshalAsAttribute(unmanagedType);
2281
2282             attribute.SafeArraySubType = safeArraySubType;
2283             attribute.SafeArrayUserDefinedSubType = safeArrayUserDefinedType;
2284             attribute.IidParameterIndex = iidParamIndex;
2285             attribute.ArraySubType = arraySubType;
2286             attribute.SizeParamIndex = (short)sizeParamIndex;
2287             attribute.SizeConst = sizeConst;
2288             attribute.MarshalType = marshalTypeName;
2289             attribute.MarshalTypeRef = marshalTypeRef;
2290             attribute.MarshalCookie = marshalCookie;
2291
2292             return attribute;
2293         }
2294
2295         private static FieldOffsetAttribute GetFieldOffsetCustomAttribute(RuntimeFieldInfo field)
2296         {
2297             int fieldOffset;
2298
2299             if (field.DeclaringType != null &&
2300                 field.GetRuntimeModule().MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out fieldOffset))
2301                 return new FieldOffsetAttribute(fieldOffset);
2302
2303             return null;
2304         }
2305
2306         internal static StructLayoutAttribute GetStructLayoutCustomAttribute(RuntimeType type)
2307         {
2308             if (type.IsInterface || type.HasElementType || type.IsGenericParameter)
2309                 return null;
2310
2311             int pack = 0, size = 0;
2312             LayoutKind layoutKind = LayoutKind.Auto;
2313             switch (type.Attributes & TypeAttributes.LayoutMask)
2314             {
2315                 case TypeAttributes.ExplicitLayout: layoutKind = LayoutKind.Explicit; break;
2316                 case TypeAttributes.AutoLayout: layoutKind = LayoutKind.Auto; break;
2317                 case TypeAttributes.SequentialLayout: layoutKind = LayoutKind.Sequential; break;
2318                 default: Debug.Fail("Unreachable code"); break;
2319             }
2320
2321             CharSet charSet = CharSet.None;
2322             switch (type.Attributes & TypeAttributes.StringFormatMask)
2323             {
2324                 case TypeAttributes.AnsiClass: charSet = CharSet.Ansi; break;
2325                 case TypeAttributes.AutoClass: charSet = CharSet.Auto; break;
2326                 case TypeAttributes.UnicodeClass: charSet = CharSet.Unicode; break;
2327                 default: Debug.Fail("Unreachable code"); break;
2328             }
2329             type.GetRuntimeModule().MetadataImport.GetClassLayout(type.MetadataToken, out pack, out size);
2330
2331             // Metadata parameter checking should not have allowed 0 for packing size.
2332             // The runtime later converts a packing size of 0 to 8 so do the same here
2333             // because it's more useful from a user perspective. 
2334             if (pack == 0)
2335                 pack = 8; // DEFAULT_PACKING_SIZE
2336
2337             StructLayoutAttribute attribute = new StructLayoutAttribute(layoutKind);
2338
2339             attribute.Pack = pack;
2340             attribute.Size = size;
2341             attribute.CharSet = charSet;
2342
2343             return attribute;
2344         }
2345     }
2346 }