< Summary

Line coverage
0%
Covered lines: 0
Uncovered lines: 256
Coverable lines: 256
Total lines: 433
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 169
Branch coverage: 0%
Method coverage

Feature is only available for sponsors

Upgrade to PRO version

Metrics

File(s)

https://raw.githubusercontent.com/dotnet/runtime/811a7eabb75c42db53440e8ba3f60c07511cfd1f/src/libraries/System.Reflection.Metadata/src/System/Reflection/Metadata/Ecma335/MetadataReaderExtensions.cs

#LineLine coverage
 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
 4using System.Collections.Generic;
 5using System.Diagnostics;
 6using System.Reflection.Internal;
 7
 8namespace System.Reflection.Metadata.Ecma335
 9{
 10    /// <summary>
 11    /// Provides extension methods for working with certain raw elements of the ECMA-335 metadata tables and heaps.
 12    /// </summary>
 13    public static class MetadataReaderExtensions
 14    {
 15        /// <summary>
 16        /// Returns the number of rows in the specified table.
 17        /// </summary>
 18        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 19        /// <exception cref="ArgumentOutOfRangeException"><paramref name="tableIndex"/> is not a valid table index.</exc
 20        public static int GetTableRowCount(this MetadataReader reader, TableIndex tableIndex)
 021        {
 022            if (reader is null)
 023            {
 024                Throw.ArgumentNull(nameof(reader));
 25            }
 26
 027            if ((int)tableIndex >= MetadataTokens.TableCount)
 028            {
 029                Throw.TableIndexOutOfRange();
 30            }
 31
 032            return reader.TableRowCounts[(int)tableIndex];
 033        }
 34
 35        /// <summary>
 36        /// Returns the size of a row in the specified table.
 37        /// </summary>
 38        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 39        /// <exception cref="ArgumentOutOfRangeException"><paramref name="tableIndex"/> is not a valid table index.</exc
 40        public static int GetTableRowSize(this MetadataReader reader, TableIndex tableIndex)
 041        {
 042            if (reader is null)
 043            {
 044                Throw.ArgumentNull(nameof(reader));
 45            }
 46
 047            return tableIndex switch
 048            {
 049                TableIndex.Module => reader.ModuleTable.RowSize,
 050                TableIndex.TypeRef => reader.TypeRefTable.RowSize,
 051                TableIndex.TypeDef => reader.TypeDefTable.RowSize,
 052                TableIndex.FieldPtr => reader.FieldPtrTable.RowSize,
 053                TableIndex.Field => reader.FieldTable.RowSize,
 054                TableIndex.MethodPtr => reader.MethodPtrTable.RowSize,
 055                TableIndex.MethodDef => reader.MethodDefTable.RowSize,
 056                TableIndex.ParamPtr => reader.ParamPtrTable.RowSize,
 057                TableIndex.Param => reader.ParamTable.RowSize,
 058                TableIndex.InterfaceImpl => reader.InterfaceImplTable.RowSize,
 059                TableIndex.MemberRef => reader.MemberRefTable.RowSize,
 060                TableIndex.Constant => reader.ConstantTable.RowSize,
 061                TableIndex.CustomAttribute => reader.CustomAttributeTable.RowSize,
 062                TableIndex.FieldMarshal => reader.FieldMarshalTable.RowSize,
 063                TableIndex.DeclSecurity => reader.DeclSecurityTable.RowSize,
 064                TableIndex.ClassLayout => reader.ClassLayoutTable.RowSize,
 065                TableIndex.FieldLayout => reader.FieldLayoutTable.RowSize,
 066                TableIndex.StandAloneSig => reader.StandAloneSigTable.RowSize,
 067                TableIndex.EventMap => reader.EventMapTable.RowSize,
 068                TableIndex.EventPtr => reader.EventPtrTable.RowSize,
 069                TableIndex.Event => reader.EventTable.RowSize,
 070                TableIndex.PropertyMap => reader.PropertyMapTable.RowSize,
 071                TableIndex.PropertyPtr => reader.PropertyPtrTable.RowSize,
 072                TableIndex.Property => reader.PropertyTable.RowSize,
 073                TableIndex.MethodSemantics => reader.MethodSemanticsTable.RowSize,
 074                TableIndex.MethodImpl => reader.MethodImplTable.RowSize,
 075                TableIndex.ModuleRef => reader.ModuleRefTable.RowSize,
 076                TableIndex.TypeSpec => reader.TypeSpecTable.RowSize,
 077                TableIndex.ImplMap => reader.ImplMapTable.RowSize,
 078                TableIndex.FieldRva => reader.FieldRvaTable.RowSize,
 079                TableIndex.EncLog => reader.EncLogTable.RowSize,
 080                TableIndex.EncMap => reader.EncMapTable.RowSize,
 081                TableIndex.Assembly => reader.AssemblyTable.RowSize,
 082                TableIndex.AssemblyProcessor => reader.AssemblyProcessorTable.RowSize,
 083                TableIndex.AssemblyOS => reader.AssemblyOSTable.RowSize,
 084                TableIndex.AssemblyRef => reader.AssemblyRefTable.RowSize,
 085                TableIndex.AssemblyRefProcessor => reader.AssemblyRefProcessorTable.RowSize,
 086                TableIndex.AssemblyRefOS => reader.AssemblyRefOSTable.RowSize,
 087                TableIndex.File => reader.FileTable.RowSize,
 088                TableIndex.ExportedType => reader.ExportedTypeTable.RowSize,
 089                TableIndex.ManifestResource => reader.ManifestResourceTable.RowSize,
 090                TableIndex.NestedClass => reader.NestedClassTable.RowSize,
 091                TableIndex.GenericParam => reader.GenericParamTable.RowSize,
 092                TableIndex.MethodSpec => reader.MethodSpecTable.RowSize,
 093                TableIndex.GenericParamConstraint => reader.GenericParamConstraintTable.RowSize,
 094
 095                // debug tables
 096                TableIndex.Document => reader.DocumentTable.RowSize,
 097                TableIndex.MethodDebugInformation => reader.MethodDebugInformationTable.RowSize,
 098                TableIndex.LocalScope => reader.LocalScopeTable.RowSize,
 099                TableIndex.LocalVariable => reader.LocalVariableTable.RowSize,
 0100                TableIndex.LocalConstant => reader.LocalConstantTable.RowSize,
 0101                TableIndex.ImportScope => reader.ImportScopeTable.RowSize,
 0102                TableIndex.StateMachineMethod => reader.StateMachineMethodTable.RowSize,
 0103                TableIndex.CustomDebugInformation => reader.CustomDebugInformationTable.RowSize,
 0104
 0105                _ => throw new ArgumentOutOfRangeException(nameof(tableIndex)),
 0106            };
 0107        }
 108
 109        /// <summary>
 110        /// Returns the offset from the start of metadata to the specified table.
 111        /// </summary>
 112        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 113        /// <exception cref="ArgumentOutOfRangeException"><paramref name="tableIndex"/> is not a valid table index.</exc
 114        public static unsafe int GetTableMetadataOffset(this MetadataReader reader, TableIndex tableIndex)
 0115        {
 0116            if (reader is null)
 0117            {
 0118                Throw.ArgumentNull(nameof(reader));
 119            }
 120
 0121            return (int)(reader.GetTableMetadataBlock(tableIndex).Pointer - reader.Block.Pointer);
 0122        }
 123
 124        private static MemoryBlock GetTableMetadataBlock(this MetadataReader reader, TableIndex tableIndex)
 0125        {
 0126            Debug.Assert(reader != null);
 127
 0128            return tableIndex switch
 0129            {
 0130                TableIndex.Module => reader.ModuleTable.Block,
 0131                TableIndex.TypeRef => reader.TypeRefTable.Block,
 0132                TableIndex.TypeDef => reader.TypeDefTable.Block,
 0133                TableIndex.FieldPtr => reader.FieldPtrTable.Block,
 0134                TableIndex.Field => reader.FieldTable.Block,
 0135                TableIndex.MethodPtr => reader.MethodPtrTable.Block,
 0136                TableIndex.MethodDef => reader.MethodDefTable.Block,
 0137                TableIndex.ParamPtr => reader.ParamPtrTable.Block,
 0138                TableIndex.Param => reader.ParamTable.Block,
 0139                TableIndex.InterfaceImpl => reader.InterfaceImplTable.Block,
 0140                TableIndex.MemberRef => reader.MemberRefTable.Block,
 0141                TableIndex.Constant => reader.ConstantTable.Block,
 0142                TableIndex.CustomAttribute => reader.CustomAttributeTable.Block,
 0143                TableIndex.FieldMarshal => reader.FieldMarshalTable.Block,
 0144                TableIndex.DeclSecurity => reader.DeclSecurityTable.Block,
 0145                TableIndex.ClassLayout => reader.ClassLayoutTable.Block,
 0146                TableIndex.FieldLayout => reader.FieldLayoutTable.Block,
 0147                TableIndex.StandAloneSig => reader.StandAloneSigTable.Block,
 0148                TableIndex.EventMap => reader.EventMapTable.Block,
 0149                TableIndex.EventPtr => reader.EventPtrTable.Block,
 0150                TableIndex.Event => reader.EventTable.Block,
 0151                TableIndex.PropertyMap => reader.PropertyMapTable.Block,
 0152                TableIndex.PropertyPtr => reader.PropertyPtrTable.Block,
 0153                TableIndex.Property => reader.PropertyTable.Block,
 0154                TableIndex.MethodSemantics => reader.MethodSemanticsTable.Block,
 0155                TableIndex.MethodImpl => reader.MethodImplTable.Block,
 0156                TableIndex.ModuleRef => reader.ModuleRefTable.Block,
 0157                TableIndex.TypeSpec => reader.TypeSpecTable.Block,
 0158                TableIndex.ImplMap => reader.ImplMapTable.Block,
 0159                TableIndex.FieldRva => reader.FieldRvaTable.Block,
 0160                TableIndex.EncLog => reader.EncLogTable.Block,
 0161                TableIndex.EncMap => reader.EncMapTable.Block,
 0162                TableIndex.Assembly => reader.AssemblyTable.Block,
 0163                TableIndex.AssemblyProcessor => reader.AssemblyProcessorTable.Block,
 0164                TableIndex.AssemblyOS => reader.AssemblyOSTable.Block,
 0165                TableIndex.AssemblyRef => reader.AssemblyRefTable.Block,
 0166                TableIndex.AssemblyRefProcessor => reader.AssemblyRefProcessorTable.Block,
 0167                TableIndex.AssemblyRefOS => reader.AssemblyRefOSTable.Block,
 0168                TableIndex.File => reader.FileTable.Block,
 0169                TableIndex.ExportedType => reader.ExportedTypeTable.Block,
 0170                TableIndex.ManifestResource => reader.ManifestResourceTable.Block,
 0171                TableIndex.NestedClass => reader.NestedClassTable.Block,
 0172                TableIndex.GenericParam => reader.GenericParamTable.Block,
 0173                TableIndex.MethodSpec => reader.MethodSpecTable.Block,
 0174                TableIndex.GenericParamConstraint => reader.GenericParamConstraintTable.Block,
 0175
 0176                // debug tables
 0177                TableIndex.Document => reader.DocumentTable.Block,
 0178                TableIndex.MethodDebugInformation => reader.MethodDebugInformationTable.Block,
 0179                TableIndex.LocalScope => reader.LocalScopeTable.Block,
 0180                TableIndex.LocalVariable => reader.LocalVariableTable.Block,
 0181                TableIndex.LocalConstant => reader.LocalConstantTable.Block,
 0182                TableIndex.ImportScope => reader.ImportScopeTable.Block,
 0183                TableIndex.StateMachineMethod => reader.StateMachineMethodTable.Block,
 0184                TableIndex.CustomDebugInformation => reader.CustomDebugInformationTable.Block,
 0185
 0186                _ => throw new ArgumentOutOfRangeException(nameof(tableIndex)),
 0187            };
 0188        }
 189
 190        /// <summary>
 191        /// Returns the size of the specified heap.
 192        /// </summary>
 193        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 194        /// <exception cref="ArgumentOutOfRangeException"><paramref name="heapIndex"/> is not a valid heap index.</excep
 195        public static int GetHeapSize(this MetadataReader reader, HeapIndex heapIndex)
 0196        {
 0197            if (reader is null)
 0198            {
 0199                Throw.ArgumentNull(nameof(reader));
 200            }
 201
 0202            return reader.GetMetadataBlock(heapIndex).Length;
 0203        }
 204
 205        /// <summary>
 206        /// Returns the offset from the start of metadata to the specified heap.
 207        /// </summary>
 208        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 209        /// <exception cref="ArgumentOutOfRangeException"><paramref name="heapIndex"/> is not a valid heap index.</excep
 210        public static unsafe int GetHeapMetadataOffset(this MetadataReader reader, HeapIndex heapIndex)
 0211        {
 0212            if (reader is null)
 0213            {
 0214                Throw.ArgumentNull(nameof(reader));
 215            }
 216
 0217            return (int)(reader.GetMetadataBlock(heapIndex).Pointer - reader.Block.Pointer);
 0218        }
 219
 220        /// <summary>
 221        /// Returns the size of the specified heap.
 222        /// </summary>
 223        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 224        /// <exception cref="ArgumentOutOfRangeException"><paramref name="heapIndex"/> is not a valid heap index.</excep
 225        private static MemoryBlock GetMetadataBlock(this MetadataReader reader, HeapIndex heapIndex)
 0226        {
 0227            Debug.Assert(reader != null);
 228
 0229            return heapIndex switch
 0230            {
 0231                HeapIndex.UserString => reader.UserStringHeap.Block,
 0232                HeapIndex.String => reader.StringHeap.Block,
 0233                HeapIndex.Blob => reader.BlobHeap.Block,
 0234                HeapIndex.Guid => reader.GuidHeap.Block,
 0235                _ => throw new ArgumentOutOfRangeException(nameof(heapIndex)),
 0236            };
 0237        }
 238
 239        /// <summary>
 240        /// Returns the a handle to the UserString that follows the given one in the UserString heap or a nil handle if 
 241        /// </summary>
 242        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 243        public static UserStringHandle GetNextHandle(this MetadataReader reader, UserStringHandle handle)
 0244        {
 0245            if (reader is null)
 0246            {
 0247                Throw.ArgumentNull(nameof(reader));
 248            }
 249
 0250            return reader.UserStringHeap.GetNextHandle(handle);
 0251        }
 252
 253        /// <summary>
 254        /// Returns the a handle to the Blob that follows the given one in the Blob heap or a nil handle if it is the la
 255        /// </summary>
 256        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 257        public static BlobHandle GetNextHandle(this MetadataReader reader, BlobHandle handle)
 0258        {
 0259            if (reader is null)
 0260            {
 0261                Throw.ArgumentNull(nameof(reader));
 262            }
 263
 0264            return reader.BlobHeap.GetNextHandle(handle);
 0265        }
 266
 267        /// <summary>
 268        /// Returns the a handle to the String that follows the given one in the String heap or a nil handle if it is th
 269        /// </summary>
 270        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 271        public static StringHandle GetNextHandle(this MetadataReader reader, StringHandle handle)
 0272        {
 0273            if (reader is null)
 0274            {
 0275                Throw.ArgumentNull(nameof(reader));
 276            }
 277
 0278            return reader.StringHeap.GetNextHandle(handle);
 0279        }
 280
 281        /// <summary>
 282        /// Enumerates entries of EnC log.
 283        /// </summary>
 284        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 285        public static IEnumerable<EditAndContinueLogEntry> GetEditAndContinueLogEntries(this MetadataReader reader)
 0286        {
 0287            if (reader is null)
 0288            {
 0289                Throw.ArgumentNull(nameof(reader));
 290            }
 291
 0292            return Core(reader);
 293
 294            static IEnumerable<EditAndContinueLogEntry> Core(MetadataReader reader)
 0295            {
 0296                for (int rid = 1; rid <= reader.EncLogTable.NumberOfRows; rid++)
 0297                {
 0298                    yield return new EditAndContinueLogEntry(
 0299                        new EntityHandle(reader.EncLogTable.GetToken(rid)),
 0300                        reader.EncLogTable.GetFuncCode(rid));
 0301                }
 0302            }
 0303        }
 304
 305        /// <summary>
 306        /// Enumerates entries of EnC map.
 307        /// </summary>
 308        /// <exception cref="ArgumentNullException"><paramref name="reader"/> is null.</exception>
 309        public static IEnumerable<EntityHandle> GetEditAndContinueMapEntries(this MetadataReader reader)
 0310        {
 0311            if (reader is null)
 0312            {
 0313                Throw.ArgumentNull(nameof(reader));
 314            }
 315
 0316            return Core(reader);
 317
 318            static IEnumerable<EntityHandle> Core(MetadataReader reader)
 0319            {
 0320                for (int rid = 1; rid <= reader.EncMapTable.NumberOfRows; rid++)
 0321                {
 0322                    yield return new EntityHandle(reader.EncMapTable.GetToken(rid));
 0323                }
 0324            }
 0325        }
 326
 327        /// <summary>
 328        /// Enumerate types that define one or more properties.
 329        /// </summary>
 330        /// <returns>
 331        /// The resulting sequence corresponds exactly to entries in PropertyMap table,
 332        /// i.e. n-th returned <see cref="TypeDefinitionHandle"/> is stored in n-th row of PropertyMap.
 333        /// </returns>
 334        public static IEnumerable<TypeDefinitionHandle> GetTypesWithProperties(this MetadataReader reader)
 0335        {
 0336            if (reader is null)
 0337            {
 0338                Throw.ArgumentNull(nameof(reader));
 339            }
 340
 0341            return Core(reader);
 342
 343            static IEnumerable<TypeDefinitionHandle> Core(MetadataReader reader)
 0344            {
 0345                for (int rid = 1; rid <= reader.PropertyMapTable.NumberOfRows; rid++)
 0346                {
 0347                    yield return reader.PropertyMapTable.GetParentType(rid);
 0348                }
 0349            }
 0350        }
 351
 352        /// <summary>
 353        /// Enumerate types that define one or more events.
 354        /// </summary>
 355        /// <returns>
 356        /// The resulting sequence corresponds exactly to entries in EventMap table,
 357        /// i.e. n-th returned <see cref="TypeDefinitionHandle"/> is stored in n-th row of EventMap.
 358        /// </returns>
 359        public static IEnumerable<TypeDefinitionHandle> GetTypesWithEvents(this MetadataReader reader)
 0360        {
 0361            if (reader is null)
 0362            {
 0363                Throw.ArgumentNull(nameof(reader));
 364            }
 365
 0366            return Core(reader);
 367
 368            static IEnumerable<TypeDefinitionHandle> Core(MetadataReader reader)
 0369            {
 0370                for (int rid = 1; rid <= reader.EventMapTable.NumberOfRows; rid++)
 0371                {
 0372                    yield return reader.EventMapTable.GetParentType(rid);
 0373                }
 0374            }
 0375        }
 376
 377        /// <summary>
 378        /// Given a type handle and a raw type kind found in a signature blob determines whether the target type is a va
 379        /// </summary>
 380        public static SignatureTypeKind ResolveSignatureTypeKind(this MetadataReader reader, EntityHandle typeHandle, by
 0381        {
 0382            if (reader is null)
 0383            {
 0384                Throw.ArgumentNull(nameof(reader));
 385            }
 386
 0387            var typeKind = (SignatureTypeKind)rawTypeKind;
 388
 0389            switch (typeKind)
 390            {
 391                case SignatureTypeKind.Unknown:
 0392                    return SignatureTypeKind.Unknown;
 393
 394                case SignatureTypeKind.Class:
 395                case SignatureTypeKind.ValueType:
 0396                    break;
 397
 398                default:
 399                    // If read from metadata by the decoder the value would have been checked already.
 400                    // So it is the callers error to pass in an invalid value, not bad metadata.
 0401                    throw new ArgumentOutOfRangeException(nameof(rawTypeKind));
 402            }
 403
 0404            switch (typeHandle.Kind)
 405            {
 406                case HandleKind.TypeDefinition:
 407                    // WinRT projections don't apply to TypeDefs
 0408                    return typeKind;
 409
 410                case HandleKind.TypeReference:
 0411                    var treatment = reader.GetTypeReference((TypeReferenceHandle)typeHandle).SignatureTreatment;
 0412                    return treatment switch
 0413                    {
 0414                        TypeRefSignatureTreatment.ProjectedToClass => SignatureTypeKind.Class,
 0415                        TypeRefSignatureTreatment.ProjectedToValueType => SignatureTypeKind.ValueType,
 0416                        TypeRefSignatureTreatment.None => typeKind,
 0417                        _ => throw ExceptionUtilities.UnexpectedValue(treatment),
 0418                    };
 419                case HandleKind.TypeSpecification:
 420                    // TODO: https://github.com/dotnet/runtime/issues/17146
 421                    // We need more work here in differentiating case because instantiations can project class
 422                    // to value type as in IReference<T> -> Nullable<T>. Unblocking Roslyn work where the differentiatio
 423                    // feature is not used. Note that the use-case of custom-mods will not hit this because there is no
 424                    // CLASS | VALUETYPE before the modifier token and so it always comes in unresolved.
 0425                    return SignatureTypeKind.Unknown;
 426
 427                default:
 0428                    throw new ArgumentOutOfRangeException(nameof(typeHandle), SR.Format(SR.UnexpectedHandleKind, typeHan
 429            }
 0430        }
 431    }
 432}
 433