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