File: Binder\Binder_Attributes.cs
Web Access
Project: ..\..\..\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;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    internal partial class Binder
    {
        #region Bind All Attributes
 
        // Method to bind attributes types early for all attributes to enable early decoding of some well-known attributes used within the binder.
        // Note: attributesToBind contains merged attributes from all the different syntax locations (e.g. for named types, partial methods, etc.).
        // Note: Additionally, the attributes with non-matching target specifier for the given owner symbol have been filtered out, i.e. Binder.MatchAttributeTarget method returned true.
        // For example, if were binding attributes on delegate type symbol for below code snippet:
        //      [A1]
        //      [return: A2]
        //      public delegate void Goo();
        // attributesToBind will only contain first attribute syntax.
        internal static void BindAttributeTypes(
            ImmutableArray<Binder> binders, ImmutableArray<AttributeSyntax> attributesToBind, Symbol ownerSymbol, NamedTypeSymbol[] boundAttributeTypes,
            Action<AttributeSyntax>? beforeAttributePartBound,
            Action<AttributeSyntax>? afterAttributePartBound,
            BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(binders.Any());
            Debug.Assert(attributesToBind.Any());
            Debug.Assert((object)ownerSymbol != null);
            Debug.Assert(binders.Length == attributesToBind.Length);
            RoslynDebug.Assert(boundAttributeTypes != null);
 
            for (int i = 0; i < attributesToBind.Length; i++)
            {
                // Some types may have been bound by an earlier stage.
                if (boundAttributeTypes[i] is null)
                {
                    var binder = binders[i];
                    AttributeSyntax attributeToBind = attributesToBind[i];
 
                    beforeAttributePartBound?.Invoke(attributeToBind);
 
                    // BindType for AttributeSyntax's name is handled specially during lookup, see Binder.LookupAttributeType.
                    // When looking up a name in attribute type context, we generate a diagnostic + error type if it is not an attribute type, i.e. named type deriving from System.Attribute.
                    // Hence we can assume here that BindType returns a NamedTypeSymbol.
                    var boundType = binder.BindType(attributeToBind.Name, diagnostics);
                    var boundTypeSymbol = (NamedTypeSymbol)boundType.Type;
 
                    // Check the attribute type (unless the attribute type is already an error).
                    if (boundTypeSymbol.TypeKind != TypeKind.Error)
                    {
                        var location = attributeToBind.Name.GetLocation();
                        binder.CheckDisallowedAttributeDependentType(boundType, location, diagnostics);
                    }
 
                    boundAttributeTypes[i] = boundTypeSymbol;
 
                    afterAttributePartBound?.Invoke(attributeToBind);
                }
            }
        }
 
        // Method to bind all attributes (attribute arguments and constructor)
        internal static void GetAttributes(
            ImmutableArray<Binder> binders,
            ImmutableArray<AttributeSyntax> attributesToBind,
            ImmutableArray<NamedTypeSymbol> boundAttributeTypes,
            CSharpAttributeData?[] attributeDataArray,
            BoundAttribute?[]? boundAttributeArray,
            Action<AttributeSyntax>? beforeAttributePartBound,
            Action<AttributeSyntax>? afterAttributePartBound,
            BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(binders.Any());
            Debug.Assert(attributesToBind.Any());
            Debug.Assert(boundAttributeTypes.Any());
            Debug.Assert(binders.Length == attributesToBind.Length);
            Debug.Assert(boundAttributeTypes.Length == attributesToBind.Length);
            RoslynDebug.Assert(attributeDataArray != null);
 
            for (int i = 0; i < attributesToBind.Length; i++)
            {
                AttributeSyntax attributeSyntax = attributesToBind[i];
                NamedTypeSymbol boundAttributeType = boundAttributeTypes[i];
                Binder binder = binders[i];
 
                var attribute = (SourceAttributeData?)attributeDataArray[i];
                if (attribute == null)
                {
                    (attributeDataArray[i], var boundAttribute) = binder.GetAttribute(attributeSyntax, boundAttributeType, beforeAttributePartBound, afterAttributePartBound, diagnostics);
                    if (boundAttributeArray is not null)
                    {
                        boundAttributeArray[i] = boundAttribute;
                    }
                }
                else
                {
                    Debug.Assert(boundAttributeArray is null || boundAttributeArray[i] is not null);
 
                    // attributesBuilder might contain some early bound well-known attributes, which had no errors.
                    // We don't rebind the early bound attributes, but need to compute isConditionallyOmitted.
                    // Note that AttributeData.IsConditionallyOmitted is required only during emit, but must be computed here as
                    // its value depends on the values of conditional symbols, which in turn depends on the source file where the attribute is applied.
 
                    Debug.Assert(!attribute.HasErrors);
                    Debug.Assert(attribute.AttributeClass is object);
                    CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = binder.GetNewCompoundUseSiteInfo(diagnostics);
                    bool isConditionallyOmitted = binder.IsAttributeConditionallyOmitted(attribute.AttributeClass, attributeSyntax.SyntaxTree, ref useSiteInfo);
                    diagnostics.Add(attributeSyntax, useSiteInfo);
                    attributeDataArray[i] = attribute.WithOmittedCondition(isConditionallyOmitted);
                }
            }
        }
 
        #endregion
 
        #region Bind Single Attribute
 
        internal (CSharpAttributeData, BoundAttribute) GetAttribute(
            AttributeSyntax node, NamedTypeSymbol boundAttributeType,
            Action<AttributeSyntax>? beforeAttributePartBound,
            Action<AttributeSyntax>? afterAttributePartBound,
            BindingDiagnosticBag diagnostics)
        {
            beforeAttributePartBound?.Invoke(node);
            var boundAttribute = new ExecutableCodeBinder(node, this.ContainingMemberOrLambda, this).BindAttribute(node, boundAttributeType, (this as ContextualAttributeBinder)?.AttributedMember, diagnostics);
            afterAttributePartBound?.Invoke(node);
            return (GetAttribute(boundAttribute, diagnostics), boundAttribute);
        }
 
        internal BoundAttribute BindAttribute(AttributeSyntax node, NamedTypeSymbol attributeType, Symbol? attributedMember, BindingDiagnosticBag diagnostics)
        {
            return this.GetRequiredBinder(node).BindAttributeCore(node, attributeType, attributedMember, diagnostics);
        }
 
        private Binder SkipSemanticModelBinder()
        {
            Binder result = this;
 
            while (result.IsSemanticModelBinder)
            {
                result = result.Next!;
            }
 
            return result;
        }
 
        private BoundAttribute BindAttributeCore(AttributeSyntax node, NamedTypeSymbol attributeType, Symbol? attributedMember, BindingDiagnosticBag diagnostics)
        {
            Debug.Assert(this.SkipSemanticModelBinder() == this.GetRequiredBinder(node).SkipSemanticModelBinder());
 
            // If attribute name bound to an error type with a single named type
            // candidate symbol, we want to bind the attribute constructor
            // and arguments with that named type to generate better semantic info.
 
            // CONSIDER:    Do we need separate code paths for IDE and 
            // CONSIDER:    batch compilation scenarios? Above mentioned scenario
            // CONSIDER:    is not useful for batch compilation.
 
            NamedTypeSymbol attributeTypeForBinding = attributeType;
            LookupResultKind resultKind = LookupResultKind.Viable;
            if (attributeTypeForBinding.IsErrorType())
            {
                var errorType = (ErrorTypeSymbol)attributeTypeForBinding;
                resultKind = errorType.ResultKind;
                if (errorType.CandidateSymbols.Length == 1 && errorType.CandidateSymbols[0] is NamedTypeSymbol)
                {
                    attributeTypeForBinding = (NamedTypeSymbol)errorType.CandidateSymbols[0];
                }
            }
 
            // Bind constructor and named attribute arguments using the attribute binder
            var argumentListOpt = node.ArgumentList;
            Binder attributeArgumentBinder = this.WithAdditionalFlags(BinderFlags.AttributeArgument);
            AnalyzedAttributeArguments analyzedArguments = attributeArgumentBinder.BindAttributeArguments(argumentListOpt, attributeTypeForBinding, diagnostics);
 
            ImmutableArray<int> argsToParamsOpt = default;
            bool expanded = false;
            BitVector defaultArguments = default;
            MethodSymbol? attributeConstructor = null;
            ImmutableArray<BoundExpression> boundConstructorArguments;
            if (attributeTypeForBinding.IsErrorType())
            {
                boundConstructorArguments = analyzedArguments.ConstructorArguments.Arguments.SelectAsArray(
                    static (arg, attributeArgumentBinder) => attributeArgumentBinder.BindToTypeForErrorRecovery(arg),
                    attributeArgumentBinder);
            }
            else
            {
                bool found = TryPerformConstructorOverloadResolution(
                    attributeTypeForBinding,
                    analyzedArguments.ConstructorArguments,
                    attributeTypeForBinding.Name,
                    node.Location,
                    suppressResultDiagnostics: attributeType.IsErrorType(),
                    diagnostics,
                    out var memberResolutionResult,
                    out var candidateConstructors,
                    allowProtectedConstructorsOfBaseType: true,
                    suppressUnsupportedRequiredMembersError: false);
                attributeConstructor = memberResolutionResult.Member;
                expanded = memberResolutionResult.Resolution == MemberResolutionKind.ApplicableInExpandedForm;
                argsToParamsOpt = memberResolutionResult.Result.ArgsToParamsOpt;
 
                if (!found)
                {
                    CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
                    resultKind = resultKind.WorseResultKind(
                        memberResolutionResult.IsValid && !IsConstructorAccessible(memberResolutionResult.Member, ref useSiteInfo) ?
                            LookupResultKind.Inaccessible :
                            LookupResultKind.OverloadResolutionFailure);
                    boundConstructorArguments = BuildArgumentsForErrorRecovery(analyzedArguments.ConstructorArguments, candidateConstructors);
                    diagnostics.Add(node, useSiteInfo);
                }
                else
                {
                    attributeArgumentBinder.BindDefaultArguments(
                        node,
                        attributeConstructor.Parameters,
                        analyzedArguments.ConstructorArguments.Arguments,
                        argumentRefKindsBuilder: null,
                        ref argsToParamsOpt,
                        out defaultArguments,
                        expanded,
                        enableCallerInfo: !IsEarlyAttributeBinder,
                        diagnostics,
                        attributedMember: attributedMember);
                    boundConstructorArguments = analyzedArguments.ConstructorArguments.Arguments.ToImmutable();
                    ReportDiagnosticsIfObsolete(diagnostics, attributeConstructor, node, hasBaseReceiver: false);
 
                    if (attributeConstructor.Parameters.Any(static p => p.RefKind == RefKind.In))
                    {
                        Error(diagnostics, ErrorCode.ERR_AttributeCtorInParameter, node, attributeConstructor.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
                    }
                }
            }
 
            Debug.Assert(boundConstructorArguments.All(a => !a.NeedsToBeConverted()));
 
            ImmutableArray<string?> boundConstructorArgumentNamesOpt = analyzedArguments.ConstructorArguments.GetNames();
            ImmutableArray<BoundAssignmentOperator> boundNamedArguments = analyzedArguments.NamedArguments?.ToImmutableAndFree() ?? ImmutableArray<BoundAssignmentOperator>.Empty;
            Debug.Assert(boundNamedArguments.All(arg => !arg.Right.NeedsToBeConverted()));
 
            if (attributeConstructor is not null)
            {
                CheckRequiredMembersInObjectInitializer(attributeConstructor, ImmutableArray<BoundExpression>.CastUp(boundNamedArguments), node, diagnostics);
            }
 
            analyzedArguments.ConstructorArguments.Free();
 
            return new BoundAttribute(
                node,
                attributeConstructor,
                boundConstructorArguments,
                boundConstructorArgumentNamesOpt,
                argsToParamsOpt,
                expanded,
                defaultArguments,
                boundNamedArguments,
                resultKind,
                attributeType,
                hasErrors: resultKind != LookupResultKind.Viable);
        }
 
        private CSharpAttributeData GetAttribute(BoundAttribute boundAttribute, BindingDiagnosticBag diagnostics)
        {
            var attributeType = (NamedTypeSymbol)boundAttribute.Type;
            var attributeConstructor = boundAttribute.Constructor;
 
            RoslynDebug.Assert((object)attributeType != null);
            Debug.Assert(boundAttribute.Syntax.Kind() == SyntaxKind.Attribute);
 
            bool hasErrors = boundAttribute.HasAnyErrors;
 
            if (attributeType.IsErrorType() || attributeType.IsAbstract || attributeConstructor is null)
            {
                // prevent cascading diagnostics
                Debug.Assert(hasErrors);
                return new SourceAttributeData(boundAttribute.Syntax.GetReference(), attributeType, attributeConstructor, hasErrors);
            }
 
            // Validate attribute constructor parameters have valid attribute parameter type
            ValidateTypeForAttributeParameters(attributeConstructor.Parameters, ((AttributeSyntax)boundAttribute.Syntax).Name, diagnostics, ref hasErrors);
 
            // Validate the attribute arguments and generate TypedConstant for argument's BoundExpression.
            var visitor = new AttributeExpressionVisitor(this);
            var arguments = boundAttribute.ConstructorArguments;
            var constructorArgsArray = visitor.VisitArguments(arguments, diagnostics, ref hasErrors);
            var namedArguments = visitor.VisitNamedArguments(boundAttribute.NamedArguments, diagnostics, ref hasErrors);
 
            Debug.Assert(!constructorArgsArray.IsDefault, "Property of VisitArguments");
 
            ImmutableArray<int> argsToParamsOpt = boundAttribute.ConstructorArgumentsToParamsOpt;
            ImmutableArray<TypedConstant> rewrittenArguments;
            if (hasErrors || attributeConstructor.ParameterCount == 0)
            {
                rewrittenArguments = constructorArgsArray;
            }
            else
            {
                rewrittenArguments = GetRewrittenAttributeConstructorArguments(
                    attributeConstructor,
                    constructorArgsArray,
                    boundAttribute.ConstructorArgumentNamesOpt,
                    (AttributeSyntax)boundAttribute.Syntax,
                    argsToParamsOpt,
                    diagnostics,
                    boundAttribute.ConstructorExpanded,
                    ref hasErrors);
                // Arguments and parameters length are only required to match when the attribute doesn't have errors.
                Debug.Assert(rewrittenArguments.Length == attributeConstructor.ParameterCount);
            }
 
            CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
            bool isConditionallyOmitted = IsAttributeConditionallyOmitted(attributeType, boundAttribute.SyntaxTree, ref useSiteInfo);
            diagnostics.Add(boundAttribute.Syntax, useSiteInfo);
 
            return new SourceAttributeData(
                boundAttribute.Syntax.GetReference(),
                attributeType,
                attributeConstructor,
                rewrittenArguments,
                makeSourceIndices(),
                namedArguments,
                hasErrors,
                isConditionallyOmitted);
 
            ImmutableArray<int> makeSourceIndices()
            {
                var lengthAfterRewriting = rewrittenArguments.Length;
                if (lengthAfterRewriting == 0 || hasErrors)
                {
                    return default;
                }
 
                // make source indices if we have anything that doesn't map 1:1 from arguments to parameters:
                // 1. implicit default arguments
                // 2. reordered labeled arguments
                // 3. expanded params calls
                var defaultArguments = boundAttribute.ConstructorDefaultArguments;
                if (argsToParamsOpt.IsDefault && !boundAttribute.ConstructorExpanded)
                {
                    var hasDefaultArgument = false;
                    var lengthBeforeRewriting = arguments.Length;
                    for (var i = 0; i < lengthBeforeRewriting; i++)
                    {
                        if (defaultArguments[i])
                        {
                            hasDefaultArgument = true;
                            break;
                        }
                    }
                    if (!hasDefaultArgument)
                    {
                        return default;
                    }
                }
 
                // After we do https://github.com/dotnet/roslyn/issues/49602, this assert can be
                // simplified to `argsToParamsOpt.IsDefault || argsToParamsOpt == lengthAfterRewriting`.
                Debug.Assert(argsToParamsOpt.IsDefault
                    || argsToParamsOpt.Length == lengthAfterRewriting
                    // in expanded scenarios, lengthAfterRewriting can only be larger than argsToParamsOpt by 1--otherwise it will be the same size or smaller
                    || (boundAttribute.ConstructorExpanded && lengthAfterRewriting - argsToParamsOpt.Length <= 1));
 
                var constructorArgumentSourceIndices = ArrayBuilder<int>.GetInstance(lengthAfterRewriting);
                constructorArgumentSourceIndices.Count = lengthAfterRewriting;
                for (int argIndex = 0; argIndex < lengthAfterRewriting; argIndex++)
                {
                    int paramIndex = argsToParamsOpt.IsDefault || argIndex >= argsToParamsOpt.Length ? argIndex : argsToParamsOpt[argIndex];
                    constructorArgumentSourceIndices[paramIndex] = defaultArguments[argIndex] ? -1 : argIndex;
                }
                return constructorArgumentSourceIndices.ToImmutableAndFree();
            }
        }
 
        private void ValidateTypeForAttributeParameters(ImmutableArray<ParameterSymbol> parameters, CSharpSyntaxNode syntax, BindingDiagnosticBag diagnostics, ref bool hasErrors)
        {
            foreach (var parameter in parameters)
            {
                var paramType = parameter.TypeWithAnnotations;
                Debug.Assert(paramType.HasType);
 
                if (!paramType.Type.IsValidAttributeParameterType(Compilation))
                {
                    Error(diagnostics, ErrorCode.ERR_BadAttributeParamType, syntax, parameter.Name, paramType.Type);
                    hasErrors = true;
                }
            }
        }
 
        protected bool IsAttributeConditionallyOmitted(NamedTypeSymbol attributeType, SyntaxTree? syntaxTree, ref CompoundUseSiteInfo<AssemblySymbol> useSiteInfo)
        {
            // When early binding attributes, we don't want to determine if the attribute type is conditional and if so, must be emitted or not.
            // Invoking IsConditional property on attributeType can lead to a cycle, hence we delay this computation until after early binding.
            if (IsEarlyAttributeBinder)
            {
                return false;
            }
 
            Debug.Assert((object)attributeType != null);
            Debug.Assert(!attributeType.IsErrorType());
 
            if (attributeType.IsConditional)
            {
                ImmutableArray<string> conditionalSymbols = attributeType.GetAppliedConditionalSymbols();
                Debug.Assert(conditionalSymbols != null);
                if (syntaxTree.IsAnyPreprocessorSymbolDefined(conditionalSymbols))
                {
                    return false;
                }
 
                var baseType = attributeType.BaseTypeWithDefinitionUseSiteDiagnostics(ref useSiteInfo);
                if ((object)baseType != null && baseType.IsConditional)
                {
                    return IsAttributeConditionallyOmitted(baseType, syntaxTree, ref useSiteInfo);
                }
 
                return true;
            }
            else
            {
                return false;
            }
        }
 
        /// <summary>
        /// The caller is responsible for freeing <see cref="AnalyzedAttributeArguments.ConstructorArguments"/> and <see cref="AnalyzedAttributeArguments.NamedArguments"/>.
        /// </summary>
        private AnalyzedAttributeArguments BindAttributeArguments(
            AttributeArgumentListSyntax? attributeArgumentList,
            NamedTypeSymbol attributeType,
            BindingDiagnosticBag diagnostics)
        {
            var boundConstructorArguments = AnalyzedArguments.GetInstance();
            ArrayBuilder<BoundAssignmentOperator>? boundNamedArgumentsBuilder = null;
 
            if (attributeArgumentList != null)
            {
                HashSet<string>? boundNamedArgumentsSet = null;
 
                // Only report the first "non-trailing named args required C# 7.2" error,
                // so as to avoid "cascading" errors.
                bool hadLangVersionError = false;
 
                var shouldHaveName = false;
 
                foreach (var argument in attributeArgumentList.Arguments)
                {
                    if (argument.NameEquals == null)
                    {
                        if (shouldHaveName)
                        {
                            diagnostics.Add(ErrorCode.ERR_NamedArgumentExpected, argument.Expression.GetLocation());
                        }
 
                        // Constructor argument
                        this.BindArgumentAndName(
                            boundConstructorArguments,
                            diagnostics,
                            ref hadLangVersionError,
                            argument,
                            BindArgumentExpression(diagnostics, argument.Expression, RefKind.None, allowArglist: false),
                            argument.NameColon,
                            refKind: RefKind.None);
                    }
                    else
                    {
                        shouldHaveName = true;
 
                        // Named argument
                        // TODO: use fully qualified identifier name for boundNamedArgumentsSet
                        string argumentName = argument.NameEquals.Name.Identifier.ValueText!;
                        if (boundNamedArgumentsBuilder == null)
                        {
                            boundNamedArgumentsBuilder = ArrayBuilder<BoundAssignmentOperator>.GetInstance();
                            boundNamedArgumentsSet = new HashSet<string>();
                        }
                        else if (boundNamedArgumentsSet!.Contains(argumentName))
                        {
                            // Duplicate named argument
                            Error(diagnostics, ErrorCode.ERR_DuplicateNamedAttributeArgument, argument, argumentName);
                        }
 
                        BoundAssignmentOperator boundNamedArgument = BindNamedAttributeArgument(argument, attributeType, diagnostics);
                        boundNamedArgumentsBuilder.Add(boundNamedArgument);
                        boundNamedArgumentsSet.Add(argumentName);
                    }
                }
            }
 
            return new AnalyzedAttributeArguments(boundConstructorArguments, boundNamedArgumentsBuilder);
        }
 
        private BoundAssignmentOperator BindNamedAttributeArgument(AttributeArgumentSyntax namedArgument, NamedTypeSymbol attributeType, BindingDiagnosticBag diagnostics)
        {
            bool wasError;
            LookupResultKind resultKind;
            Symbol namedArgumentNameSymbol = BindNamedAttributeArgumentName(namedArgument, attributeType, diagnostics, out wasError, out resultKind);
 
            ReportDiagnosticsIfObsolete(diagnostics, namedArgumentNameSymbol, namedArgument, hasBaseReceiver: false);
 
            if (namedArgumentNameSymbol.Kind == SymbolKind.Property)
            {
                var propertySymbol = (PropertySymbol)namedArgumentNameSymbol;
                var setMethod = propertySymbol.GetOwnOrInheritedSetMethod();
                if (setMethod != null)
                {
                    ReportDiagnosticsIfObsolete(diagnostics, setMethod, namedArgument, hasBaseReceiver: false);
 
                    if (setMethod.IsInitOnly && setMethod.DeclaringCompilation != this.Compilation)
                    {
                        // an error would have already been reported on declaring an init-only setter
                        CheckFeatureAvailability(namedArgument, MessageID.IDS_FeatureInitOnlySetters, diagnostics);
                    }
                }
            }
 
            Debug.Assert(resultKind == LookupResultKind.Viable || wasError);
 
            TypeSymbol namedArgumentType;
            if (wasError)
            {
                namedArgumentType = CreateErrorType();  // don't generate cascaded errors.
            }
            else
            {
                namedArgumentType = BindNamedAttributeArgumentType(namedArgument, namedArgumentNameSymbol, attributeType, diagnostics);
            }
 
            // BindRValue just binds the expression without doing any validation (if its a valid expression for attribute argument).
            // Validation is done later by AttributeExpressionVisitor
            BoundExpression namedArgumentValue = this.BindValue(namedArgument.Expression, diagnostics, BindValueKind.RValue);
            namedArgumentValue = GenerateConversionForAssignment(namedArgumentType, namedArgumentValue, diagnostics);
 
            // TODO: should we create an entry even if there are binding errors?
            var fieldSymbol = namedArgumentNameSymbol as FieldSymbol;
            RoslynDebug.Assert(namedArgument.NameEquals is object);
            IdentifierNameSyntax nameSyntax = namedArgument.NameEquals.Name;
            BoundExpression lvalue;
            if (fieldSymbol is object)
            {
                var containingAssembly = fieldSymbol.ContainingAssembly as SourceAssemblySymbol;
 
                // We do not want to generate any unassigned field or unreferenced field diagnostics.
                containingAssembly?.NoteFieldAccess(fieldSymbol, read: true, write: true);
 
                lvalue = new BoundFieldAccess(nameSyntax, null, fieldSymbol, ConstantValue.NotAvailable, resultKind, fieldSymbol.Type);
            }
            else
            {
                var propertySymbol = namedArgumentNameSymbol as PropertySymbol;
                if (propertySymbol is object)
                {
                    lvalue = new BoundPropertyAccess(nameSyntax, null, propertySymbol, resultKind, namedArgumentType);
                }
                else
                {
                    lvalue = BadExpression(nameSyntax, resultKind);
                }
            }
 
            return new BoundAssignmentOperator(namedArgument, lvalue, namedArgumentValue, namedArgumentType);
        }
 
        private Symbol BindNamedAttributeArgumentName(AttributeArgumentSyntax namedArgument, NamedTypeSymbol attributeType, BindingDiagnosticBag diagnostics, out bool wasError, out LookupResultKind resultKind)
        {
            RoslynDebug.Assert(namedArgument.NameEquals is object);
            var identifierName = namedArgument.NameEquals.Name;
            var name = identifierName.Identifier.ValueText;
            LookupResult result = LookupResult.GetInstance();
            CompoundUseSiteInfo<AssemblySymbol> useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics);
            this.LookupMembersWithFallback(result, attributeType, name, 0, ref useSiteInfo);
            diagnostics.Add(identifierName, useSiteInfo);
            Symbol resultSymbol = this.ResultSymbol(result, name, 0, identifierName, diagnostics, false, out wasError, qualifierOpt: null);
            resultKind = result.Kind;
            result.Free();
            return resultSymbol;
        }
 
        private TypeSymbol BindNamedAttributeArgumentType(AttributeArgumentSyntax namedArgument, Symbol namedArgumentNameSymbol, NamedTypeSymbol attributeType, BindingDiagnosticBag diagnostics)
        {
            if (namedArgumentNameSymbol.Kind == SymbolKind.ErrorType)
            {
                return (TypeSymbol)namedArgumentNameSymbol;
            }
 
            // SPEC:    For each named-argument Arg in named-argument-list N:
            // SPEC:        Let Name be the identifier of the named-argument Arg.
            // SPEC:        Name must identify a non-static read-write public field or property on 
            // SPEC:            attribute class T. If T has no such field or property, then a compile-time error occurs.
 
            bool invalidNamedArgument = false;
            TypeSymbol? namedArgumentType = null;
            invalidNamedArgument |= (namedArgumentNameSymbol.DeclaredAccessibility != Accessibility.Public);
            invalidNamedArgument |= namedArgumentNameSymbol.IsStatic;
 
            if (!invalidNamedArgument)
            {
                switch (namedArgumentNameSymbol.Kind)
                {
                    case SymbolKind.Field:
                        var fieldSymbol = (FieldSymbol)namedArgumentNameSymbol;
                        namedArgumentType = fieldSymbol.Type;
                        invalidNamedArgument |= fieldSymbol.IsReadOnly;
                        invalidNamedArgument |= fieldSymbol.IsConst;
                        break;
 
                    case SymbolKind.Property:
                        var propertySymbol = ((PropertySymbol)namedArgumentNameSymbol).GetLeastOverriddenProperty(this.ContainingType);
                        namedArgumentType = propertySymbol.Type;
                        invalidNamedArgument |= propertySymbol.IsReadOnly;
                        var getMethod = propertySymbol.GetMethod;
                        var setMethod = propertySymbol.SetMethod;
                        invalidNamedArgument = invalidNamedArgument || (object)getMethod == null || (object)setMethod == null;
                        if (!invalidNamedArgument)
                        {
                            invalidNamedArgument =
                                getMethod!.DeclaredAccessibility != Accessibility.Public ||
                                setMethod!.DeclaredAccessibility != Accessibility.Public;
                        }
                        break;
 
                    default:
                        invalidNamedArgument = true;
                        break;
                }
            }
 
            if (invalidNamedArgument)
            {
                RoslynDebug.Assert(namedArgument.NameEquals is object);
                return new ExtendedErrorTypeSymbol(attributeType,
                    namedArgumentNameSymbol,
                    LookupResultKind.NotAVariable,
                    diagnostics.Add(ErrorCode.ERR_BadNamedAttributeArgument,
                        namedArgument.NameEquals.Name.Location,
                        namedArgumentNameSymbol.Name));
            }
 
            RoslynDebug.Assert(namedArgumentType is object);
 
            if (!namedArgumentType.IsValidAttributeParameterType(Compilation))
            {
                RoslynDebug.Assert(namedArgument.NameEquals is object);
                return new ExtendedErrorTypeSymbol(attributeType,
                    namedArgumentNameSymbol,
                    LookupResultKind.NotAVariable,
                    diagnostics.Add(ErrorCode.ERR_BadNamedAttributeArgumentType,
                        namedArgument.NameEquals.Name.Location,
                        namedArgumentNameSymbol.Name));
            }
 
            return namedArgumentType;
        }
 
        /// <summary>
        /// Gets the rewritten attribute constructor arguments, i.e. the arguments
        /// are in the order of parameters, which may differ from the source
        /// if named constructor arguments are used.
        /// 
        /// For example:
        ///     void Goo(int x, int y, int z, int w = 3);
        /// 
        ///     Goo(0, z: 2, y: 1);
        ///     
        ///     Arguments returned: 0, 1, 2, 3
        /// </summary>
        /// <returns>Rewritten attribute constructor arguments</returns>
        /// <remarks>
        /// CONSIDER: Can we share some code will call rewriting in the local rewriter?
        /// </remarks>
        private ImmutableArray<TypedConstant> GetRewrittenAttributeConstructorArguments(
            MethodSymbol attributeConstructor,
            ImmutableArray<TypedConstant> constructorArgsArray,
            ImmutableArray<string?> constructorArgumentNamesOpt,
            AttributeSyntax syntax,
            ImmutableArray<int> argumentsToParams,
            BindingDiagnosticBag diagnostics,
            bool expanded,
            ref bool hasErrors)
        {
            RoslynDebug.Assert((object)attributeConstructor != null);
            Debug.Assert(!constructorArgsArray.IsDefault);
            Debug.Assert(!hasErrors);
 
            int argumentsCount = constructorArgsArray.Length;
 
            ImmutableArray<ParameterSymbol> parameters = attributeConstructor.Parameters;
            int parameterCount = parameters.Length;
 
            var reorderedArguments = new TypedConstant[parameterCount];
            for (int i = 0; i < argumentsCount; i++)
            {
                var paramIndex = argumentsToParams.IsDefault ? i : argumentsToParams[i];
                ParameterSymbol parameter = parameters[paramIndex];
 
                TypedConstant reorderedArgument;
                if (parameter.IsParams && parameter.Type.IsSZArray())
                {
                    reorderedArgument = GetParamArrayArgument(
                        parameter,
                        constructorArgsArray,
                        constructorArgumentNamesOpt,
                        argumentsCount,
                        currentArgumentIndex: i,
                        this.Conversions,
                        endOfParamsArrayIndex: out i);
                }
                else
                {
                    reorderedArgument = constructorArgsArray[i];
                }
 
                if (!hasErrors)
                {
                    if (reorderedArgument.Kind == TypedConstantKind.Error)
                    {
                        hasErrors = true;
                    }
                    else if (reorderedArgument.Kind == TypedConstantKind.Array &&
                        parameter.Type.TypeKind == TypeKind.Array &&
                        !((TypeSymbol)reorderedArgument.TypeInternal!).Equals(parameter.Type, TypeCompareKind.AllIgnoreOptions))
                    {
                        // NOTE: As in dev11, we don't allow array covariance conversions (presumably, we don't have a way to
                        // represent the conversion in metadata).
                        diagnostics.Add(ErrorCode.ERR_BadAttributeArgument, syntax.Location);
                        hasErrors = true;
                    }
                }
 
                reorderedArguments[paramIndex] = reorderedArgument;
            }
 
            // If we are in expanded form and no explicit argument was provided for the params array, then create the empty params array now.
            if (expanded && reorderedArguments[^1].Kind == TypedConstantKind.Error)
            {
                var paramArray = parameters[^1];
                Debug.Assert(paramArray.IsParams);
                reorderedArguments[^1] = new TypedConstant(paramArray.Type, ImmutableArray<TypedConstant>.Empty);
            }
 
            Debug.Assert(hasErrors || reorderedArguments.All(arg => arg.Kind != TypedConstantKind.Error));
            return reorderedArguments.AsImmutable();
        }
 
        // This should eventually be moved to initial binding.
        // https://github.com/dotnet/roslyn/issues/49602
        private static TypedConstant GetParamArrayArgument(
            ParameterSymbol parameter,
            ImmutableArray<TypedConstant> constructorArgsArray,
            ImmutableArray<string?> constructorArgumentNamesOpt,
            int argumentsCount,
            int currentArgumentIndex,
            Conversions conversions,
            out int endOfParamsArrayIndex)
        {
            Debug.Assert(currentArgumentIndex <= argumentsCount);
 
            // If there's a named argument, we'll use that
            if (!constructorArgumentNamesOpt.IsDefault && constructorArgumentNamesOpt.Contains(parameter.Name))
            {
                Debug.Assert(constructorArgumentNamesOpt.IndexOf(parameter.Name) == currentArgumentIndex);
                endOfParamsArrayIndex = currentArgumentIndex;
                if (TryGetNormalParamValue(parameter, constructorArgsArray, currentArgumentIndex, conversions, out var namedValue))
                {
                    return namedValue;
                }
 
                // A named argument for a params parameter is necessarily the only one for that parameter
                return new TypedConstant(parameter.Type, ImmutableArray.Create(constructorArgsArray[currentArgumentIndex]));
            }
 
            int paramArrayArgCount = argumentsCount - currentArgumentIndex;
 
            // If there are zero arguments left
            if (paramArrayArgCount == 0)
            {
                endOfParamsArrayIndex = argumentsCount - 1;
                return new TypedConstant(parameter.Type, ImmutableArray<TypedConstant>.Empty);
            }
 
            // If there's exactly one argument left, we'll try to use it in normal form
            if (paramArrayArgCount == 1 &&
                TryGetNormalParamValue(parameter, constructorArgsArray, currentArgumentIndex, conversions, out var lastValue))
            {
                endOfParamsArrayIndex = argumentsCount - 1;
                return lastValue;
            }
 
            Debug.Assert(!constructorArgsArray.IsDefault);
            Debug.Assert(currentArgumentIndex <= constructorArgsArray.Length);
 
            // Take the trailing arguments as an array for expanded form
            var values = new TypedConstant[paramArrayArgCount];
 
            for (int i = 0; i < paramArrayArgCount; i++)
            {
                values[i] = constructorArgsArray[currentArgumentIndex++];
            }
 
            endOfParamsArrayIndex = currentArgumentIndex + paramArrayArgCount - 1;
            return new TypedConstant(parameter.Type, values.AsImmutableOrNull());
        }
 
        private static bool TryGetNormalParamValue(ParameterSymbol parameter, ImmutableArray<TypedConstant> constructorArgsArray,
            int argIndex, Conversions conversions, out TypedConstant result)
        {
            TypedConstant argument = constructorArgsArray[argIndex];
            if (argument.Kind != TypedConstantKind.Array)
            {
                result = default;
                return false;
            }
 
            Debug.Assert(argument.TypeInternal is object);
            var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded; // ignoring, since already bound argument and parameter
            Conversion conversion = conversions.ClassifyBuiltInConversion((TypeSymbol)argument.TypeInternal, parameter.Type, isChecked: false, ref discardedUseSiteInfo);
 
            // NOTE: Won't always succeed, even though we've performed overload resolution.
            // For example, passing int[] to params object[] actually treats the int[] as an element of the object[].
            if (conversion.IsValid && (conversion.Kind == ConversionKind.ImplicitReference || conversion.Kind == ConversionKind.Identity))
            {
                result = argument;
                return true;
            }
 
            result = default;
            return false;
        }
 
        #endregion
 
        #region AttributeExpressionVisitor
 
        /// <summary>
        /// Walk a custom attribute argument bound node and return a TypedConstant.  Verify that the expression is a constant expression.
        /// </summary>
        private readonly struct AttributeExpressionVisitor
        {
            private readonly Binder _binder;
 
            public AttributeExpressionVisitor(Binder binder)
            {
                _binder = binder;
            }
 
            public ImmutableArray<TypedConstant> VisitArguments(ImmutableArray<BoundExpression> arguments, BindingDiagnosticBag diagnostics, ref bool attrHasErrors, bool parentHasErrors = false)
            {
                var validatedArguments = ImmutableArray<TypedConstant>.Empty;
 
                int numArguments = arguments.Length;
                if (numArguments > 0)
                {
                    var builder = ArrayBuilder<TypedConstant>.GetInstance(numArguments);
                    foreach (var argument in arguments)
                    {
                        // current argument has errors if parent had errors OR argument.HasErrors.
                        bool curArgumentHasErrors = parentHasErrors || argument.HasAnyErrors;
 
                        builder.Add(VisitExpression(argument, diagnostics, ref attrHasErrors, curArgumentHasErrors));
                    }
                    validatedArguments = builder.ToImmutableAndFree();
                }
 
                return validatedArguments;
            }
 
            public ImmutableArray<KeyValuePair<string, TypedConstant>> VisitNamedArguments(ImmutableArray<BoundAssignmentOperator> arguments, BindingDiagnosticBag diagnostics, ref bool attrHasErrors)
            {
                ArrayBuilder<KeyValuePair<string, TypedConstant>>? builder = null;
                foreach (var argument in arguments)
                {
                    var kv = VisitNamedArgument(argument, diagnostics, ref attrHasErrors);
 
                    if (kv.HasValue)
                    {
                        if (builder == null)
                        {
                            builder = ArrayBuilder<KeyValuePair<string, TypedConstant>>.GetInstance();
                        }
 
                        builder.Add(kv.Value);
                    }
                }
 
                if (builder == null)
                {
                    return ImmutableArray<KeyValuePair<string, TypedConstant>>.Empty;
                }
 
                return builder.ToImmutableAndFree();
            }
 
            private KeyValuePair<String, TypedConstant>? VisitNamedArgument(BoundAssignmentOperator assignment, BindingDiagnosticBag diagnostics, ref bool attrHasErrors)
            {
                KeyValuePair<String, TypedConstant>? visitedArgument = null;
 
                switch (assignment.Left.Kind)
                {
                    case BoundKind.FieldAccess:
                        var fa = (BoundFieldAccess)assignment.Left;
                        visitedArgument = new KeyValuePair<String, TypedConstant>(fa.FieldSymbol.Name, VisitExpression(assignment.Right, diagnostics, ref attrHasErrors, assignment.HasAnyErrors));
                        break;
 
                    case BoundKind.PropertyAccess:
                        var pa = (BoundPropertyAccess)assignment.Left;
                        visitedArgument = new KeyValuePair<String, TypedConstant>(pa.PropertySymbol.Name, VisitExpression(assignment.Right, diagnostics, ref attrHasErrors, assignment.HasAnyErrors));
                        break;
                }
 
                return visitedArgument;
            }
 
            // SPEC:    An expression E is an attribute-argument-expression if all of the following statements are true:
            // SPEC:    1) The type of E is an attribute parameter type (§17.1.3).
            // SPEC:    2) At compile-time, the value of Expression can be resolved to one of the following:
            // SPEC:        a) A constant value.
            // SPEC:        b) A System.Type object.
            // SPEC:        c) A one-dimensional array of attribute-argument-expressions
 
            private TypedConstant VisitExpression(BoundExpression node, BindingDiagnosticBag diagnostics, ref bool attrHasErrors, bool curArgumentHasErrors)
            {
                // Validate Statement 1) of the spec comment above.
 
                RoslynDebug.Assert(node.Type is object);
                var typedConstantKind = node.Type.GetAttributeParameterTypedConstantKind(_binder.Compilation);
 
                return VisitExpression(node, typedConstantKind, diagnostics, ref attrHasErrors, curArgumentHasErrors || typedConstantKind == TypedConstantKind.Error);
            }
 
            private TypedConstant VisitExpression(BoundExpression node, TypedConstantKind typedConstantKind, BindingDiagnosticBag diagnostics, ref bool attrHasErrors, bool curArgumentHasErrors)
            {
                // Validate Statement 2) of the spec comment above.
 
                ConstantValue? constantValue = node.ConstantValueOpt;
                if (constantValue != null)
                {
                    if (constantValue.IsBad)
                    {
                        typedConstantKind = TypedConstantKind.Error;
                    }
 
                    ConstantValueUtils.CheckLangVersionForConstantValue(node, diagnostics);
 
                    return CreateTypedConstant(node, typedConstantKind, diagnostics, ref attrHasErrors, curArgumentHasErrors, simpleValue: constantValue.Value);
                }
 
                switch (node.Kind)
                {
                    case BoundKind.Conversion:
                        return VisitConversion((BoundConversion)node, diagnostics, ref attrHasErrors, curArgumentHasErrors);
                    case BoundKind.TypeOfOperator:
                        return VisitTypeOfExpression((BoundTypeOfOperator)node, diagnostics, ref attrHasErrors, curArgumentHasErrors);
                    case BoundKind.ArrayCreation:
                        return VisitArrayCreation((BoundArrayCreation)node, diagnostics, ref attrHasErrors, curArgumentHasErrors);
                    default:
                        return CreateTypedConstant(node, TypedConstantKind.Error, diagnostics, ref attrHasErrors, curArgumentHasErrors);
                }
            }
 
            private TypedConstant VisitConversion(BoundConversion node, BindingDiagnosticBag diagnostics, ref bool attrHasErrors, bool curArgumentHasErrors)
            {
                Debug.Assert(node.ConstantValueOpt == null);
 
                // We have a bound conversion with a non-constant value.
                // According to statement 2) of the spec comment, this is not a valid attribute argument.
                // However, native compiler allows conversions to object type if the conversion operand is a valid attribute argument.
                // See method AttributeHelper::VerifyAttrArg(EXPR *arg).
 
                // We will match native compiler's behavior here.
                // Devdiv Bug #8763: Additionally we allow conversions from array type to object[], provided a conversion exists and each array element is a valid attribute argument.
 
                var type = node.Type;
                var operand = node.Operand;
                var operandType = operand.Type;
 
                if ((object)type != null && operandType is object)
                {
                    if (type.SpecialType == SpecialType.System_Object ||
                        operandType.IsArray() && type.IsArray() &&
                        ((ArrayTypeSymbol)type).ElementType.SpecialType == SpecialType.System_Object)
                    {
                        var typedConstantKind = operandType.GetAttributeParameterTypedConstantKind(_binder.Compilation);
                        return VisitExpression(operand, typedConstantKind, diagnostics, ref attrHasErrors, curArgumentHasErrors);
                    }
                }
 
                return CreateTypedConstant(node, TypedConstantKind.Error, diagnostics, ref attrHasErrors, curArgumentHasErrors);
            }
 
            private static TypedConstant VisitTypeOfExpression(BoundTypeOfOperator node, BindingDiagnosticBag diagnostics, ref bool attrHasErrors, bool curArgumentHasErrors)
            {
                var typeOfArgument = (TypeSymbol?)node.SourceType.Type;
 
                // typeof argument is allowed to be:
                //  (a) an unbound type
                //  (b) closed constructed type
                // typeof argument cannot be an open type
 
                if (typeOfArgument is object) // skip this if the argument was an alias symbol
                {
                    var isValidArgument = true;
                    switch (typeOfArgument.Kind)
                    {
                        case SymbolKind.TypeParameter:
                            // type parameter represents an open type
                            isValidArgument = false;
                            break;
 
                        default:
                            isValidArgument = typeOfArgument.IsUnboundGenericType() || !typeOfArgument.ContainsTypeParameter();
                            break;
                    }
 
                    if (!isValidArgument && !curArgumentHasErrors)
                    {
                        // attribute argument type cannot be an open type
                        Binder.Error(diagnostics, ErrorCode.ERR_AttrArgWithTypeVars, node.Syntax, typeOfArgument.ToDisplayString(SymbolDisplayFormat.CSharpErrorMessageFormat));
                        curArgumentHasErrors = true;
                        attrHasErrors = true;
                    }
                }
 
                return CreateTypedConstant(node, TypedConstantKind.Type, diagnostics, ref attrHasErrors, curArgumentHasErrors, simpleValue: node.SourceType.Type);
            }
 
            private TypedConstant VisitArrayCreation(BoundArrayCreation node, BindingDiagnosticBag diagnostics, ref bool attrHasErrors, bool curArgumentHasErrors)
            {
                ImmutableArray<BoundExpression> bounds = node.Bounds;
                int boundsCount = bounds.Length;
 
                if (boundsCount > 1)
                {
                    return CreateTypedConstant(node, TypedConstantKind.Error, diagnostics, ref attrHasErrors, curArgumentHasErrors);
                }
 
                var type = (ArrayTypeSymbol)node.Type;
                var typedConstantKind = type.GetAttributeParameterTypedConstantKind(_binder.Compilation);
 
                ImmutableArray<TypedConstant> initializer;
                if (node.InitializerOpt == null)
                {
                    if (boundsCount == 0)
                    {
                        initializer = ImmutableArray<TypedConstant>.Empty;
                    }
                    else
                    {
                        if (bounds[0].IsDefaultValue())
                        {
                            initializer = ImmutableArray<TypedConstant>.Empty;
                        }
                        else
                        {
                            // error: non-constant array creation
                            initializer = ImmutableArray.Create(CreateTypedConstant(node, TypedConstantKind.Error, diagnostics, ref attrHasErrors, curArgumentHasErrors));
                        }
                    }
                }
                else
                {
                    initializer = VisitArguments(node.InitializerOpt.Initializers, diagnostics, ref attrHasErrors, curArgumentHasErrors);
                }
 
                return CreateTypedConstant(node, typedConstantKind, diagnostics, ref attrHasErrors, curArgumentHasErrors, arrayValue: initializer);
            }
 
            private static TypedConstant CreateTypedConstant(BoundExpression node, TypedConstantKind typedConstantKind, BindingDiagnosticBag diagnostics, ref bool attrHasErrors, bool curArgumentHasErrors,
                object? simpleValue = null, ImmutableArray<TypedConstant> arrayValue = default(ImmutableArray<TypedConstant>))
            {
                var type = node.Type;
                RoslynDebug.Assert(type is object);
 
                if (typedConstantKind != TypedConstantKind.Error && type.ContainsTypeParameter())
                {
                    // Devdiv Bug #12636: Constant values of open types should not be allowed in attributes
 
                    // SPEC ERROR:  C# language specification does not explicitly disallow constant values of open types. For e.g.
 
                    //  public class C<T>
                    //  {
                    //      public enum E { V }
                    //  }
                    //
                    //  [SomeAttr(C<T>.E.V)]        // case (a): Constant value of open type.
                    //  [SomeAttr(C<int>.E.V)]      // case (b): Constant value of constructed type.
 
                    // Both expressions 'C<T>.E.V' and 'C<int>.E.V' satisfy the requirements for a valid attribute-argument-expression:
                    //  (a) Its type is a valid attribute parameter type as per section 17.1.3 of the specification.
                    //  (b) It has a compile time constant value.
 
                    // However, native compiler disallows both the above cases.
                    // We disallow case (a) as it cannot be serialized correctly, but allow case (b) to compile.
 
                    typedConstantKind = TypedConstantKind.Error;
                }
 
                if (typedConstantKind == TypedConstantKind.Error)
                {
                    if (!curArgumentHasErrors)
                    {
                        Binder.Error(diagnostics, ErrorCode.ERR_BadAttributeArgument, node.Syntax);
                        attrHasErrors = true;
                    }
 
                    return new TypedConstant(type, TypedConstantKind.Error, null);
                }
                else if (typedConstantKind == TypedConstantKind.Array)
                {
                    return new TypedConstant(type, arrayValue);
                }
                else
                {
                    return new TypedConstant(type, typedConstantKind, simpleValue);
                }
            }
        }
 
        #endregion
 
        #region AnalyzedAttributeArguments
 
        private readonly struct AnalyzedAttributeArguments
        {
            internal readonly AnalyzedArguments ConstructorArguments;
            internal readonly ArrayBuilder<BoundAssignmentOperator>? NamedArguments;
 
            internal AnalyzedAttributeArguments(AnalyzedArguments constructorArguments, ArrayBuilder<BoundAssignmentOperator>? namedArguments)
            {
                this.ConstructorArguments = constructorArguments;
                this.NamedArguments = namedArguments;
            }
        }
 
        #endregion
    }
}