< Summary

Information
Line coverage
0%
Covered lines: 0
Uncovered lines: 161
Coverable lines: 161
Total lines: 349
Line coverage: 0%
Branch coverage
0%
Covered branches: 0
Total branches: 75
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/SignatureDecoder.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.Immutable;
 5using System.Diagnostics;
 6
 7namespace System.Reflection.Metadata.Ecma335
 8{
 9    /// <summary>
 10    /// Decodes signature blobs.
 11    /// See Metadata Specification section II.23.2: Blobs and signatures.
 12    /// </summary>
 13    public readonly struct SignatureDecoder<TType, TGenericContext>
 14    {
 15        private readonly ISignatureTypeProvider<TType, TGenericContext> _provider;
 16        private readonly MetadataReader _metadataReaderOpt;
 17        private readonly TGenericContext _genericContext;
 18
 19        /// <summary>
 20        /// Creates a new SignatureDecoder.
 21        /// </summary>
 22        /// <param name="provider">The provider used to obtain type symbols as the signature is decoded.</param>
 23        /// <param name="metadataReader">
 24        /// The metadata reader from which the signature was obtained. It may be null if the given provider allows it.
 25        /// </param>
 26        /// <param name="genericContext">
 27        /// Additional context needed to resolve generic parameters.
 28        /// </param>
 29        public SignatureDecoder(
 30            ISignatureTypeProvider<TType, TGenericContext> provider,
 31            MetadataReader metadataReader,
 32            TGenericContext genericContext)
 033        {
 034            if (provider is null)
 035            {
 036                Throw.ArgumentNull(nameof(provider));
 37            }
 38
 039            _metadataReaderOpt = metadataReader;
 040            _provider = provider;
 041            _genericContext = genericContext;
 042        }
 43
 44        /// <summary>
 45        /// Decodes a type embedded in a signature and advances the reader past the type.
 46        /// </summary>
 47        /// <param name="blobReader">The blob reader positioned at the leading SignatureTypeCode</param>
 48        /// <param name="allowTypeSpecifications">Allow a <see cref="TypeSpecificationHandle"/> to follow a (CLASS | VAL
 49        /// At present, the only context where that would be valid is in a LocalConstantSig as defined by the Portable P
 50        /// </param>
 51        /// <returns>The decoded type.</returns>
 52        /// <exception cref="System.BadImageFormatException">The reader was not positioned at a valid signature type.</e
 53        public TType DecodeType(ref BlobReader blobReader, bool allowTypeSpecifications = false)
 054        {
 055            return DecodeType(ref blobReader, allowTypeSpecifications, blobReader.ReadCompressedInteger());
 056        }
 57
 58        private TType DecodeType(ref BlobReader blobReader, bool allowTypeSpecifications, int typeCode)
 059        {
 60            TType elementType;
 61            int index;
 62
 063            switch (typeCode)
 64            {
 65                case (int)SignatureTypeCode.Boolean:
 66                case (int)SignatureTypeCode.Char:
 67                case (int)SignatureTypeCode.SByte:
 68                case (int)SignatureTypeCode.Byte:
 69                case (int)SignatureTypeCode.Int16:
 70                case (int)SignatureTypeCode.UInt16:
 71                case (int)SignatureTypeCode.Int32:
 72                case (int)SignatureTypeCode.UInt32:
 73                case (int)SignatureTypeCode.Int64:
 74                case (int)SignatureTypeCode.UInt64:
 75                case (int)SignatureTypeCode.Single:
 76                case (int)SignatureTypeCode.Double:
 77                case (int)SignatureTypeCode.IntPtr:
 78                case (int)SignatureTypeCode.UIntPtr:
 79                case (int)SignatureTypeCode.Object:
 80                case (int)SignatureTypeCode.String:
 81                case (int)SignatureTypeCode.Void:
 82                case (int)SignatureTypeCode.TypedReference:
 083                    return _provider.GetPrimitiveType((PrimitiveTypeCode)typeCode);
 84
 85                case (int)SignatureTypeCode.Pointer:
 086                    elementType = DecodeType(ref blobReader);
 087                    return _provider.GetPointerType(elementType);
 88
 89                case (int)SignatureTypeCode.ByReference:
 090                    elementType = DecodeType(ref blobReader);
 091                    return _provider.GetByReferenceType(elementType);
 92
 93                case (int)SignatureTypeCode.Pinned:
 094                    elementType = DecodeType(ref blobReader);
 095                    return _provider.GetPinnedType(elementType);
 96
 97                case (int)SignatureTypeCode.SZArray:
 098                    elementType = DecodeType(ref blobReader);
 099                    return _provider.GetSZArrayType(elementType);
 100
 101                case (int)SignatureTypeCode.FunctionPointer:
 0102                    MethodSignature<TType> methodSignature = DecodeMethodSignature(ref blobReader);
 0103                    return _provider.GetFunctionPointerType(methodSignature);
 104
 105                case (int)SignatureTypeCode.Array:
 0106                    return DecodeArrayType(ref blobReader);
 107
 108                case (int)SignatureTypeCode.RequiredModifier:
 0109                    return DecodeModifiedType(ref blobReader, isRequired: true);
 110
 111                case (int)SignatureTypeCode.OptionalModifier:
 0112                    return DecodeModifiedType(ref blobReader, isRequired: false);
 113
 114                case (int)SignatureTypeCode.GenericTypeInstance:
 0115                    return DecodeGenericTypeInstance(ref blobReader);
 116
 117                case (int)SignatureTypeCode.GenericTypeParameter:
 0118                    index = blobReader.ReadCompressedInteger();
 0119                    return _provider.GetGenericTypeParameter(_genericContext, index);
 120
 121                case (int)SignatureTypeCode.GenericMethodParameter:
 0122                    index = blobReader.ReadCompressedInteger();
 0123                    return _provider.GetGenericMethodParameter(_genericContext, index);
 124
 125                case (int)SignatureTypeKind.Class:
 126                case (int)SignatureTypeKind.ValueType:
 0127                    return DecodeTypeHandle(ref blobReader, (byte)typeCode, allowTypeSpecifications);
 128
 129                default:
 0130                    throw new BadImageFormatException(SR.Format(SR.UnexpectedSignatureTypeCode, typeCode));
 131            }
 0132        }
 133
 134        /// <summary>
 135        /// Decodes a list of types, with at least one instance that is preceded by its count as a compressed integer.
 136        /// </summary>
 137        private ImmutableArray<TType> DecodeTypeSequence(ref BlobReader blobReader)
 0138        {
 0139            int count = blobReader.ReadCompressedInteger();
 0140            if (count == 0)
 0141            {
 142                // This method is used for Local signatures and method specs, neither of which can have
 143                // 0 elements. Parameter sequences can have 0 elements, but they are handled separately
 144                // to deal with the sentinel/varargs case.
 0145                throw new BadImageFormatException(SR.SignatureTypeSequenceMustHaveAtLeastOneElement);
 146            }
 147
 0148            var types = ImmutableArray.CreateBuilder<TType>(count);
 149
 0150            for (int i = 0; i < count; i++)
 0151            {
 0152                types.Add(DecodeType(ref blobReader));
 0153            }
 154
 0155            return types.MoveToImmutable();
 0156        }
 157
 158        /// <summary>
 159        /// Decodes a method (definition, reference, or standalone) or property signature blob.
 160        /// </summary>
 161        /// <param name="blobReader">BlobReader positioned at a method signature.</param>
 162        /// <returns>The decoded method signature.</returns>
 163        /// <exception cref="System.BadImageFormatException">The method signature is invalid.</exception>
 164        public MethodSignature<TType> DecodeMethodSignature(ref BlobReader blobReader)
 0165        {
 0166            SignatureHeader header = blobReader.ReadSignatureHeader();
 0167            CheckMethodOrPropertyHeader(header);
 168
 0169            int genericParameterCount = 0;
 0170            if (header.IsGeneric)
 0171            {
 0172                genericParameterCount = blobReader.ReadCompressedInteger();
 0173            }
 174
 0175            int parameterCount = blobReader.ReadCompressedInteger();
 0176            TType returnType = DecodeType(ref blobReader);
 177            ImmutableArray<TType> parameterTypes;
 178            int requiredParameterCount;
 179
 0180            if (parameterCount == 0)
 0181            {
 0182                requiredParameterCount = 0;
 0183                parameterTypes = ImmutableArray<TType>.Empty;
 0184            }
 185            else
 0186            {
 0187                var parameterBuilder = ImmutableArray.CreateBuilder<TType>(parameterCount);
 188                int parameterIndex;
 189
 0190                for (parameterIndex = 0; parameterIndex < parameterCount; parameterIndex++)
 0191                {
 0192                    int typeCode = blobReader.ReadCompressedInteger();
 0193                    if (typeCode == (int)SignatureTypeCode.Sentinel)
 0194                    {
 0195                        break;
 196                    }
 0197                    parameterBuilder.Add(DecodeType(ref blobReader, allowTypeSpecifications: false, typeCode: typeCode))
 0198                }
 199
 0200                requiredParameterCount = parameterIndex;
 0201                for (; parameterIndex < parameterCount; parameterIndex++)
 0202                {
 0203                    parameterBuilder.Add(DecodeType(ref blobReader));
 0204                }
 0205                parameterTypes = parameterBuilder.MoveToImmutable();
 0206            }
 207
 0208            return new MethodSignature<TType>(header, returnType, requiredParameterCount, genericParameterCount, paramet
 0209        }
 210
 211        /// <summary>
 212        /// Decodes a method specification signature blob and advances the reader past the signature.
 213        /// </summary>
 214        /// <param name="blobReader">A BlobReader positioned at a valid method specification signature.</param>
 215        /// <returns>The types used to instantiate a generic method via the method specification.</returns>
 216        public ImmutableArray<TType> DecodeMethodSpecificationSignature(ref BlobReader blobReader)
 0217        {
 0218            SignatureHeader header = blobReader.ReadSignatureHeader();
 0219            CheckHeader(header, SignatureKind.MethodSpecification);
 0220            return DecodeTypeSequence(ref blobReader);
 0221        }
 222
 223        /// <summary>
 224        /// Decodes a local variable signature blob and advances the reader past the signature.
 225        /// </summary>
 226        /// <param name="blobReader">The blob reader positioned at a local variable signature.</param>
 227        /// <returns>The local variable types.</returns>
 228        /// <exception cref="System.BadImageFormatException">The local variable signature is invalid.</exception>
 229        public ImmutableArray<TType> DecodeLocalSignature(ref BlobReader blobReader)
 0230        {
 0231            SignatureHeader header = blobReader.ReadSignatureHeader();
 0232            CheckHeader(header, SignatureKind.LocalVariables);
 0233            return DecodeTypeSequence(ref blobReader);
 0234        }
 235
 236        /// <summary>
 237        /// Decodes a field signature blob and advances the reader past the signature.
 238        /// </summary>
 239        /// <param name="blobReader">The blob reader positioned at a field signature.</param>
 240        /// <returns>The decoded field type.</returns>
 241        public TType DecodeFieldSignature(ref BlobReader blobReader)
 0242        {
 0243            SignatureHeader header = blobReader.ReadSignatureHeader();
 0244            CheckHeader(header, SignatureKind.Field);
 0245            return DecodeType(ref blobReader);
 0246        }
 247
 248        private TType DecodeArrayType(ref BlobReader blobReader)
 0249        {
 250            // PERF_TODO: Cache/reuse common case of small number of all-zero lower-bounds.
 251
 0252            TType elementType = DecodeType(ref blobReader);
 0253            int rank = blobReader.ReadCompressedInteger();
 0254            var sizes = ImmutableArray<int>.Empty;
 0255            var lowerBounds = ImmutableArray<int>.Empty;
 256
 0257            int sizesCount = blobReader.ReadCompressedInteger();
 0258            if (sizesCount > 0)
 0259            {
 0260                var builder = ImmutableArray.CreateBuilder<int>(sizesCount);
 0261                for (int i = 0; i < sizesCount; i++)
 0262                {
 0263                    builder.Add(blobReader.ReadCompressedInteger());
 0264                }
 0265                sizes = builder.MoveToImmutable();
 0266            }
 267
 0268            int lowerBoundsCount = blobReader.ReadCompressedInteger();
 0269            if (lowerBoundsCount > 0)
 0270            {
 0271                var builder = ImmutableArray.CreateBuilder<int>(lowerBoundsCount);
 0272                for (int i = 0; i < lowerBoundsCount; i++)
 0273                {
 0274                    builder.Add(blobReader.ReadCompressedSignedInteger());
 0275                }
 0276                lowerBounds = builder.MoveToImmutable();
 0277            }
 278
 0279            var arrayShape = new ArrayShape(rank, sizes, lowerBounds);
 0280            return _provider.GetArrayType(elementType, arrayShape);
 0281        }
 282
 283        private TType DecodeGenericTypeInstance(ref BlobReader blobReader)
 0284        {
 0285            TType genericType = DecodeType(ref blobReader);
 0286            ImmutableArray<TType> types = DecodeTypeSequence(ref blobReader);
 0287            return _provider.GetGenericInstantiation(genericType, types);
 0288        }
 289
 290        private TType DecodeModifiedType(ref BlobReader blobReader, bool isRequired)
 0291        {
 0292            TType modifier = DecodeTypeHandle(ref blobReader, 0, allowTypeSpecifications: true);
 0293            TType unmodifiedType = DecodeType(ref blobReader);
 294
 0295            return _provider.GetModifiedType(modifier, unmodifiedType, isRequired);
 0296        }
 297
 298        private TType DecodeTypeHandle(ref BlobReader blobReader, byte rawTypeKind, bool allowTypeSpecifications)
 0299        {
 0300            EntityHandle handle = blobReader.ReadTypeHandle();
 0301            if (!handle.IsNil)
 0302            {
 0303                switch (handle.Kind)
 304                {
 305                    case HandleKind.TypeDefinition:
 0306                        return _provider.GetTypeFromDefinition(_metadataReaderOpt, (TypeDefinitionHandle)handle, rawType
 307
 308                    case HandleKind.TypeReference:
 0309                        return _provider.GetTypeFromReference(_metadataReaderOpt, (TypeReferenceHandle)handle, rawTypeKi
 310
 311                    case HandleKind.TypeSpecification:
 0312                        if (!allowTypeSpecifications)
 0313                        {
 314                            // To prevent cycles, the token following (CLASS | VALUETYPE) must not be a type spec.
 315                            // https://github.com/dotnet/coreclr/blob/8ff2389204d7c41b17eff0e9536267aea8d6496f/src/md/co
 0316                            throw new BadImageFormatException(SR.NotTypeDefOrRefHandle);
 317                        }
 318
 0319                        return _provider.GetTypeFromSpecification(_metadataReaderOpt, _genericContext, (TypeSpecificatio
 320
 321                    default:
 322                        // indicates an error returned from ReadTypeHandle, otherwise unreachable.
 0323                        Debug.Assert(handle.IsNil); // will fall through to throw in release.
 0324                        break;
 325                }
 0326            }
 327
 0328            throw new BadImageFormatException(SR.NotTypeDefOrRefOrSpecHandle);
 0329        }
 330
 331        private static void CheckHeader(SignatureHeader header, SignatureKind expectedKind)
 0332        {
 0333            if (header.Kind != expectedKind)
 0334            {
 0335                throw new BadImageFormatException(SR.Format(SR.UnexpectedSignatureHeader, expectedKind, header.Kind, hea
 336            }
 0337        }
 338
 339        private static void CheckMethodOrPropertyHeader(SignatureHeader header)
 0340        {
 0341            SignatureKind kind = header.Kind;
 0342            if (kind != SignatureKind.Method && kind != SignatureKind.Property)
 0343            {
 0344                throw new BadImageFormatException(SR.Format(SR.UnexpectedSignatureHeader2, SignatureKind.Property, Signa
 345            }
 0346        }
 347    }
 348}
 349