File: Emit\EditAndContinue\AddedOrChangedMethodInfo.cs
Web Access
Project: src\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 System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CodeGen;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.Emit
{
    internal readonly struct AddedOrChangedMethodInfo
    {
        public readonly DebugId MethodId;
 
        // locals:
        public readonly ImmutableArray<EncLocalInfo> Locals;
 
        // lambdas, closures:
        public readonly ImmutableArray<EncLambdaInfo> LambdaDebugInfo;
        public readonly ImmutableArray<EncClosureInfo> ClosureDebugInfo;
 
        // state machines:
        public readonly string? StateMachineTypeName;
        public readonly ImmutableArray<EncHoistedLocalInfo> StateMachineHoistedLocalSlotsOpt;
        public readonly ImmutableArray<Cci.ITypeReference?> StateMachineAwaiterSlotsOpt;
        public readonly StateMachineStatesDebugInfo StateMachineStates;
 
        public AddedOrChangedMethodInfo(
            DebugId methodId,
            ImmutableArray<EncLocalInfo> locals,
            ImmutableArray<EncLambdaInfo> lambdaDebugInfo,
            ImmutableArray<EncClosureInfo> closureDebugInfo,
            string? stateMachineTypeName,
            ImmutableArray<EncHoistedLocalInfo> stateMachineHoistedLocalSlotsOpt,
            ImmutableArray<Cci.ITypeReference?> stateMachineAwaiterSlotsOpt,
            StateMachineStatesDebugInfo stateMachineStates)
        {
            // An updated method will carry its id over,
            // an added method id has generation set to the current generation ordinal.
            Debug.Assert(methodId.Generation >= 0);
 
            // each state machine has to have awaiters:
            Debug.Assert(stateMachineAwaiterSlotsOpt.IsDefault == stateMachineTypeName is null);
 
            // a state machine might not have hoisted variables:
            Debug.Assert(stateMachineHoistedLocalSlotsOpt.IsDefault || stateMachineTypeName is not null);
 
            MethodId = methodId;
            Locals = locals;
            LambdaDebugInfo = lambdaDebugInfo;
            ClosureDebugInfo = closureDebugInfo;
            StateMachineTypeName = stateMachineTypeName;
            StateMachineHoistedLocalSlotsOpt = stateMachineHoistedLocalSlotsOpt;
            StateMachineAwaiterSlotsOpt = stateMachineAwaiterSlotsOpt;
            StateMachineStates = stateMachineStates;
        }
 
        public AddedOrChangedMethodInfo MapTypes(SymbolMatcher map)
        {
            var mappedLocals = ImmutableArray.CreateRange(Locals, MapLocalInfo, map);
 
            var mappedHoistedLocalSlots = StateMachineHoistedLocalSlotsOpt.IsDefault ? default :
                ImmutableArray.CreateRange(StateMachineHoistedLocalSlotsOpt, MapHoistedLocalSlot, map);
 
            var mappedAwaiterSlots = StateMachineAwaiterSlotsOpt.IsDefault ? default :
                ImmutableArray.CreateRange(StateMachineAwaiterSlotsOpt, static (typeRef, map) => (typeRef is null) ? null : map.MapReference(typeRef), map);
 
            return new AddedOrChangedMethodInfo(MethodId, mappedLocals, LambdaDebugInfo, ClosureDebugInfo, StateMachineTypeName, mappedHoistedLocalSlots, mappedAwaiterSlots, StateMachineStates);
        }
 
        private static EncLocalInfo MapLocalInfo(EncLocalInfo info, SymbolMatcher map)
        {
            Debug.Assert(!info.IsDefault);
            if (info.Type is null)
            {
                Debug.Assert(info.Signature != null);
                return info;
            }
 
            var typeRef = map.MapReference(info.Type);
            RoslynDebug.AssertNotNull(typeRef);
 
            return new EncLocalInfo(info.SlotInfo, typeRef, info.Constraints, info.Signature);
        }
 
        private static EncHoistedLocalInfo MapHoistedLocalSlot(EncHoistedLocalInfo info, SymbolMatcher map)
        {
            if (info.Type is null)
            {
                return info;
            }
 
            var typeRef = map.MapReference(info.Type);
            RoslynDebug.AssertNotNull(typeRef);
 
            return new EncHoistedLocalInfo(info.SlotInfo, typeRef);
        }
    }
}