File: Binder\Binder_Flags.cs
Web Access
Project: src\src\Compilers\CSharp\Portable\Microsoft.CodeAnalysis.CSharp.csproj (Microsoft.CodeAnalysis.CSharp)
// 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 Microsoft.CodeAnalysis.CSharp.Symbols;
using System.Diagnostics;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    internal partial class Binder
    {
        /// <summary>
        /// Represents a small change from the enclosing/next binder.
        /// Can specify a BindingLocation and a ContainingMemberOrLambda.
        /// </summary>
        private sealed class BinderWithContainingMemberOrLambda : Binder
        {
            private readonly Symbol _containingMemberOrLambda;
 
            internal BinderWithContainingMemberOrLambda(Binder next, Symbol containingMemberOrLambda)
                : base(next)
            {
                Debug.Assert(containingMemberOrLambda != null);
 
                _containingMemberOrLambda = containingMemberOrLambda;
            }
 
            internal BinderWithContainingMemberOrLambda(Binder next, BinderFlags flags, Symbol containingMemberOrLambda)
                : base(next, flags)
            {
                Debug.Assert(containingMemberOrLambda != null);
 
                _containingMemberOrLambda = containingMemberOrLambda;
            }
 
            internal override Symbol ContainingMemberOrLambda
            {
                get { return _containingMemberOrLambda; }
            }
        }
 
        /// <summary>
        /// Represents a small change from the enclosing/next binder.
        /// Can specify a receiver Expression for containing conditional member access.
        /// </summary>
        private sealed class BinderWithConditionalReceiver : Binder
        {
            private readonly BoundExpression _receiverExpression;
 
            internal BinderWithConditionalReceiver(Binder next, BoundExpression receiverExpression)
                : base(next)
            {
                Debug.Assert(receiverExpression != null);
 
                _receiverExpression = receiverExpression;
            }
 
            internal override BoundExpression ConditionalReceiverExpression
            {
                get { return _receiverExpression; }
            }
        }
 
        internal Binder WithFlags(BinderFlags flags)
        {
            return this.Flags == flags
                ? this
                : new Binder(this, flags);
        }
 
        internal Binder WithAdditionalFlags(BinderFlags flags)
        {
            return this.Flags.Includes(flags)
                ? this
                : new Binder(this, this.Flags | flags);
        }
 
        internal Binder WithContainingMemberOrLambda(Symbol containing)
        {
            Debug.Assert((object)containing != null);
            return new BinderWithContainingMemberOrLambda(this, containing);
        }
 
        /// <remarks>
        /// It seems to be common to do both of these things at once, so provide a way to do so
        /// without adding two links to the binder chain.
        /// </remarks>
        internal Binder WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags flags, Symbol containing)
        {
            Debug.Assert((object)containing != null);
            return new BinderWithContainingMemberOrLambda(this, this.Flags | flags, containing);
        }
 
        internal Binder SetOrClearUnsafeRegionIfNecessary(SyntaxTokenList modifiers, bool isIteratorBody = false)
        {
            // In C# 13 and above, iterator bodies define a safe context even when nested in an unsafe context.
            // In C# 12 and below, we keep the (spec violating) behavior that iterator bodies inherit the safe/unsafe context
            // from their containing scope. Since there are errors for unsafe constructs directly in iterators,
            // this inherited unsafe context can be observed only in nested non-iterator local functions.
            var withoutUnsafe = isIteratorBody && this.Compilation.IsFeatureEnabled(MessageID.IDS_FeatureRefUnsafeInIteratorAsync);
 
            if (this.Flags.Includes(BinderFlags.UnsafeRegion))
            {
                return withoutUnsafe
                    ? new Binder(this, this.Flags & ~BinderFlags.UnsafeRegion)
                    : this;
            }
 
            return !withoutUnsafe && modifiers.Any(SyntaxKind.UnsafeKeyword)
                ? new Binder(this, this.Flags | BinderFlags.UnsafeRegion)
                : this;
        }
 
        internal Binder WithCheckedOrUncheckedRegion(bool @checked)
        {
            Debug.Assert(!this.Flags.Includes(BinderFlags.UncheckedRegion | BinderFlags.CheckedRegion));
 
            BinderFlags added = @checked ? BinderFlags.CheckedRegion : BinderFlags.UncheckedRegion;
            BinderFlags removed = @checked ? BinderFlags.UncheckedRegion : BinderFlags.CheckedRegion;
 
            return this.Flags.Includes(added)
                ? this
                : new Binder(this, (this.Flags & ~removed) | added);
        }
    }
}