File: Symbols\Synthesized\SynthesizedLocal.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.
 
#nullable disable
 
using System;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Runtime.CompilerServices;
using System.Text;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    /// <summary>
    /// A synthesized local variable.
    /// </summary>
    [DebuggerDisplay("{GetDebuggerDisplay(),nq}")]
    internal sealed class SynthesizedLocal : LocalSymbol
    {
        private readonly MethodSymbol _containingMethodOpt;
        private readonly TypeWithAnnotations _type;
        private readonly SynthesizedLocalKind _kind;
        private readonly SyntaxNode _syntaxOpt;
        private readonly bool _isPinned;
        private bool _isKnownToReferToTempIfReferenceType;
        private readonly RefKind _refKind;
 
#if DEBUG
        private readonly int _createdAtLineNumber;
        private readonly string _createdAtFilePath;
#endif
 
        internal SynthesizedLocal(
            MethodSymbol containingMethodOpt,
            TypeWithAnnotations type,
            SynthesizedLocalKind kind,
            SyntaxNode syntaxOpt = null,
            bool isPinned = false,
            bool isKnownToReferToTempIfReferenceType = false,
            RefKind refKind = RefKind.None
#if DEBUG
            ,
            [CallerLineNumber] int createdAtLineNumber = 0,
            [CallerFilePath] string createdAtFilePath = null
#endif
            )
        {
            Debug.Assert(!type.IsVoidType());
            Debug.Assert(!kind.IsLongLived() || syntaxOpt != null);
            Debug.Assert(refKind != RefKind.Out);
            Debug.Assert(containingMethodOpt is null || containingMethodOpt.DeclaringCompilation is not null);
 
            _containingMethodOpt = containingMethodOpt;
            _type = type;
            _kind = kind;
            _syntaxOpt = syntaxOpt;
            _isPinned = isPinned;
            _isKnownToReferToTempIfReferenceType = isKnownToReferToTempIfReferenceType;
            _refKind = refKind;
 
#if DEBUG
            _createdAtLineNumber = createdAtLineNumber;
            _createdAtFilePath = createdAtFilePath;
#endif
        }
 
        public SyntaxNode SyntaxOpt
        {
            get { return _syntaxOpt; }
        }
 
        internal sealed override LocalSymbol WithSynthesizedLocalKindAndSyntax(
            SynthesizedLocalKind kind, SyntaxNode syntax
#if DEBUG
            ,
            [CallerLineNumber] int createdAtLineNumber = 0,
            [CallerFilePath] string createdAtFilePath = null
#endif
            )
        {
            return new SynthesizedLocal(
                _containingMethodOpt,
                _type,
                kind,
                syntax,
                _isPinned,
                _isKnownToReferToTempIfReferenceType,
                _refKind
#if DEBUG
                ,
                createdAtLineNumber,
                createdAtFilePath
#endif
                );
        }
 
        public sealed override RefKind RefKind
        {
            get { return _refKind; }
        }
 
        internal sealed override bool IsImportedFromMetadata
        {
            get { return false; }
        }
 
        internal sealed override LocalDeclarationKind DeclarationKind
        {
            get { return LocalDeclarationKind.None; }
        }
 
        internal sealed override SynthesizedLocalKind SynthesizedKind
        {
            get { return _kind; }
        }
 
        internal sealed override SyntaxNode ScopeDesignatorOpt
        {
            get { return null; }
        }
 
        internal sealed override SyntaxToken IdentifierToken
        {
            get { return default(SyntaxToken); }
        }
 
        public sealed override Symbol ContainingSymbol
        {
            get { return _containingMethodOpt; }
        }
 
        public sealed override string Name
        {
            get { return null; }
        }
 
        public sealed override TypeWithAnnotations TypeWithAnnotations
        {
            get { return _type; }
        }
 
        public sealed override ImmutableArray<Location> Locations
        {
            get { return (_syntaxOpt == null) ? ImmutableArray<Location>.Empty : ImmutableArray.Create(_syntaxOpt.GetLocation()); }
        }
 
        public sealed override ImmutableArray<SyntaxReference> DeclaringSyntaxReferences
        {
            get { return (_syntaxOpt == null) ? ImmutableArray<SyntaxReference>.Empty : ImmutableArray.Create(_syntaxOpt.GetReference()); }
        }
 
        internal sealed override SyntaxNode GetDeclaratorSyntax()
        {
            Debug.Assert(_syntaxOpt != null);
            return _syntaxOpt;
        }
 
        internal override bool HasSourceLocation
            => _syntaxOpt != null;
 
        public sealed override bool IsImplicitlyDeclared
        {
            get { return true; }
        }
 
        internal sealed override bool IsPinned
        {
            get { return _isPinned; }
        }
 
        internal sealed override bool IsKnownToReferToTempIfReferenceType
        {
            get { return _isKnownToReferToTempIfReferenceType; }
        }
 
        internal void SetIsKnownToReferToTempIfReferenceType()
        {
            Debug.Assert(!_isKnownToReferToTempIfReferenceType);
            _isKnownToReferToTempIfReferenceType = true;
        }
 
        internal sealed override bool IsCompilerGenerated
        {
            get { return true; }
        }
 
        internal sealed override ScopedKind Scope => ScopedKind.None;
 
        internal sealed override ConstantValue GetConstantValue(SyntaxNode node, LocalSymbol inProgress, BindingDiagnosticBag diagnostics)
        {
            return null;
        }
 
        internal sealed override ReadOnlyBindingDiagnostic<AssemblySymbol> GetConstantValueDiagnostics(BoundExpression boundInitValue)
        {
            return ReadOnlyBindingDiagnostic<AssemblySymbol>.Empty;
        }
 
#if DEBUG
        private static int _nextSequence = 0;
        // Produce a token that helps distinguish one variable from another when debugging
        private readonly int _sequence = System.Threading.Interlocked.Increment(ref _nextSequence);
 
        internal string DumperString()
        {
            var builder = new StringBuilder();
            builder.Append(_type.ToDisplayString(SymbolDisplayFormat.TestFormat));
            builder.Append(' ');
            builder.Append(_kind.ToString());
            builder.Append('.');
            builder.Append(_sequence);
            return builder.ToString();
        }
#endif
 
        internal sealed override string GetDebuggerDisplay()
        {
            var builder = new StringBuilder();
            builder.Append('<');
            builder.Append(_kind.ToString());
            builder.Append('>');
#if DEBUG
            builder.Append('.');
            builder.Append(_sequence);
#endif
            builder.Append(' ');
            builder.Append(_type.ToDisplayString(SymbolDisplayFormat.TestFormat));
 
#if DEBUG
            builder.Append(" @");
            builder.Append(_createdAtFilePath);
            builder.Append('(');
            builder.Append(_createdAtLineNumber);
            builder.Append(')');
#endif
 
            return builder.ToString();
        }
    }
}