File: MethodContextReuseConstraints.cs
Web Access
Project: src\src\ExpressionEvaluator\Core\Source\ExpressionCompiler\Microsoft.CodeAnalysis.ExpressionCompiler.csproj (Microsoft.CodeAnalysis.ExpressionEvaluator.ExpressionCompiler)
// 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;
using System.Collections.Generic;
using System.Diagnostics;
using System.Reflection.Metadata;
using System.Reflection.Metadata.Ecma335;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.ExpressionEvaluator
{
    internal readonly struct MethodContextReuseConstraints
    {
        private readonly Guid _moduleVersionId;
        private readonly int _methodToken;
        private readonly int _methodVersion;
        private readonly ILSpan _span;
 
        internal MethodContextReuseConstraints(Guid moduleVersionId, int methodToken, int methodVersion, ILSpan span)
        {
            Debug.Assert(moduleVersionId != Guid.Empty);
            Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition);
            Debug.Assert(methodVersion >= 1);
 
            _moduleVersionId = moduleVersionId;
            _methodToken = methodToken;
            _methodVersion = methodVersion;
            _span = span;
        }
 
        public bool AreSatisfied(Guid moduleVersionId, int methodToken, int methodVersion, int ilOffset)
        {
            Debug.Assert(moduleVersionId != Guid.Empty);
            Debug.Assert(MetadataTokens.Handle(methodToken).Kind == HandleKind.MethodDefinition);
            Debug.Assert(methodVersion >= 1);
            Debug.Assert(ilOffset >= 0);
 
            return moduleVersionId == _moduleVersionId &&
                methodToken == _methodToken &&
                methodVersion == _methodVersion &&
                _span.Contains(ilOffset);
        }
 
        public override string ToString()
        {
            return $"0x{_methodToken:x8}v{_methodVersion} from {_moduleVersionId} {_span}";
        }
 
        /// <summary>
        /// Finds a span of IL containing the specified offset where local variables and imports are guaranteed to be the same.
        /// Examples:
        /// scopes: [   [   ) x [  )  )
        /// result:         [   )
        /// 
        /// scopes: [ x [   )   [  )  )
        /// result: [   )     
        /// 
        /// scopes: [   [ x )   [  )  )
        /// result:     [   )     
        /// </summary>
        public static ILSpan CalculateReuseSpan(int ilOffset, ILSpan initialSpan, IEnumerable<ILSpan> scopes)
        {
            Debug.Assert(ilOffset >= 0);
 
            uint _startOffset = initialSpan.StartOffset;
            uint _endOffsetExclusive = initialSpan.EndOffsetExclusive;
 
            foreach (ILSpan scope in scopes)
            {
                if (ilOffset < scope.StartOffset)
                {
                    _endOffsetExclusive = Math.Min(_endOffsetExclusive, scope.StartOffset);
                }
                else if (ilOffset >= scope.EndOffsetExclusive)
                {
                    _startOffset = Math.Max(_startOffset, scope.EndOffsetExclusive);
                }
                else
                {
                    _startOffset = Math.Max(_startOffset, scope.StartOffset);
                    _endOffsetExclusive = Math.Min(_endOffsetExclusive, scope.EndOffsetExclusive);
                }
            }
 
            return new ILSpan(_startOffset, _endOffsetExclusive);
        }
    }
}