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 using System.Diagnostics;
6 using System.Reflection.Metadata.Ecma335;
7 using System.Runtime.CompilerServices;
8 
9 namespace System.Reflection.Metadata
10 {
11     partial class MetadataReader
12     {
13         internal const string ClrPrefix = "<CLR>";
14 
15         internal static readonly byte[] WinRTPrefix = new[] {
16             (byte)'<',
17             (byte)'W',
18             (byte)'i',
19             (byte)'n',
20             (byte)'R',
21             (byte)'T',
22             (byte)'>'
23         };
24 
25         #region Projection Tables
26 
27         // Maps names of projected types to projection information for each type.
28         // Both arrays are of the same length and sorted by the type name.
29         private static string[] s_projectedTypeNames;
30         private static ProjectionInfo[] s_projectionInfos;
31 
32         private readonly struct ProjectionInfo
33         {
34             public readonly string WinRTNamespace;
35             public readonly StringHandle.VirtualIndex ClrNamespace;
36             public readonly StringHandle.VirtualIndex ClrName;
37             public readonly AssemblyReferenceHandle.VirtualIndex AssemblyRef;
38             public readonly TypeDefTreatment Treatment;
39             public readonly TypeRefSignatureTreatment SignatureTreatment;
40             public readonly bool IsIDisposable;
41 
ProjectionInfoSystem.Reflection.Metadata.MetadataReader.ProjectionInfo42             public ProjectionInfo(
43                 string winRtNamespace,
44                 StringHandle.VirtualIndex clrNamespace,
45                 StringHandle.VirtualIndex clrName,
46                 AssemblyReferenceHandle.VirtualIndex clrAssembly,
47                 TypeDefTreatment treatment = TypeDefTreatment.RedirectedToClrType,
48                 TypeRefSignatureTreatment signatureTreatment = TypeRefSignatureTreatment.None,
49                 bool isIDisposable = false)
50             {
51                 this.WinRTNamespace = winRtNamespace;
52                 this.ClrNamespace = clrNamespace;
53                 this.ClrName = clrName;
54                 this.AssemblyRef = clrAssembly;
55                 this.Treatment = treatment;
56                 this.SignatureTreatment = signatureTreatment;
57                 this.IsIDisposable = isIDisposable;
58             }
59         }
60 
GetWellKnownTypeDefinitionTreatment(TypeDefinitionHandle typeDef)61         private TypeDefTreatment GetWellKnownTypeDefinitionTreatment(TypeDefinitionHandle typeDef)
62         {
63             InitializeProjectedTypes();
64 
65             StringHandle name = TypeDefTable.GetName(typeDef);
66 
67             int index = StringHeap.BinarySearchRaw(s_projectedTypeNames, name);
68             if (index < 0)
69             {
70                 return TypeDefTreatment.None;
71             }
72 
73             StringHandle namespaceName = TypeDefTable.GetNamespace(typeDef);
74             if (StringHeap.EqualsRaw(namespaceName, StringHeap.GetVirtualString(s_projectionInfos[index].ClrNamespace)))
75             {
76                 return s_projectionInfos[index].Treatment;
77             }
78 
79             // TODO: we can avoid this comparison if info.DotNetNamespace == info.WinRtNamespace
80             if (StringHeap.EqualsRaw(namespaceName, s_projectionInfos[index].WinRTNamespace))
81             {
82                 return s_projectionInfos[index].Treatment | TypeDefTreatment.MarkInternalFlag;
83             }
84 
85             return TypeDefTreatment.None;
86         }
87 
GetProjectionIndexForTypeReference(TypeReferenceHandle typeRef, out bool isIDisposable)88         private int GetProjectionIndexForTypeReference(TypeReferenceHandle typeRef, out bool isIDisposable)
89         {
90             InitializeProjectedTypes();
91 
92             int index = StringHeap.BinarySearchRaw(s_projectedTypeNames, TypeRefTable.GetName(typeRef));
93             if (index >= 0 && StringHeap.EqualsRaw(TypeRefTable.GetNamespace(typeRef), s_projectionInfos[index].WinRTNamespace))
94             {
95                 isIDisposable = s_projectionInfos[index].IsIDisposable;
96                 return index;
97             }
98 
99             isIDisposable = false;
100             return -1;
101         }
102 
GetProjectedAssemblyRef(int projectionIndex)103         internal static AssemblyReferenceHandle GetProjectedAssemblyRef(int projectionIndex)
104         {
105             Debug.Assert(s_projectionInfos != null && projectionIndex >= 0 && projectionIndex < s_projectionInfos.Length);
106             return AssemblyReferenceHandle.FromVirtualIndex(s_projectionInfos[projectionIndex].AssemblyRef);
107         }
108 
GetProjectedName(int projectionIndex)109         internal static StringHandle GetProjectedName(int projectionIndex)
110         {
111             Debug.Assert(s_projectionInfos != null && projectionIndex >= 0 && projectionIndex < s_projectionInfos.Length);
112             return StringHandle.FromVirtualIndex(s_projectionInfos[projectionIndex].ClrName);
113         }
114 
GetProjectedNamespace(int projectionIndex)115         internal static StringHandle GetProjectedNamespace(int projectionIndex)
116         {
117             Debug.Assert(s_projectionInfos != null && projectionIndex >= 0 && projectionIndex < s_projectionInfos.Length);
118             return StringHandle.FromVirtualIndex(s_projectionInfos[projectionIndex].ClrNamespace);
119         }
120 
GetProjectedSignatureTreatment(int projectionIndex)121         internal static TypeRefSignatureTreatment GetProjectedSignatureTreatment(int projectionIndex)
122         {
123             Debug.Assert(s_projectionInfos != null && projectionIndex >= 0 && projectionIndex < s_projectionInfos.Length);
124             return s_projectionInfos[projectionIndex].SignatureTreatment;
125         }
126 
InitializeProjectedTypes()127         private static void InitializeProjectedTypes()
128         {
129             if (s_projectedTypeNames == null || s_projectionInfos == null)
130             {
131                 var systemRuntimeWindowsRuntime = AssemblyReferenceHandle.VirtualIndex.System_Runtime_WindowsRuntime;
132                 var systemRuntime = AssemblyReferenceHandle.VirtualIndex.System_Runtime;
133                 var systemObjectModel = AssemblyReferenceHandle.VirtualIndex.System_ObjectModel;
134                 var systemRuntimeWindowsUiXaml = AssemblyReferenceHandle.VirtualIndex.System_Runtime_WindowsRuntime_UI_Xaml;
135                 var systemRuntimeInterop = AssemblyReferenceHandle.VirtualIndex.System_Runtime_InteropServices_WindowsRuntime;
136                 var systemNumericsVectors = AssemblyReferenceHandle.VirtualIndex.System_Numerics_Vectors;
137 
138                 // sorted by name
139                 var keys = new string[50];
140                 var values = new ProjectionInfo[50];
141                 int k = 0, v = 0;
142 
143                 // WARNING: Keys must be sorted by name and must only contain ASCII characters. WinRTNamespace must also be ASCII only.
144 
145                 keys[k++] = "AttributeTargets"; values[v++] = new ProjectionInfo("Windows.Foundation.Metadata", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.AttributeTargets, systemRuntime);
146                 keys[k++] = "AttributeUsageAttribute"; values[v++] = new ProjectionInfo("Windows.Foundation.Metadata", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.AttributeUsageAttribute, systemRuntime, treatment: TypeDefTreatment.RedirectedToClrAttribute);
147                 keys[k++] = "Color"; values[v++] = new ProjectionInfo("Windows.UI", StringHandle.VirtualIndex.Windows_UI, StringHandle.VirtualIndex.Color, systemRuntimeWindowsRuntime);
148                 keys[k++] = "CornerRadius"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.CornerRadius, systemRuntimeWindowsUiXaml);
149                 keys[k++] = "DateTime"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.DateTimeOffset, systemRuntime);
150                 keys[k++] = "Duration"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.Duration, systemRuntimeWindowsUiXaml);
151                 keys[k++] = "DurationType"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.DurationType, systemRuntimeWindowsUiXaml);
152                 keys[k++] = "EventHandler`1"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.EventHandler1, systemRuntime);
153                 keys[k++] = "EventRegistrationToken"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System_Runtime_InteropServices_WindowsRuntime, StringHandle.VirtualIndex.EventRegistrationToken, systemRuntimeInterop);
154                 keys[k++] = "GeneratorPosition"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Controls.Primitives", StringHandle.VirtualIndex.Windows_UI_Xaml_Controls_Primitives, StringHandle.VirtualIndex.GeneratorPosition, systemRuntimeWindowsUiXaml);
155                 keys[k++] = "GridLength"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.GridLength, systemRuntimeWindowsUiXaml);
156                 keys[k++] = "GridUnitType"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.GridUnitType, systemRuntimeWindowsUiXaml);
157                 keys[k++] = "HResult"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.Exception, systemRuntime, signatureTreatment: TypeRefSignatureTreatment.ProjectedToClass);
158                 keys[k++] = "IBindableIterable"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections, StringHandle.VirtualIndex.IEnumerable, systemRuntime);
159                 keys[k++] = "IBindableVector"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections, StringHandle.VirtualIndex.IList, systemRuntime);
160                 keys[k++] = "IClosable"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.IDisposable, systemRuntime, isIDisposable: true);
161                 keys[k++] = "ICommand"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Input", StringHandle.VirtualIndex.System_Windows_Input, StringHandle.VirtualIndex.ICommand, systemObjectModel);
162                 keys[k++] = "IIterable`1"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IEnumerable1, systemRuntime);
163                 keys[k++] = "IKeyValuePair`2"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.KeyValuePair2, systemRuntime, signatureTreatment: TypeRefSignatureTreatment.ProjectedToValueType);
164                 keys[k++] = "IMapView`2"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IReadOnlyDictionary2, systemRuntime);
165                 keys[k++] = "IMap`2"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IDictionary2, systemRuntime);
166                 keys[k++] = "INotifyCollectionChanged"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections_Specialized, StringHandle.VirtualIndex.INotifyCollectionChanged, systemObjectModel);
167                 keys[k++] = "INotifyPropertyChanged"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Data", StringHandle.VirtualIndex.System_ComponentModel, StringHandle.VirtualIndex.INotifyPropertyChanged, systemObjectModel);
168                 keys[k++] = "IReference`1"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.Nullable1, systemRuntime, signatureTreatment: TypeRefSignatureTreatment.ProjectedToValueType);
169                 keys[k++] = "IVectorView`1"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IReadOnlyList1, systemRuntime);
170                 keys[k++] = "IVector`1"; values[v++] = new ProjectionInfo("Windows.Foundation.Collections", StringHandle.VirtualIndex.System_Collections_Generic, StringHandle.VirtualIndex.IList1, systemRuntime);
171                 keys[k++] = "KeyTime"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media.Animation", StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Animation, StringHandle.VirtualIndex.KeyTime, systemRuntimeWindowsUiXaml);
172                 keys[k++] = "Matrix"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media", StringHandle.VirtualIndex.Windows_UI_Xaml_Media, StringHandle.VirtualIndex.Matrix, systemRuntimeWindowsUiXaml);
173                 keys[k++] = "Matrix3D"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media.Media3D", StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Media3D, StringHandle.VirtualIndex.Matrix3D, systemRuntimeWindowsUiXaml);
174                 keys[k++] = "Matrix3x2"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Matrix3x2, systemNumericsVectors);
175                 keys[k++] = "Matrix4x4"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Matrix4x4, systemNumericsVectors);
176                 keys[k++] = "NotifyCollectionChangedAction"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections_Specialized, StringHandle.VirtualIndex.NotifyCollectionChangedAction, systemObjectModel);
177                 keys[k++] = "NotifyCollectionChangedEventArgs"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections_Specialized, StringHandle.VirtualIndex.NotifyCollectionChangedEventArgs, systemObjectModel);
178                 keys[k++] = "NotifyCollectionChangedEventHandler"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System_Collections_Specialized, StringHandle.VirtualIndex.NotifyCollectionChangedEventHandler, systemObjectModel);
179                 keys[k++] = "Plane"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Plane, systemNumericsVectors);
180                 keys[k++] = "Point"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.Windows_Foundation, StringHandle.VirtualIndex.Point, systemRuntimeWindowsRuntime);
181                 keys[k++] = "PropertyChangedEventArgs"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Data", StringHandle.VirtualIndex.System_ComponentModel, StringHandle.VirtualIndex.PropertyChangedEventArgs, systemObjectModel);
182                 keys[k++] = "PropertyChangedEventHandler"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Data", StringHandle.VirtualIndex.System_ComponentModel, StringHandle.VirtualIndex.PropertyChangedEventHandler, systemObjectModel);
183                 keys[k++] = "Quaternion"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Quaternion, systemNumericsVectors);
184                 keys[k++] = "Rect"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.Windows_Foundation, StringHandle.VirtualIndex.Rect, systemRuntimeWindowsRuntime);
185                 keys[k++] = "RepeatBehavior"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media.Animation", StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Animation, StringHandle.VirtualIndex.RepeatBehavior, systemRuntimeWindowsUiXaml);
186                 keys[k++] = "RepeatBehaviorType"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Media.Animation", StringHandle.VirtualIndex.Windows_UI_Xaml_Media_Animation, StringHandle.VirtualIndex.RepeatBehaviorType, systemRuntimeWindowsUiXaml);
187                 keys[k++] = "Size"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.Windows_Foundation, StringHandle.VirtualIndex.Size, systemRuntimeWindowsRuntime);
188                 keys[k++] = "Thickness"; values[v++] = new ProjectionInfo("Windows.UI.Xaml", StringHandle.VirtualIndex.Windows_UI_Xaml, StringHandle.VirtualIndex.Thickness, systemRuntimeWindowsUiXaml);
189                 keys[k++] = "TimeSpan"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.TimeSpan, systemRuntime);
190                 keys[k++] = "TypeName"; values[v++] = new ProjectionInfo("Windows.UI.Xaml.Interop", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.Type, systemRuntime, signatureTreatment: TypeRefSignatureTreatment.ProjectedToClass);
191                 keys[k++] = "Uri"; values[v++] = new ProjectionInfo("Windows.Foundation", StringHandle.VirtualIndex.System, StringHandle.VirtualIndex.Uri, systemRuntime);
192                 keys[k++] = "Vector2"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Vector2, systemNumericsVectors);
193                 keys[k++] = "Vector3"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Vector3, systemNumericsVectors);
194                 keys[k++] = "Vector4"; values[v++] = new ProjectionInfo("Windows.Foundation.Numerics", StringHandle.VirtualIndex.System_Numerics, StringHandle.VirtualIndex.Vector4, systemNumericsVectors);
195 
196                 Debug.Assert(k == keys.Length && v == keys.Length && k == v);
197                 AssertSorted(keys);
198 
199                 s_projectedTypeNames = keys;
200                 s_projectionInfos = values;
201             }
202         }
203 
204         [Conditional("DEBUG")]
AssertSorted(string[] keys)205         private static void AssertSorted(string[] keys)
206         {
207             for (int i = 0; i < keys.Length - 1; i++)
208             {
209                 Debug.Assert(String.CompareOrdinal(keys[i], keys[i + 1]) < 0);
210             }
211         }
212 
213         // test only
GetProjectedTypeNames()214         internal static string[] GetProjectedTypeNames()
215         {
216             InitializeProjectedTypes();
217             return s_projectedTypeNames;
218         }
219 
220         #endregion
221 
TreatmentAndRowId(byte treatment, int rowId)222         private static uint TreatmentAndRowId(byte treatment, int rowId)
223         {
224             return ((uint)treatment << TokenTypeIds.RowIdBitCount) | (uint)rowId;
225         }
226 
227         #region TypeDef
228 
229         [MethodImpl(MethodImplOptions.NoInlining)]
CalculateTypeDefTreatmentAndRowId(TypeDefinitionHandle handle)230         internal uint CalculateTypeDefTreatmentAndRowId(TypeDefinitionHandle handle)
231         {
232             Debug.Assert(_metadataKind != MetadataKind.Ecma335);
233 
234             TypeDefTreatment treatment;
235 
236             TypeAttributes flags = TypeDefTable.GetFlags(handle);
237             EntityHandle extends = TypeDefTable.GetExtends(handle);
238 
239             if ((flags & TypeAttributes.WindowsRuntime) != 0)
240             {
241                 if (_metadataKind == MetadataKind.WindowsMetadata)
242                 {
243                     treatment = GetWellKnownTypeDefinitionTreatment(handle);
244                     if (treatment != TypeDefTreatment.None)
245                     {
246                         return TreatmentAndRowId((byte)treatment, handle.RowId);
247                     }
248 
249                     // Is this an attribute?
250                     if (extends.Kind == HandleKind.TypeReference && IsSystemAttribute((TypeReferenceHandle)extends))
251                     {
252                         treatment = TypeDefTreatment.NormalAttribute;
253                     }
254                     else
255                     {
256                         treatment = TypeDefTreatment.NormalNonAttribute;
257                     }
258                 }
259                 else if (_metadataKind == MetadataKind.ManagedWindowsMetadata && NeedsWinRTPrefix(flags, extends))
260                 {
261                     // WinMDExp emits two versions of RuntimeClasses and Enums:
262                     //
263                     //    public class Foo {}            // the WinRT reference class
264                     //    internal class <CLR>Foo {}     // the implementation class that we want WinRT consumers to ignore
265                     //
266                     // The adapter's job is to undo WinMDExp's transformations. I.e. turn the above into:
267                     //
268                     //    internal class <WinRT>Foo {}   // the WinRT reference class that we want CLR consumers to ignore
269                     //    public class Foo {}            // the implementation class
270                     //
271                     // We only add the <WinRT> prefix here since the WinRT view is the only view that is marked WindowsRuntime
272                     // De-mangling the CLR name is done below.
273 
274 
275                     // tomat: The CLR adapter implements a back-compat quirk: Enums exported with an older WinMDExp have only one version
276                     // not marked with tdSpecialName. These enums should *not* be mangled and flipped to private.
277                     // We don't implement this flag since the WinMDs produced by the older WinMDExp are not used in the wild.
278 
279                     treatment = TypeDefTreatment.PrefixWinRTName;
280                 }
281                 else
282                 {
283                     treatment = TypeDefTreatment.None;
284                 }
285 
286                 // Scan through Custom Attributes on type, looking for interesting bits. We only
287                 // need to do this for RuntimeClasses
288                 if ((treatment == TypeDefTreatment.PrefixWinRTName || treatment == TypeDefTreatment.NormalNonAttribute))
289                 {
290                     if ((flags & TypeAttributes.Interface) == 0
291                         && HasAttribute(handle, "Windows.UI.Xaml", "TreatAsAbstractComposableClassAttribute"))
292                     {
293                         treatment |= TypeDefTreatment.MarkAbstractFlag;
294                     }
295                 }
296             }
297             else if (_metadataKind == MetadataKind.ManagedWindowsMetadata && IsClrImplementationType(handle))
298             {
299                 // <CLR> implementation classes are not marked WindowsRuntime, but still need to be modified
300                 // by the adapter.
301                 treatment = TypeDefTreatment.UnmangleWinRTName;
302             }
303             else
304             {
305                 treatment = TypeDefTreatment.None;
306             }
307 
308             return TreatmentAndRowId((byte)treatment, handle.RowId);
309         }
310 
IsClrImplementationType(TypeDefinitionHandle typeDef)311         private bool IsClrImplementationType(TypeDefinitionHandle typeDef)
312         {
313             var attrs = TypeDefTable.GetFlags(typeDef);
314 
315             if ((attrs & (TypeAttributes.VisibilityMask | TypeAttributes.SpecialName)) != TypeAttributes.SpecialName)
316             {
317                 return false;
318             }
319 
320             return StringHeap.StartsWithRaw(TypeDefTable.GetName(typeDef), ClrPrefix);
321         }
322 
323         #endregion
324 
325         #region TypeRef
326 
CalculateTypeRefTreatmentAndRowId(TypeReferenceHandle handle)327         internal uint CalculateTypeRefTreatmentAndRowId(TypeReferenceHandle handle)
328         {
329             Debug.Assert(_metadataKind != MetadataKind.Ecma335);
330 
331             bool isIDisposable;
332             int projectionIndex = GetProjectionIndexForTypeReference(handle, out isIDisposable);
333             if (projectionIndex >= 0)
334             {
335                 return TreatmentAndRowId((byte)TypeRefTreatment.UseProjectionInfo, projectionIndex);
336             }
337             else
338             {
339                 return TreatmentAndRowId((byte)GetSpecialTypeRefTreatment(handle), handle.RowId);
340             }
341         }
342 
GetSpecialTypeRefTreatment(TypeReferenceHandle handle)343         private TypeRefTreatment GetSpecialTypeRefTreatment(TypeReferenceHandle handle)
344         {
345             if (StringHeap.EqualsRaw(TypeRefTable.GetNamespace(handle), "System"))
346             {
347                 StringHandle name = TypeRefTable.GetName(handle);
348 
349                 if (StringHeap.EqualsRaw(name, "MulticastDelegate"))
350                 {
351                     return TypeRefTreatment.SystemDelegate;
352                 }
353 
354                 if (StringHeap.EqualsRaw(name, "Attribute"))
355                 {
356                     return TypeRefTreatment.SystemAttribute;
357                 }
358             }
359 
360             return TypeRefTreatment.None;
361         }
362 
IsSystemAttribute(TypeReferenceHandle handle)363         private bool IsSystemAttribute(TypeReferenceHandle handle)
364         {
365             return StringHeap.EqualsRaw(TypeRefTable.GetNamespace(handle), "System") &&
366                    StringHeap.EqualsRaw(TypeRefTable.GetName(handle), "Attribute");
367         }
368 
NeedsWinRTPrefix(TypeAttributes flags, EntityHandle extends)369         private bool NeedsWinRTPrefix(TypeAttributes flags, EntityHandle extends)
370         {
371             if ((flags & (TypeAttributes.VisibilityMask | TypeAttributes.Interface)) != TypeAttributes.Public)
372             {
373                 return false;
374             }
375 
376             if (extends.Kind != HandleKind.TypeReference)
377             {
378                 return false;
379             }
380 
381             // Check if the type is a delegate, struct, or attribute
382             TypeReferenceHandle extendsRefHandle = (TypeReferenceHandle)extends;
383             if (StringHeap.EqualsRaw(TypeRefTable.GetNamespace(extendsRefHandle), "System"))
384             {
385                 StringHandle nameHandle = TypeRefTable.GetName(extendsRefHandle);
386                 if (StringHeap.EqualsRaw(nameHandle, "MulticastDelegate")
387                     || StringHeap.EqualsRaw(nameHandle, "ValueType")
388                     || StringHeap.EqualsRaw(nameHandle, "Attribute"))
389                 {
390                     return false;
391                 }
392             }
393             return true;
394         }
395 
396         #endregion
397 
398         #region MethodDef
399 
CalculateMethodDefTreatmentAndRowId(MethodDefinitionHandle methodDef)400         private uint CalculateMethodDefTreatmentAndRowId(MethodDefinitionHandle methodDef)
401         {
402             MethodDefTreatment treatment = MethodDefTreatment.Implementation;
403 
404             TypeDefinitionHandle parentTypeDef = GetDeclaringType(methodDef);
405             TypeAttributes parentFlags = TypeDefTable.GetFlags(parentTypeDef);
406 
407             if ((parentFlags & TypeAttributes.WindowsRuntime) != 0)
408             {
409                 if (IsClrImplementationType(parentTypeDef))
410                 {
411                     treatment = MethodDefTreatment.Implementation;
412                 }
413                 else if (parentFlags.IsNested())
414                 {
415                     treatment = MethodDefTreatment.Implementation;
416                 }
417                 else if ((parentFlags & TypeAttributes.Interface) != 0)
418                 {
419                     treatment = MethodDefTreatment.InterfaceMethod;
420                 }
421                 else if (_metadataKind == MetadataKind.ManagedWindowsMetadata && (parentFlags & TypeAttributes.Public) == 0)
422                 {
423                     treatment = MethodDefTreatment.Implementation;
424                 }
425                 else
426                 {
427                     treatment = MethodDefTreatment.Other;
428 
429                     var parentBaseType = TypeDefTable.GetExtends(parentTypeDef);
430                     if (parentBaseType.Kind == HandleKind.TypeReference)
431                     {
432                         switch (GetSpecialTypeRefTreatment((TypeReferenceHandle)parentBaseType))
433                         {
434                             case TypeRefTreatment.SystemAttribute:
435                                 treatment = MethodDefTreatment.AttributeMethod;
436                                 break;
437 
438                             case TypeRefTreatment.SystemDelegate:
439                                 treatment = MethodDefTreatment.DelegateMethod | MethodDefTreatment.MarkPublicFlag;
440                                 break;
441                         }
442                     }
443                 }
444             }
445 
446             if (treatment == MethodDefTreatment.Other)
447             {
448                 // we want to hide the method if it implements
449                 // only redirected interfaces
450                 // We also want to check if the methodImpl is IClosable.Close,
451                 // so we can change the name
452                 bool seenRedirectedInterfaces = false;
453                 bool seenNonRedirectedInterfaces = false;
454 
455                 bool isIClosableClose = false;
456 
457                 foreach (var methodImplHandle in new MethodImplementationHandleCollection(this, parentTypeDef))
458                 {
459                     MethodImplementation methodImpl = GetMethodImplementation(methodImplHandle);
460                     if (methodImpl.MethodBody == methodDef)
461                     {
462                         EntityHandle declaration = methodImpl.MethodDeclaration;
463 
464                         // See if this MethodImpl implements a redirected interface
465                         // In WinMD, MethodImpl will always use MemberRef and TypeRefs to refer to redirected interfaces,
466                         // even if they are in the same module.
467                         if (declaration.Kind == HandleKind.MemberReference &&
468                             ImplementsRedirectedInterface((MemberReferenceHandle)declaration, out isIClosableClose))
469                         {
470                             seenRedirectedInterfaces = true;
471                             if (isIClosableClose)
472                             {
473                                 // This method implements IClosable.Close
474                                 // Let's rename to IDisposable later
475                                 // Once we know this implements IClosable.Close, we are done
476                                 // looking
477                                 break;
478                             }
479                         }
480                         else
481                         {
482                             // Now we know this implements a non-redirected interface
483                             // But we need to keep looking, just in case we got a methodimpl that
484                             // implements the IClosable.Close method and needs to be renamed
485                             seenNonRedirectedInterfaces = true;
486                         }
487                     }
488                 }
489 
490                 if (isIClosableClose)
491                 {
492                     treatment = MethodDefTreatment.DisposeMethod;
493                 }
494                 else if (seenRedirectedInterfaces && !seenNonRedirectedInterfaces)
495                 {
496                     // Only hide if all the interfaces implemented are redirected
497                     treatment = MethodDefTreatment.HiddenInterfaceImplementation;
498                 }
499             }
500 
501             // If treatment is other, then this is a non-managed WinRT runtime class definition
502             // Find out about various bits that we apply via attributes and name parsing
503             if (treatment == MethodDefTreatment.Other)
504             {
505                 treatment |= GetMethodTreatmentFromCustomAttributes(methodDef);
506             }
507 
508             return TreatmentAndRowId((byte)treatment, methodDef.RowId);
509         }
510 
GetMethodTreatmentFromCustomAttributes(MethodDefinitionHandle methodDef)511         private MethodDefTreatment GetMethodTreatmentFromCustomAttributes(MethodDefinitionHandle methodDef)
512         {
513             MethodDefTreatment treatment = 0;
514 
515             foreach (var caHandle in GetCustomAttributes(methodDef))
516             {
517                 StringHandle namespaceHandle, nameHandle;
518                 if (!GetAttributeTypeNameRaw(caHandle, out namespaceHandle, out nameHandle))
519                 {
520                     continue;
521                 }
522 
523                 Debug.Assert(!namespaceHandle.IsVirtual && !nameHandle.IsVirtual);
524 
525                 if (StringHeap.EqualsRaw(namespaceHandle, "Windows.UI.Xaml"))
526                 {
527                     if (StringHeap.EqualsRaw(nameHandle, "TreatAsPublicMethodAttribute"))
528                     {
529                         treatment |= MethodDefTreatment.MarkPublicFlag;
530                     }
531 
532                     if (StringHeap.EqualsRaw(nameHandle, "TreatAsAbstractMethodAttribute"))
533                     {
534                         treatment |= MethodDefTreatment.MarkAbstractFlag;
535                     }
536                 }
537             }
538 
539             return treatment;
540         }
541 
542         #endregion
543 
544         #region FieldDef
545 
546         /// <summary>
547         /// The backing field of a WinRT enumeration type is not public although the backing fields
548         /// of managed enumerations are. To allow managed languages to directly access this field,
549         /// it is made public by the metadata adapter.
550         /// </summary>
CalculateFieldDefTreatmentAndRowId(FieldDefinitionHandle handle)551         private uint CalculateFieldDefTreatmentAndRowId(FieldDefinitionHandle handle)
552         {
553             var flags = FieldTable.GetFlags(handle);
554             FieldDefTreatment treatment = FieldDefTreatment.None;
555 
556             if ((flags & FieldAttributes.RTSpecialName) != 0 && StringHeap.EqualsRaw(FieldTable.GetName(handle), "value__"))
557             {
558                 TypeDefinitionHandle typeDef = GetDeclaringType(handle);
559 
560                 EntityHandle baseTypeHandle = TypeDefTable.GetExtends(typeDef);
561                 if (baseTypeHandle.Kind == HandleKind.TypeReference)
562                 {
563                     var typeRef = (TypeReferenceHandle)baseTypeHandle;
564 
565                     if (StringHeap.EqualsRaw(TypeRefTable.GetName(typeRef), "Enum") &&
566                         StringHeap.EqualsRaw(TypeRefTable.GetNamespace(typeRef), "System"))
567                     {
568                         treatment = FieldDefTreatment.EnumValue;
569                     }
570                 }
571             }
572 
573             return TreatmentAndRowId((byte)treatment, handle.RowId);
574         }
575 
576         #endregion
577 
578         #region MemberRef
579 
CalculateMemberRefTreatmentAndRowId(MemberReferenceHandle handle)580         private uint CalculateMemberRefTreatmentAndRowId(MemberReferenceHandle handle)
581         {
582             MemberRefTreatment treatment;
583 
584             // We need to rename the MemberRef for IClosable.Close as well
585             // so that the MethodImpl for the Dispose method can be correctly shown
586             // as IDisposable.Dispose instead of IDisposable.Close
587             bool isIDisposable;
588             if (ImplementsRedirectedInterface(handle, out isIDisposable) && isIDisposable)
589             {
590                 treatment = MemberRefTreatment.Dispose;
591             }
592             else
593             {
594                 treatment = MemberRefTreatment.None;
595             }
596 
597             return TreatmentAndRowId((byte)treatment, handle.RowId);
598         }
599 
600         /// <summary>
601         /// We want to know if a given method implements a redirected interface.
602         /// For example, if we are given the method RemoveAt on a class "A"
603         /// which implements the IVector interface (which is redirected
604         /// to IList in .NET) then this method would return true. The most
605         /// likely reason why we would want to know this is that we wish to hide
606         /// (mark private) all methods which implement methods on a redirected
607         /// interface.
608         /// </summary>
609         /// <param name="memberRef">The declaration token for the method</param>
610         /// <param name="isIDisposable">
611         /// Returns true if the redirected interface is <see cref="IDisposable"/>.
612         /// </param>
613         /// <returns>True if the method implements a method on a redirected interface.
614         /// False otherwise.</returns>
ImplementsRedirectedInterface(MemberReferenceHandle memberRef, out bool isIDisposable)615         private bool ImplementsRedirectedInterface(MemberReferenceHandle memberRef, out bool isIDisposable)
616         {
617             isIDisposable = false;
618 
619             EntityHandle parent = MemberRefTable.GetClass(memberRef);
620 
621             TypeReferenceHandle typeRef;
622             if (parent.Kind == HandleKind.TypeReference)
623             {
624                 typeRef = (TypeReferenceHandle)parent;
625             }
626             else if (parent.Kind == HandleKind.TypeSpecification)
627             {
628                 BlobHandle blob = TypeSpecTable.GetSignature((TypeSpecificationHandle)parent);
629                 BlobReader sig = new BlobReader(BlobHeap.GetMemoryBlock(blob));
630 
631                 if (sig.Length < 2 ||
632                     sig.ReadByte() != (byte)CorElementType.ELEMENT_TYPE_GENERICINST ||
633                     sig.ReadByte() != (byte)CorElementType.ELEMENT_TYPE_CLASS)
634                 {
635                     return false;
636                 }
637 
638                 EntityHandle token = sig.ReadTypeHandle();
639                 if (token.Kind != HandleKind.TypeReference)
640                 {
641                     return false;
642                 }
643 
644                 typeRef = (TypeReferenceHandle)token;
645             }
646             else
647             {
648                 return false;
649             }
650 
651             return GetProjectionIndexForTypeReference(typeRef, out isIDisposable) >= 0;
652         }
653 
654         #endregion
655 
656         #region AssemblyRef
657 
FindMscorlibAssemblyRefNoProjection()658         private int FindMscorlibAssemblyRefNoProjection()
659         {
660             for (int i = 1; i <= AssemblyRefTable.NumberOfNonVirtualRows; i++)
661             {
662                 if (StringHeap.EqualsRaw(AssemblyRefTable.GetName(i), "mscorlib"))
663                 {
664                     return i;
665                 }
666             }
667 
668             throw new BadImageFormatException(SR.WinMDMissingMscorlibRef);
669         }
670 
671         #endregion
672 
673         #region CustomAttribute
674 
CalculateCustomAttributeValueTreatment(CustomAttributeHandle handle)675         internal CustomAttributeValueTreatment CalculateCustomAttributeValueTreatment(CustomAttributeHandle handle)
676         {
677             Debug.Assert(_metadataKind != MetadataKind.Ecma335);
678 
679             var parent = CustomAttributeTable.GetParent(handle);
680 
681             // Check for Windows.Foundation.Metadata.AttributeUsageAttribute.
682             // WinMD rules:
683             //   - The attribute is only applicable on TypeDefs.
684             //   - Constructor must be a MemberRef with TypeRef.
685             if (!IsWindowsAttributeUsageAttribute(parent, handle))
686             {
687                 return CustomAttributeValueTreatment.None;
688             }
689 
690             var targetTypeDef = (TypeDefinitionHandle)parent;
691             if (StringHeap.EqualsRaw(TypeDefTable.GetNamespace(targetTypeDef), "Windows.Foundation.Metadata"))
692             {
693                 if (StringHeap.EqualsRaw(TypeDefTable.GetName(targetTypeDef), "VersionAttribute"))
694                 {
695                     return CustomAttributeValueTreatment.AttributeUsageVersionAttribute;
696                 }
697 
698                 if (StringHeap.EqualsRaw(TypeDefTable.GetName(targetTypeDef), "DeprecatedAttribute"))
699                 {
700                     return CustomAttributeValueTreatment.AttributeUsageDeprecatedAttribute;
701                 }
702             }
703 
704             bool allowMultiple = HasAttribute(targetTypeDef, "Windows.Foundation.Metadata", "AllowMultipleAttribute");
705             return allowMultiple ? CustomAttributeValueTreatment.AttributeUsageAllowMultiple : CustomAttributeValueTreatment.AttributeUsageAllowSingle;
706         }
707 
IsWindowsAttributeUsageAttribute(EntityHandle targetType, CustomAttributeHandle attributeHandle)708         private bool IsWindowsAttributeUsageAttribute(EntityHandle targetType, CustomAttributeHandle attributeHandle)
709         {
710             // Check for Windows.Foundation.Metadata.AttributeUsageAttribute.
711             // WinMD rules:
712             //   - The attribute is only applicable on TypeDefs.
713             //   - Constructor must be a MemberRef with TypeRef.
714 
715             if (targetType.Kind != HandleKind.TypeDefinition)
716             {
717                 return false;
718             }
719 
720             var attributeCtor = CustomAttributeTable.GetConstructor(attributeHandle);
721             if (attributeCtor.Kind != HandleKind.MemberReference)
722             {
723                 return false;
724             }
725 
726             var attributeType = MemberRefTable.GetClass((MemberReferenceHandle)attributeCtor);
727             if (attributeType.Kind != HandleKind.TypeReference)
728             {
729                 return false;
730             }
731 
732             var attributeTypeRef = (TypeReferenceHandle)attributeType;
733             return StringHeap.EqualsRaw(TypeRefTable.GetName(attributeTypeRef), "AttributeUsageAttribute") &&
734                    StringHeap.EqualsRaw(TypeRefTable.GetNamespace(attributeTypeRef), "Windows.Foundation.Metadata");
735         }
736 
HasAttribute(EntityHandle token, string asciiNamespaceName, string asciiTypeName)737         private bool HasAttribute(EntityHandle token, string asciiNamespaceName, string asciiTypeName)
738         {
739             foreach (var caHandle in GetCustomAttributes(token))
740             {
741                 StringHandle namespaceName, typeName;
742                 if (GetAttributeTypeNameRaw(caHandle, out namespaceName, out typeName) &&
743                     StringHeap.EqualsRaw(typeName, asciiTypeName) &&
744                     StringHeap.EqualsRaw(namespaceName, asciiNamespaceName))
745                 {
746                     return true;
747                 }
748             }
749 
750             return false;
751         }
752 
GetAttributeTypeNameRaw(CustomAttributeHandle caHandle, out StringHandle namespaceName, out StringHandle typeName)753         private bool GetAttributeTypeNameRaw(CustomAttributeHandle caHandle, out StringHandle namespaceName, out StringHandle typeName)
754         {
755             namespaceName = typeName = default(StringHandle);
756 
757             EntityHandle typeDefOrRef = GetAttributeTypeRaw(caHandle);
758             if (typeDefOrRef.IsNil)
759             {
760                 return false;
761             }
762 
763             if (typeDefOrRef.Kind == HandleKind.TypeReference)
764             {
765                 TypeReferenceHandle typeRef = (TypeReferenceHandle)typeDefOrRef;
766                 var resolutionScope = TypeRefTable.GetResolutionScope(typeRef);
767 
768                 if (!resolutionScope.IsNil && resolutionScope.Kind == HandleKind.TypeReference)
769                 {
770                     // we don't need to handle nested types
771                     return false;
772                 }
773 
774                 // other resolution scopes don't affect full name
775 
776                 typeName = TypeRefTable.GetName(typeRef);
777                 namespaceName = TypeRefTable.GetNamespace(typeRef);
778             }
779             else if (typeDefOrRef.Kind == HandleKind.TypeDefinition)
780             {
781                 TypeDefinitionHandle typeDef = (TypeDefinitionHandle)typeDefOrRef;
782 
783                 if (TypeDefTable.GetFlags(typeDef).IsNested())
784                 {
785                     // we don't need to handle nested types
786                     return false;
787                 }
788 
789                 typeName = TypeDefTable.GetName(typeDef);
790                 namespaceName = TypeDefTable.GetNamespace(typeDef);
791             }
792             else
793             {
794                 // invalid metadata
795                 return false;
796             }
797 
798             return true;
799         }
800 
801         /// <summary>
802         /// Returns the type definition or reference handle of the attribute type.
803         /// </summary>
804         /// <returns><see cref="TypeDefinitionHandle"/> or <see cref="TypeReferenceHandle"/> or nil token if the metadata is invalid and the type can't be determined.</returns>
GetAttributeTypeRaw(CustomAttributeHandle handle)805         private EntityHandle GetAttributeTypeRaw(CustomAttributeHandle handle)
806         {
807             var ctor = CustomAttributeTable.GetConstructor(handle);
808 
809             if (ctor.Kind == HandleKind.MethodDefinition)
810             {
811                 return GetDeclaringType((MethodDefinitionHandle)ctor);
812             }
813 
814             if (ctor.Kind == HandleKind.MemberReference)
815             {
816                 // In general the parent can be MethodDef, ModuleRef, TypeDef, TypeRef, or TypeSpec.
817                 // For attributes only TypeDef and TypeRef are applicable.
818                 EntityHandle typeDefOrRef = MemberRefTable.GetClass((MemberReferenceHandle)ctor);
819                 HandleKind handleType = typeDefOrRef.Kind;
820 
821                 if (handleType == HandleKind.TypeReference || handleType == HandleKind.TypeDefinition)
822                 {
823                     return typeDefOrRef;
824                 }
825             }
826 
827             return default(EntityHandle);
828         }
829         #endregion
830     }
831 }
832