| File: MemberDescriptor.cs | Web Access |
| Project: src\roslyn\src\Compilers\Core\Portable\Microsoft.CodeAnalysis.csproj (Microsoft.CodeAnalysis) |
// Licensed to the .NET Foundation under one or more agreements. // The .NET Foundation licenses this file to you under the MIT license. // See the LICENSE file in the project root for more information. using Roslyn.Utilities; using System; using System.Collections.Immutable; using System.Diagnostics; using System.IO; using System.Reflection.Metadata; namespace Microsoft.CodeAnalysis.RuntimeMembers { [Flags()] internal enum MemberFlags : byte { // BEGIN Mutually exclusive Member kinds: Method = 0x01, Field = 0x02, Constructor = 0x04, PropertyGet = 0x08, Property = 0x10, // END Mutually exclusive Member kinds KindMask = 0x1F, Static = 0x20, Virtual = 0x40, // Virtual in CLR terms, i.e. sealed should be accepted. } /// <summary> /// Structure that describes a member of a type. /// </summary> internal readonly struct MemberDescriptor { public readonly MemberFlags Flags; /// <summary> /// Id/token of containing type, usually value from some enum. /// For example from SpecialType enum. /// I am not using SpecialType as the type for this field because /// VB runtime types are not part of SpecialType. /// /// So, the implication is that any type ids we use outside of the SpecialType /// (either for the VB runtime classes, or types like System.Task etc.) will need /// to use IDs that are all mutually disjoint. /// </summary> private readonly short _declaringTypeId; public bool IsSpecialTypeMember => _declaringTypeId < (int)InternalSpecialType.NextAvailable; public ExtendedSpecialType DeclaringSpecialType { get { Debug.Assert(_declaringTypeId < (int)InternalSpecialType.NextAvailable); return (ExtendedSpecialType)_declaringTypeId; } } public WellKnownType DeclaringWellKnownType { get { Debug.Assert(_declaringTypeId >= (int)WellKnownType.First); return (WellKnownType)_declaringTypeId; } } public string DeclaringTypeMetadataName { get { return IsSpecialTypeMember ? DeclaringSpecialType.GetMetadataName()! : DeclaringWellKnownType.GetMetadataName(); } } public readonly ushort Arity; public readonly string Name; /// <summary> /// Signature of the field or method, similar to metadata signature, /// but with the following exceptions: /// 1) Truncated on the left, for methods starts at [ParamCount], for fields at [Type] /// 2) Type tokens are not compressed /// 3) BOOLEAN | CHAR | I1 | U1 | I2 | U2 | I4 | U4 | I8 | U8 | R4 | R8 | I | U | Void types are encoded by /// using VALUETYPE+typeId notation. /// 4) array bounds are not included. /// 5) modifiers are not included. /// 6) (CLASS | VALUETYPE) are omitted after GENERICINST /// </summary> public readonly ImmutableArray<byte> Signature; /// <summary> /// Applicable only to properties and methods, throws otherwise. /// </summary> public int ParametersCount { get { MemberFlags memberKind = Flags & MemberFlags.KindMask; switch (memberKind) { case MemberFlags.Constructor: case MemberFlags.Method: case MemberFlags.PropertyGet: case MemberFlags.Property: return Signature[0]; default: throw ExceptionUtilities.UnexpectedValue(memberKind); } } } public MemberDescriptor( MemberFlags Flags, short DeclaringTypeId, string Name, ImmutableArray<byte> Signature, ushort Arity = 0) { this.Flags = Flags; this._declaringTypeId = DeclaringTypeId; this.Name = Name; this.Arity = Arity; this.Signature = Signature; } internal static ImmutableArray<MemberDescriptor> InitializeFromStream(Stream stream, string[] nameTable) { int count = nameTable.Length; var builder = ImmutableArray.CreateBuilder<MemberDescriptor>(count); var signatureBuilder = ImmutableArray.CreateBuilder<byte>(); for (int i = 0; i < count; i++) { MemberFlags flags = (MemberFlags)stream.ReadByte(); short declaringTypeId = ReadTypeId(stream); ushort arity = (ushort)stream.ReadByte(); if ((flags & MemberFlags.Field) != 0) { ParseType(signatureBuilder, stream); } else { // Property, PropertyGet, Method or Constructor ParseMethodOrPropertySignature(signatureBuilder, stream); } builder.Add(new MemberDescriptor(flags, declaringTypeId, nameTable[i], signatureBuilder.ToImmutable(), arity)); signatureBuilder.Clear(); } return builder.ToImmutable(); } /// <summary> /// The type Id may be: /// (1) encoded in a single byte (for types below 255) /// (2) encoded in two bytes (255 + extension byte) for types below 512 /// </summary> private static short ReadTypeId(Stream stream) { var firstByte = (byte)stream.ReadByte(); if (firstByte == (byte)WellKnownType.ExtSentinel) { return (short)(stream.ReadByte() + WellKnownType.ExtSentinel); } else { return firstByte; } } private static void ParseMethodOrPropertySignature(ImmutableArray<byte>.Builder builder, Stream stream) { int paramCount = stream.ReadByte(); builder.Add((byte)paramCount); // Return type ParseType(builder, stream, allowByRef: true); // Parameters for (int i = 0; i < paramCount; i++) { ParseType(builder, stream, allowByRef: true); } } private static void ParseType(ImmutableArray<byte>.Builder builder, Stream stream, bool allowByRef = false) { while (true) { var typeCode = (SignatureTypeCode)stream.ReadByte(); builder.Add((byte)typeCode); switch (typeCode) { default: throw ExceptionUtilities.UnexpectedValue(typeCode); case SignatureTypeCode.TypeHandle: ParseTypeHandle(builder, stream); return; case SignatureTypeCode.GenericTypeParameter: case SignatureTypeCode.GenericMethodParameter: builder.Add((byte)stream.ReadByte()); return; case SignatureTypeCode.ByReference: if (!allowByRef) goto default; break; case SignatureTypeCode.SZArray: break; case SignatureTypeCode.Pointer: break; case SignatureTypeCode.GenericTypeInstance: ParseGenericTypeInstance(builder, stream); return; } allowByRef = false; } } /// <summary> /// Read a type Id from the stream and copy it into the builder. /// This may copy one or two bytes depending on the first one. /// </summary> private static void ParseTypeHandle(ImmutableArray<byte>.Builder builder, Stream stream) { var firstByte = (byte)stream.ReadByte(); builder.Add(firstByte); if (firstByte == (byte)WellKnownType.ExtSentinel) { var secondByte = (byte)stream.ReadByte(); builder.Add(secondByte); } } private static void ParseGenericTypeInstance(ImmutableArray<byte>.Builder builder, Stream stream) { ParseType(builder, stream); // Generic type parameters int argumentCount = stream.ReadByte(); builder.Add((byte)argumentCount); for (int i = 0; i < argumentCount; i++) { ParseType(builder, stream); } } } }