580a34a9ae6284e8ca34fbfb751dad0b74d9682f
[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 Dictionary<RuntimeType, RuntimeType> s_pca;
1882         private static int s_pcasCount;
1883         #endregion
1884
1885         #region Static Constructor
1886         static PseudoCustomAttribute()
1887         {
1888             RuntimeType[] pcas = new RuntimeType[]
1889             {
1890                 // See //depot/DevDiv/private/Main/ndp/clr/src/MD/Compiler/CustAttr.cpp
1891                 typeof(FieldOffsetAttribute) as RuntimeType, // field
1892                 typeof(SerializableAttribute) as RuntimeType, // class, struct, enum, delegate
1893                 typeof(MarshalAsAttribute) as RuntimeType, // parameter, field, return-value
1894                 typeof(ComImportAttribute) as RuntimeType, // class, interface 
1895                 typeof(NonSerializedAttribute) as RuntimeType, // field, inherited
1896                 typeof(InAttribute) as RuntimeType, // parameter
1897                 typeof(OutAttribute) as RuntimeType, // parameter
1898                 typeof(OptionalAttribute) as RuntimeType, // parameter
1899                 typeof(DllImportAttribute) as RuntimeType, // method
1900                 typeof(PreserveSigAttribute) as RuntimeType, // method
1901                 typeof(TypeForwardedToAttribute) as RuntimeType, // assembly
1902             };
1903
1904             s_pcasCount = pcas.Length;
1905             Dictionary<RuntimeType, RuntimeType> temp_pca = new Dictionary<RuntimeType, RuntimeType>(s_pcasCount);
1906
1907             for (int i = 0; i < s_pcasCount; i++)
1908             {
1909                 VerifyPseudoCustomAttribute(pcas[i]);
1910                 temp_pca[pcas[i]] = pcas[i];
1911             }
1912             s_pca = temp_pca;
1913         }
1914
1915         [Conditional("DEBUG")]
1916         private static void VerifyPseudoCustomAttribute(RuntimeType pca)
1917         {
1918             // If any of these are invariants are no longer true will have to 
1919             // re-architect the PCA product logic and test cases -- you've been warned!
1920             Debug.Assert(pca.BaseType == (RuntimeType)typeof(Attribute), "Pseudo CA Error");
1921             AttributeUsageAttribute usage = CustomAttribute.GetAttributeUsage(pca);
1922             Debug.Assert(usage.Inherited == false, "Pseudo CA Error");
1923             //AllowMultiple is true for TypeForwardedToAttribute
1924             //Debug.Assert(usage.AllowMultiple == false, "Pseudo CA Error");
1925         }
1926         #endregion
1927
1928         #region Internal Static
1929         internal static Attribute[] GetCustomAttributes(RuntimeType type, RuntimeType caType, out int count)
1930         {
1931             Debug.Assert(type != null);
1932             Debug.Assert(caType != null);
1933
1934             count = 0;
1935
1936             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
1937             if (!all && !s_pca.ContainsKey(caType))
1938                 return Array.Empty<Attribute>();
1939
1940             List<Attribute> pcas = new List<Attribute>();
1941
1942             if (all || caType == (RuntimeType)typeof(SerializableAttribute))
1943             {
1944                 if ((type.Attributes & TypeAttributes.Serializable) != 0)
1945                     pcas.Add(new SerializableAttribute());
1946             }
1947             if (all || caType == (RuntimeType)typeof(ComImportAttribute))
1948             {
1949                 if ((type.Attributes & TypeAttributes.Import) != 0)
1950                     pcas.Add(new ComImportAttribute());
1951             }
1952
1953             count = pcas.Count;
1954             return pcas.ToArray();
1955         }
1956         internal static bool IsDefined(RuntimeType type, RuntimeType caType)
1957         {
1958             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
1959             if (!all && !s_pca.ContainsKey(caType))
1960                 return false;
1961
1962             if (all || caType == (RuntimeType)typeof(SerializableAttribute))
1963             {
1964                 if ((type.Attributes & TypeAttributes.Serializable) != 0)
1965                     return true;
1966             }
1967             if (all || caType == (RuntimeType)typeof(ComImportAttribute))
1968             {
1969                 if ((type.Attributes & TypeAttributes.Import) != 0)
1970                     return true;
1971             }
1972
1973             return false;
1974         }
1975
1976         internal static Attribute[] GetCustomAttributes(RuntimeMethodInfo method, RuntimeType caType, out int count)
1977         {
1978             Debug.Assert(method != null);
1979             Debug.Assert(caType != null);
1980
1981             count = 0;
1982
1983             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
1984             if (!all && !s_pca.ContainsKey(caType))
1985                 return Array.Empty<Attribute>();
1986
1987             List<Attribute> pcas = new List<Attribute>();
1988             Attribute pca;
1989
1990             if (all || caType == (RuntimeType)typeof(DllImportAttribute))
1991             {
1992                 pca = GetDllImportCustomAttribute(method);
1993                 if (pca != null) pcas[count++] = pca;
1994             }
1995             if (all || caType == (RuntimeType)typeof(PreserveSigAttribute))
1996             {
1997                 if ((method.GetMethodImplementationFlags() & MethodImplAttributes.PreserveSig) != 0)
1998                     pcas.Add(new PreserveSigAttribute());
1999             }
2000
2001             count = pcas.Count;
2002             return pcas.ToArray();
2003         }
2004         internal static bool IsDefined(RuntimeMethodInfo method, RuntimeType caType)
2005         {
2006             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2007             if (!all && !s_pca.ContainsKey(caType))
2008                 return false;
2009
2010             if (all || caType == (RuntimeType)typeof(DllImportAttribute))
2011             {
2012                 if ((method.Attributes & MethodAttributes.PinvokeImpl) != 0)
2013                     return true;
2014             }
2015             if (all || caType == (RuntimeType)typeof(PreserveSigAttribute))
2016             {
2017                 if ((method.GetMethodImplementationFlags() & MethodImplAttributes.PreserveSig) != 0)
2018                     return true;
2019             }
2020
2021             return false;
2022         }
2023
2024         internal static Attribute[] GetCustomAttributes(RuntimeParameterInfo parameter, RuntimeType caType, out int count)
2025         {
2026             Debug.Assert(parameter != null);
2027             Debug.Assert(caType != null);
2028
2029             count = 0;
2030
2031             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2032             if (!all && !s_pca.ContainsKey(caType))
2033                 return null;
2034
2035             Attribute[] pcas = new Attribute[s_pcasCount];
2036             Attribute pca;
2037
2038             if (all || caType == (RuntimeType)typeof(InAttribute))
2039             {
2040                 if (parameter.IsIn)
2041                     pcas[count++] = new InAttribute();
2042             }
2043             if (all || caType == (RuntimeType)typeof(OutAttribute))
2044             {
2045                 if (parameter.IsOut)
2046                     pcas[count++] = new OutAttribute();
2047             }
2048             if (all || caType == (RuntimeType)typeof(OptionalAttribute))
2049             {
2050                 if (parameter.IsOptional)
2051                     pcas[count++] = new OptionalAttribute();
2052             }
2053             if (all || caType == (RuntimeType)typeof(MarshalAsAttribute))
2054             {
2055                 pca = GetMarshalAsCustomAttribute(parameter);
2056                 if (pca != null) pcas[count++] = pca;
2057             }
2058             return pcas;
2059         }
2060         internal static bool IsDefined(RuntimeParameterInfo parameter, RuntimeType caType)
2061         {
2062             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2063             if (!all && !s_pca.ContainsKey(caType))
2064                 return false;
2065
2066
2067             if (all || caType == (RuntimeType)typeof(InAttribute))
2068             {
2069                 if (parameter.IsIn) return true;
2070             }
2071             if (all || caType == (RuntimeType)typeof(OutAttribute))
2072             {
2073                 if (parameter.IsOut) return true;
2074             }
2075             if (all || caType == (RuntimeType)typeof(OptionalAttribute))
2076             {
2077                 if (parameter.IsOptional) return true;
2078             }
2079             if (all || caType == (RuntimeType)typeof(MarshalAsAttribute))
2080             {
2081                 if (GetMarshalAsCustomAttribute(parameter) != null) return true;
2082             }
2083
2084             return false;
2085         }
2086
2087         internal static Attribute[] GetCustomAttributes(RuntimeAssembly assembly, RuntimeType caType, out int count)
2088         {
2089             count = 0;
2090             return null;
2091         }
2092         internal static bool IsDefined(RuntimeAssembly assembly, RuntimeType caType)
2093         {
2094             return false;
2095         }
2096
2097         internal static Attribute[] GetCustomAttributes(RuntimeModule module, RuntimeType caType, out int count)
2098         {
2099             count = 0;
2100             return null;
2101         }
2102         internal static bool IsDefined(RuntimeModule module, RuntimeType caType)
2103         {
2104             return false;
2105         }
2106
2107         internal static Attribute[] GetCustomAttributes(RuntimeFieldInfo field, RuntimeType caType, out int count)
2108         {
2109             Debug.Assert(field != null);
2110             Debug.Assert(caType != null);
2111
2112             count = 0;
2113
2114             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2115             if (!all && !s_pca.ContainsKey(caType))
2116                 return null;
2117
2118             Attribute[] pcas = new Attribute[s_pcasCount];
2119             Attribute pca;
2120
2121             if (all || caType == (RuntimeType)typeof(MarshalAsAttribute))
2122             {
2123                 pca = GetMarshalAsCustomAttribute(field);
2124                 if (pca != null) pcas[count++] = pca;
2125             }
2126             if (all || caType == (RuntimeType)typeof(FieldOffsetAttribute))
2127             {
2128                 pca = GetFieldOffsetCustomAttribute(field);
2129                 if (pca != null) pcas[count++] = pca;
2130             }
2131             if (all || caType == (RuntimeType)typeof(NonSerializedAttribute))
2132             {
2133                 if ((field.Attributes & FieldAttributes.NotSerialized) != 0)
2134                     pcas[count++] = new NonSerializedAttribute();
2135             }
2136             return pcas;
2137         }
2138         internal static bool IsDefined(RuntimeFieldInfo field, RuntimeType caType)
2139         {
2140             bool all = caType == (RuntimeType)typeof(object) || caType == (RuntimeType)typeof(Attribute);
2141             if (!all && !s_pca.ContainsKey(caType))
2142                 return false;
2143
2144             if (all || caType == (RuntimeType)typeof(MarshalAsAttribute))
2145             {
2146                 if (GetMarshalAsCustomAttribute(field) != null) return true;
2147             }
2148             if (all || caType == (RuntimeType)typeof(FieldOffsetAttribute))
2149             {
2150                 if (GetFieldOffsetCustomAttribute(field) != null) return true;
2151             }
2152             if (all || caType == (RuntimeType)typeof(NonSerializedAttribute))
2153             {
2154                 if ((field.Attributes & FieldAttributes.NotSerialized) != 0)
2155                     return true;
2156             }
2157
2158             return false;
2159         }
2160
2161         internal static Attribute[] GetCustomAttributes(RuntimeConstructorInfo ctor, RuntimeType caType, out int count)
2162         {
2163             count = 0;
2164             return null;
2165         }
2166         internal static bool IsDefined(RuntimeConstructorInfo ctor, RuntimeType caType)
2167         {
2168             return false;
2169         }
2170
2171         internal static Attribute[] GetCustomAttributes(RuntimePropertyInfo property, RuntimeType caType, out int count)
2172         {
2173             count = 0;
2174             return null;
2175         }
2176         internal static bool IsDefined(RuntimePropertyInfo property, RuntimeType caType)
2177         {
2178             return false;
2179         }
2180
2181         internal static Attribute[] GetCustomAttributes(RuntimeEventInfo e, RuntimeType caType, out int count)
2182         {
2183             count = 0;
2184             return null;
2185         }
2186         internal static bool IsDefined(RuntimeEventInfo e, RuntimeType caType)
2187         {
2188             return false;
2189         }
2190         #endregion
2191
2192         private static DllImportAttribute GetDllImportCustomAttribute(RuntimeMethodInfo method)
2193         {
2194             if ((method.Attributes & MethodAttributes.PinvokeImpl) == 0)
2195                 return null;
2196
2197             MetadataImport scope = ModuleHandle.GetMetadataImport(method.Module.ModuleHandle.GetRuntimeModule());
2198             string entryPoint, dllName = null;
2199             int token = method.MetadataToken;
2200             PInvokeAttributes flags = 0;
2201
2202             scope.GetPInvokeMap(token, out flags, out entryPoint, out dllName);
2203
2204             CharSet charSet = CharSet.None;
2205
2206             switch (flags & PInvokeAttributes.CharSetMask)
2207             {
2208                 case PInvokeAttributes.CharSetNotSpec: charSet = CharSet.None; break;
2209                 case PInvokeAttributes.CharSetAnsi: charSet = CharSet.Ansi; break;
2210                 case PInvokeAttributes.CharSetUnicode: charSet = CharSet.Unicode; break;
2211                 case PInvokeAttributes.CharSetAuto: charSet = CharSet.Auto; break;
2212
2213                 // Invalid: default to CharSet.None
2214                 default: break;
2215             }
2216
2217             CallingConvention callingConvention = CallingConvention.Cdecl;
2218
2219             switch (flags & PInvokeAttributes.CallConvMask)
2220             {
2221                 case PInvokeAttributes.CallConvWinapi: callingConvention = CallingConvention.Winapi; break;
2222                 case PInvokeAttributes.CallConvCdecl: callingConvention = CallingConvention.Cdecl; break;
2223                 case PInvokeAttributes.CallConvStdcall: callingConvention = CallingConvention.StdCall; break;
2224                 case PInvokeAttributes.CallConvThiscall: callingConvention = CallingConvention.ThisCall; break;
2225                 case PInvokeAttributes.CallConvFastcall: callingConvention = CallingConvention.FastCall; break;
2226
2227                 // Invalid: default to CallingConvention.Cdecl
2228                 default: break;
2229             }
2230
2231             DllImportAttribute attribute = new DllImportAttribute(dllName);
2232
2233             attribute.EntryPoint = entryPoint;
2234             attribute.CharSet = charSet;
2235             attribute.SetLastError = (flags & PInvokeAttributes.SupportsLastError) != 0;
2236             attribute.ExactSpelling = (flags & PInvokeAttributes.NoMangle) != 0;
2237             attribute.PreserveSig = (method.GetMethodImplementationFlags() & MethodImplAttributes.PreserveSig) != 0;
2238             attribute.CallingConvention = callingConvention;
2239             attribute.BestFitMapping = (flags & PInvokeAttributes.BestFitMask) == PInvokeAttributes.BestFitEnabled;
2240             attribute.ThrowOnUnmappableChar = (flags & PInvokeAttributes.ThrowOnUnmappableCharMask) == PInvokeAttributes.ThrowOnUnmappableCharEnabled;
2241
2242             return attribute;
2243         }
2244
2245
2246         private static MarshalAsAttribute GetMarshalAsCustomAttribute(RuntimeParameterInfo parameter)
2247         {
2248             return GetMarshalAsCustomAttribute(parameter.MetadataToken, parameter.GetRuntimeModule());
2249         }
2250         private static MarshalAsAttribute GetMarshalAsCustomAttribute(RuntimeFieldInfo field)
2251         {
2252             return GetMarshalAsCustomAttribute(field.MetadataToken, field.GetRuntimeModule());
2253         }
2254
2255         private static MarshalAsAttribute GetMarshalAsCustomAttribute(int token, RuntimeModule scope)
2256         {
2257             UnmanagedType unmanagedType, arraySubType;
2258             VarEnum safeArraySubType;
2259             int sizeParamIndex = 0, sizeConst = 0;
2260             string marshalTypeName = null, marshalCookie = null, safeArrayUserDefinedTypeName = null;
2261             int iidParamIndex = 0;
2262             ConstArray nativeType = ModuleHandle.GetMetadataImport(scope.GetNativeHandle()).GetFieldMarshal(token);
2263
2264             if (nativeType.Length == 0)
2265                 return null;
2266
2267             MetadataImport.GetMarshalAs(nativeType,
2268                 out unmanagedType, out safeArraySubType, out safeArrayUserDefinedTypeName, out arraySubType, out sizeParamIndex,
2269                 out sizeConst, out marshalTypeName, out marshalCookie, out iidParamIndex);
2270
2271             RuntimeType safeArrayUserDefinedType = safeArrayUserDefinedTypeName == null || safeArrayUserDefinedTypeName.Length == 0 ? null :
2272                 RuntimeTypeHandle.GetTypeByNameUsingCARules(safeArrayUserDefinedTypeName, scope);
2273             RuntimeType marshalTypeRef = null;
2274
2275             try
2276             {
2277                 marshalTypeRef = marshalTypeName == null ? null : RuntimeTypeHandle.GetTypeByNameUsingCARules(marshalTypeName, scope);
2278             }
2279             catch (System.TypeLoadException)
2280             {
2281                 // The user may have supplied a bad type name string causing this TypeLoadException
2282                 // Regardless, we return the bad type name
2283                 Debug.Assert(marshalTypeName != null);
2284             }
2285
2286             MarshalAsAttribute attribute = new MarshalAsAttribute(unmanagedType);
2287
2288             attribute.SafeArraySubType = safeArraySubType;
2289             attribute.SafeArrayUserDefinedSubType = safeArrayUserDefinedType;
2290             attribute.IidParameterIndex = iidParamIndex;
2291             attribute.ArraySubType = arraySubType;
2292             attribute.SizeParamIndex = (short)sizeParamIndex;
2293             attribute.SizeConst = sizeConst;
2294             attribute.MarshalType = marshalTypeName;
2295             attribute.MarshalTypeRef = marshalTypeRef;
2296             attribute.MarshalCookie = marshalCookie;
2297
2298             return attribute;
2299         }
2300
2301         private static FieldOffsetAttribute GetFieldOffsetCustomAttribute(RuntimeFieldInfo field)
2302         {
2303             int fieldOffset;
2304
2305             if (field.DeclaringType != null &&
2306                 field.GetRuntimeModule().MetadataImport.GetFieldOffset(field.DeclaringType.MetadataToken, field.MetadataToken, out fieldOffset))
2307                 return new FieldOffsetAttribute(fieldOffset);
2308
2309             return null;
2310         }
2311
2312         internal static StructLayoutAttribute GetStructLayoutCustomAttribute(RuntimeType type)
2313         {
2314             if (type.IsInterface || type.HasElementType || type.IsGenericParameter)
2315                 return null;
2316
2317             int pack = 0, size = 0;
2318             LayoutKind layoutKind = LayoutKind.Auto;
2319             switch (type.Attributes & TypeAttributes.LayoutMask)
2320             {
2321                 case TypeAttributes.ExplicitLayout: layoutKind = LayoutKind.Explicit; break;
2322                 case TypeAttributes.AutoLayout: layoutKind = LayoutKind.Auto; break;
2323                 case TypeAttributes.SequentialLayout: layoutKind = LayoutKind.Sequential; break;
2324                 default: Debug.Fail("Unreachable code"); break;
2325             }
2326
2327             CharSet charSet = CharSet.None;
2328             switch (type.Attributes & TypeAttributes.StringFormatMask)
2329             {
2330                 case TypeAttributes.AnsiClass: charSet = CharSet.Ansi; break;
2331                 case TypeAttributes.AutoClass: charSet = CharSet.Auto; break;
2332                 case TypeAttributes.UnicodeClass: charSet = CharSet.Unicode; break;
2333                 default: Debug.Fail("Unreachable code"); break;
2334             }
2335             type.GetRuntimeModule().MetadataImport.GetClassLayout(type.MetadataToken, out pack, out size);
2336
2337             // Metadata parameter checking should not have allowed 0 for packing size.
2338             // The runtime later converts a packing size of 0 to 8 so do the same here
2339             // because it's more useful from a user perspective. 
2340             if (pack == 0)
2341                 pack = 8; // DEFAULT_PACKING_SIZE
2342
2343             StructLayoutAttribute attribute = new StructLayoutAttribute(layoutKind);
2344
2345             attribute.Pack = pack;
2346             attribute.Size = size;
2347             attribute.CharSet = charSet;
2348
2349             return attribute;
2350         }
2351     }
2352 }