File: Symbols\Synthesized\Records\SynthesizedRecordPropertySymbol.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 System.Collections.Immutable;
using System.Diagnostics;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp.Symbols
{
    internal sealed class SynthesizedRecordPropertySymbol : SourcePropertySymbolBase
    {
        public SourceParameterSymbol BackingParameter { get; }
 
        public SynthesizedRecordPropertySymbol(
            SourceMemberContainerTypeSymbol containingType,
            CSharpSyntaxNode syntax,
            ParameterSymbol backingParameter,
            bool isOverride,
            BindingDiagnosticBag diagnostics)
            : base(
                containingType,
                syntax: syntax,
                hasGetAccessor: true,
                hasSetAccessor: true,
                isExplicitInterfaceImplementation: false,
                explicitInterfaceType: null,
                aliasQualifierOpt: null,
                modifiers: DeclarationModifiers.Public | (isOverride ? DeclarationModifiers.Override : DeclarationModifiers.None),
                hasInitializer: true, // Synthesized record properties always have a synthesized initializer
                hasExplicitAccessMod: false,
                hasAutoPropertyGet: true,
                hasAutoPropertySet: true,
                isExpressionBodied: false,
                accessorsHaveImplementation: true,
                getterUsesFieldKeyword: false,
                setterUsesFieldKeyword: false,
                RefKind.None,
                backingParameter.Name,
                indexerNameAttributeLists: new SyntaxList<AttributeListSyntax>(),
                backingParameter.GetFirstLocation(),
                diagnostics)
        {
            BackingParameter = (SourceParameterSymbol)backingParameter;
        }
 
        protected override SourcePropertySymbolBase? BoundAttributesSource => null;
 
        public override IAttributeTargetSymbol AttributesOwner => BackingParameter as IAttributeTargetSymbol ?? this;
 
        protected override Location TypeLocation
            => ((ParameterSyntax)CSharpSyntaxNode).Type!.Location;
 
        public override OneOrMany<SyntaxList<AttributeListSyntax>> GetAttributeDeclarations()
            => OneOrMany.Create(BackingParameter.AttributeDeclarationList);
 
        protected override SourcePropertyAccessorSymbol CreateGetAccessorSymbol(bool isAutoPropertyAccessor, BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(isAutoPropertyAccessor);
            return CreateAccessorSymbol(isGet: true, CSharpSyntaxNode, diagnostics);
        }
 
        protected override SourcePropertyAccessorSymbol CreateSetAccessorSymbol(bool isAutoPropertyAccessor, BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(isAutoPropertyAccessor);
            return CreateAccessorSymbol(isGet: false, CSharpSyntaxNode, diagnostics);
        }
 
        private static bool ShouldUseInit(TypeSymbol container)
        {
            // the setter is always init-only in record class and in readonly record struct
            return !container.IsStructType() || container.IsReadOnly;
        }
 
        private SourcePropertyAccessorSymbol CreateAccessorSymbol(
            bool isGet,
            CSharpSyntaxNode syntax,
            BindingDiagnosticBag diagnostics)
        {
            var usesInit = !isGet && ShouldUseInit(ContainingType);
            return SourcePropertyAccessorSymbol.CreateAccessorSymbol(
                isGet,
                usesInit,
                ContainingType,
                this,
                _modifiers,
                ((ParameterSyntax)syntax).Identifier.GetLocation(),
                syntax,
                diagnostics);
        }
 
        protected override (TypeWithAnnotations Type, ImmutableArray<ParameterSymbol> Parameters) MakeParametersAndBindType(BindingDiagnosticBag diagnostics)
        {
            return (BackingParameter.TypeWithAnnotations,
                    ImmutableArray<ParameterSymbol>.Empty);
        }
 
        public static bool HaveCorrespondingSynthesizedRecordPropertySymbol(SourceParameterSymbol parameter)
        {
            return parameter.ContainingSymbol is SynthesizedPrimaryConstructor &&
                   parameter.ContainingType.GetMembersUnordered().Any((s, parameter) => (s as SynthesizedRecordPropertySymbol)?.BackingParameter == (object)parameter, parameter);
        }
    }
}