File: Compilation\SyntaxTreeSemanticModel.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.
 
#pragma warning disable RSEXPERIMENTAL001 // Internal use of experimental API
#nullable disable
 
using System;
using System.Collections.Generic;
using System.Collections.Immutable;
using System.Diagnostics;
using System.Linq;
using System.Threading;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.PooledObjects;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
 
namespace Microsoft.CodeAnalysis.CSharp
{
    /// <summary>
    /// Allows asking semantic questions about any node in a SyntaxTree within a Compilation.
    /// </summary>
    internal partial class SyntaxTreeSemanticModel : PublicSemanticModel
    {
        private readonly CSharpCompilation _compilation;
        private readonly SyntaxTree _syntaxTree;
 
        /// <summary>
        /// Note, the name of this field could be somewhat confusing because it is also 
        /// used to store models for attributes and default parameter values, which are
        /// not members.
        /// </summary>
        private ImmutableDictionary<CSharpSyntaxNode, MemberSemanticModel> _memberModels = ImmutableDictionary<CSharpSyntaxNode, MemberSemanticModel>.Empty;
 
        private readonly BinderFactory _binderFactory;
        private Func<CSharpSyntaxNode, MemberSemanticModel> _createMemberModelFunction;
        private readonly SemanticModelOptions _options;
        private ScriptLocalScopeBinder.Labels _globalStatementLabels;
 
        private static readonly Func<CSharpSyntaxNode, bool> s_isMemberDeclarationFunction = IsMemberDeclaration;
 
        internal SyntaxTreeSemanticModel(CSharpCompilation compilation, SyntaxTree syntaxTree, SemanticModelOptions options)
        {
            _compilation = compilation;
            _syntaxTree = syntaxTree;
            _options = options;
 
            _binderFactory = compilation.GetBinderFactory(SyntaxTree, (options & SemanticModelOptions.IgnoreAccessibility) != 0);
        }
 
        internal SyntaxTreeSemanticModel(CSharpCompilation parentCompilation, SyntaxTree parentSyntaxTree, SyntaxTree speculatedSyntaxTree, SemanticModelOptions options)
        {
            _compilation = parentCompilation;
            _syntaxTree = speculatedSyntaxTree;
            _binderFactory = _compilation.GetBinderFactory(parentSyntaxTree, ignoreAccessibility: (options & SemanticModelOptions.IgnoreAccessibility) != 0);
            _options = options;
        }
 
        /// <summary>
        /// The compilation this object was obtained from.
        /// </summary>
        public override CSharpCompilation Compilation
        {
            get
            {
                return _compilation;
            }
        }
 
        /// <summary>
        /// The root node of the syntax tree that this object is associated with.
        /// </summary>
        internal override CSharpSyntaxNode Root
        {
            get
            {
                return (CSharpSyntaxNode)_syntaxTree.GetRoot();
            }
        }
 
        /// <summary>
        /// The SyntaxTree that this object is associated with.
        /// </summary>
        public override SyntaxTree SyntaxTree
        {
            get
            {
                return _syntaxTree;
            }
        }
 
        internal SemanticModelOptions Options => _options;
 
        /// <summary>
        /// Returns true if this is a SemanticModel that ignores accessibility rules when answering semantic questions.
        /// </summary>
        public override bool IgnoresAccessibility
        {
            get { return (_options & SemanticModelOptions.IgnoreAccessibility) != 0; }
        }
 
        public override bool NullableAnalysisIsDisabled => (_options & SemanticModelOptions.DisableNullableAnalysis) != 0;
 
        private void VerifySpanForGetDiagnostics(TextSpan? span)
        {
            if (span.HasValue && !this.Root.FullSpan.Contains(span.Value))
            {
                throw new ArgumentException("span");
            }
        }
 
        public override ImmutableArray<Diagnostic> GetSyntaxDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            VerifySpanForGetDiagnostics(span);
            return Compilation.GetDiagnosticsForSyntaxTree(
            CompilationStage.Parse, this.SyntaxTree, span, includeEarlierStages: false, cancellationToken: cancellationToken);
        }
 
        public override ImmutableArray<Diagnostic> GetDeclarationDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            VerifySpanForGetDiagnostics(span);
            return Compilation.GetDiagnosticsForSyntaxTree(
            CompilationStage.Declare, this.SyntaxTree, span, includeEarlierStages: false, cancellationToken: cancellationToken);
        }
 
        public override ImmutableArray<Diagnostic> GetMethodBodyDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            VerifySpanForGetDiagnostics(span);
            return Compilation.GetDiagnosticsForSyntaxTree(
            CompilationStage.Compile, this.SyntaxTree, span, includeEarlierStages: false, cancellationToken: cancellationToken);
        }
 
        public override ImmutableArray<Diagnostic> GetDiagnostics(TextSpan? span = null, CancellationToken cancellationToken = default(CancellationToken))
        {
            VerifySpanForGetDiagnostics(span);
            return Compilation.GetDiagnosticsForSyntaxTree(
            CompilationStage.Compile, this.SyntaxTree, span, includeEarlierStages: true, cancellationToken: cancellationToken);
        }
#nullable disable
 
        /// <summary>
        /// Gets the enclosing binder associated with the node
        /// </summary>
        /// <param name="position"></param>
        /// <returns></returns>
        internal override Binder GetEnclosingBinderInternal(int position)
        {
            AssertPositionAdjusted(position);
            SyntaxToken token = this.Root.FindTokenIncludingCrefAndNameAttributes(position);
 
            // If we're before the start of the first token, just return
            // the binder for the compilation unit.
            if (position == 0 && position != token.SpanStart)
            {
                return _binderFactory.GetBinder(this.Root, position).WithAdditionalFlags(GetSemanticModelBinderFlags());
            }
 
            MemberSemanticModel memberModel = GetMemberModel(position);
            if (memberModel != null)
            {
                return memberModel.GetEnclosingBinder(position);
            }
 
            return _binderFactory.GetBinder((CSharpSyntaxNode)token.Parent, position).WithAdditionalFlags(GetSemanticModelBinderFlags());
        }
 
        internal override IOperation GetOperationWorker(CSharpSyntaxNode node, CancellationToken cancellationToken)
        {
            MemberSemanticModel model;
 
            switch (node)
            {
                case ConstructorDeclarationSyntax constructor:
                    model = (constructor.HasAnyBody() || constructor.Initializer != null) ? GetOrAddModel(node) : null;
                    break;
                case BaseMethodDeclarationSyntax method:
                    model = method.HasAnyBody() ? GetOrAddModel(node) : null;
                    break;
                case AccessorDeclarationSyntax accessor:
                    model = (accessor.Body != null || accessor.ExpressionBody != null) ? GetOrAddModel(node) : null;
                    break;
                case TypeDeclarationSyntax { ParameterList: { }, PrimaryConstructorBaseTypeIfClass: { } } typeDeclaration when TryGetSynthesizedPrimaryConstructor(typeDeclaration) is SynthesizedPrimaryConstructor:
                    model = GetOrAddModel(typeDeclaration);
                    break;
                default:
                    model = this.GetMemberModel(node);
                    break;
            }
 
            if (model != null)
            {
                return model.GetOperationWorker(node, cancellationToken);
            }
            else
            {
                return null;
            }
        }
 
        internal override SymbolInfo GetSymbolInfoWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken))
        {
            ValidateSymbolInfoOptions(options);
 
            // in case this is right side of a qualified name or member access (or part of a cref)
            node = SyntaxFactory.GetStandaloneNode(node);
 
            var model = this.GetMemberModel(node);
            SymbolInfo result;
 
            XmlNameAttributeSyntax attrSyntax;
            CrefSyntax crefSyntax;
 
            if (model != null)
            {
                // Expression occurs in an executable code (method body or initializer) context. Use that
                // model to get the information.
                result = model.GetSymbolInfoWorker(node, options, cancellationToken);
 
                // If we didn't get anything and were in Type/Namespace only context, let's bind normally and see
                // if any symbol comes out.
                if ((object)result.Symbol == null && result.CandidateReason == CandidateReason.None && node is ExpressionSyntax && SyntaxFacts.IsInNamespaceOrTypeContext((ExpressionSyntax)node))
                {
                    var binder = this.GetEnclosingBinder(GetAdjustedNodePosition(node));
 
                    if (binder != null)
                    {
                        // Wrap the binder in a LocalScopeBinder because Binder.BindExpression assumes there
                        // will be one in the binder chain and one isn't necessarily required for the batch case.
                        binder = new LocalScopeBinder(binder);
 
                        BoundExpression bound = binder.BindExpression((ExpressionSyntax)node, BindingDiagnosticBag.Discarded);
 
                        SymbolInfo info = GetSymbolInfoForNode(options, bound, bound, boundNodeForSyntacticParent: null, binderOpt: null);
                        if ((object)info.Symbol != null)
                        {
                            result = new SymbolInfo(ImmutableArray.Create<ISymbol>(info.Symbol), CandidateReason.NotATypeOrNamespace);
                        }
                        else if (!info.CandidateSymbols.IsEmpty)
                        {
                            result = new SymbolInfo(info.CandidateSymbols, CandidateReason.NotATypeOrNamespace);
                        }
                    }
                }
            }
            else if (node.Parent.Kind() == SyntaxKind.XmlNameAttribute && (attrSyntax = (XmlNameAttributeSyntax)node.Parent).Identifier == node)
            {
                result = SymbolInfo.None;
 
                var binder = this.GetEnclosingBinder(GetAdjustedNodePosition(node));
                if (binder != null)
                {
                    var discardedUseSiteInfo = CompoundUseSiteInfo<AssemblySymbol>.Discarded;
                    var symbols = binder.BindXmlNameAttribute(attrSyntax, ref discardedUseSiteInfo);
 
                    // NOTE: We don't need to call GetSymbolInfoForSymbol because the symbols
                    // can only be parameters or type parameters.
                    Debug.Assert(symbols.All(s => s.Kind == SymbolKind.TypeParameter || s.Kind == SymbolKind.Parameter));
 
                    switch (symbols.Length)
                    {
                        case 0:
                            result = SymbolInfo.None;
                            break;
                        case 1:
                            result = SymbolInfoFactory.Create(symbols, LookupResultKind.Viable, isDynamic: false);
                            break;
                        default:
                            result = SymbolInfoFactory.Create(symbols, LookupResultKind.Ambiguous, isDynamic: false);
                            break;
                    }
                }
            }
            else if ((crefSyntax = node as CrefSyntax) != null)
            {
                int adjustedPosition = GetAdjustedNodePosition(crefSyntax);
                result = GetCrefSymbolInfo(adjustedPosition, crefSyntax, options, HasParameterList(crefSyntax));
            }
            else
            {
                // if expression is not part of a member context then caller may really just have a
                // reference to a type or namespace name
                var symbol = GetSemanticInfoSymbolInNonMemberContext(node, bindVarAsAliasFirst: (options & SymbolInfoOptions.PreserveAliases) != 0);
                result = (object)symbol != null ? GetSymbolInfoForSymbol(symbol, options) : SymbolInfo.None;
            }
 
            return result;
        }
 
        internal override SymbolInfo GetCollectionInitializerSymbolInfoWorker(InitializerExpressionSyntax collectionInitializer, ExpressionSyntax node, CancellationToken cancellationToken = default(CancellationToken))
        {
            var model = this.GetMemberModel(collectionInitializer);
 
            if (model != null)
            {
                // Expression occurs in an executable code (method body or initializer) context. Use that
                // model to get the information.
                return model.GetCollectionInitializerSymbolInfoWorker(collectionInitializer, node, cancellationToken);
            }
 
            return SymbolInfo.None;
        }
 
        internal override CSharpTypeInfo GetTypeInfoWorker(CSharpSyntaxNode node, CancellationToken cancellationToken = default(CancellationToken))
        {
            // in case this is right side of a qualified name or member access (or part of a cref)
            node = SyntaxFactory.GetStandaloneNode(node);
 
            var model = this.GetMemberModel(node);
 
            if (model != null)
            {
                // Expression occurs in an executable code (method body or initializer) context. Use that
                // model to get the information.
                return model.GetTypeInfoWorker(node, cancellationToken);
            }
            else
            {
                // if expression is not part of a member context then caller may really just have a
                // reference to a type or namespace name
                var symbol = GetSemanticInfoSymbolInNonMemberContext(node, bindVarAsAliasFirst: false); // Don't care about aliases here.
                return (object)symbol != null ? GetTypeInfoForSymbol(symbol) : CSharpTypeInfo.None;
            }
        }
 
        // Common helper method for GetSymbolInfoWorker and GetTypeInfoWorker, which is called when there is no member model for the given syntax node.
        // Even if the  expression is not part of a member context, the caller may really just have a reference to a type or namespace name.
        // If so, the methods binds the syntax as a namespace or type or alias symbol. Otherwise, it returns null.
        private Symbol GetSemanticInfoSymbolInNonMemberContext(CSharpSyntaxNode node, bool bindVarAsAliasFirst)
        {
            Debug.Assert(this.GetMemberModel(node) == null);
 
            var binder = this.GetEnclosingBinder(GetAdjustedNodePosition(node));
            if (binder != null)
            {
                // if expression is not part of a member context then caller may really just have a
                // reference to a type or namespace name
                var type = node as TypeSyntax;
                if ((object)type != null)
                {
                    // determine if this type is part of a base declaration being resolved
                    var basesBeingResolved = GetBasesBeingResolved(type);
 
                    if (SyntaxFacts.IsNamespaceAliasQualifier(type))
                    {
                        return binder.BindNamespaceAliasSymbol(node as IdentifierNameSyntax, BindingDiagnosticBag.Discarded);
                    }
                    else if (SyntaxFacts.IsInTypeOnlyContext(type))
                    {
                        if (!type.IsVar)
                        {
                            return binder.BindTypeOrAlias(type, BindingDiagnosticBag.Discarded, basesBeingResolved).Symbol;
                        }
 
                        Symbol result = bindVarAsAliasFirst
                            ? binder.BindTypeOrAlias(type, BindingDiagnosticBag.Discarded, basesBeingResolved).Symbol
                            : null;
 
                        // CONSIDER: we might bind "var" twice - once to see if it is an alias and again
                        // as the type of a declared field.  This should only happen for GetAliasInfo
                        // calls on implicitly-typed fields (rare?).  If it becomes a problem, then we
                        // probably need to have the FieldSymbol retain alias info when it does its own
                        // binding and expose it to us here.
 
                        if ((object)result == null || result.Kind == SymbolKind.ErrorType)
                        {
                            // We might be in a field declaration with "var" keyword as the type name.
                            // Implicitly typed field symbols are not allowed in regular C#,
                            // but they are allowed in interactive scenario.
                            // However, we can return fieldSymbol.Type for implicitly typed field symbols in both cases.
                            // Note that for regular C#, fieldSymbol.Type would be an error type.
 
                            var variableDecl = type.ModifyingScopedOrRefTypeOrSelf().Parent as VariableDeclarationSyntax;
                            if (variableDecl != null && variableDecl.Variables.Any())
                            {
                                var fieldSymbol = GetDeclaredFieldSymbol(variableDecl.Variables.First());
                                if ((object)fieldSymbol != null)
                                {
                                    result = fieldSymbol.Type;
                                }
                            }
                        }
 
                        return result ?? binder.BindTypeOrAlias(type, BindingDiagnosticBag.Discarded, basesBeingResolved).Symbol;
                    }
                    else
                    {
                        return binder.BindNamespaceOrTypeOrAliasSymbol(type, BindingDiagnosticBag.Discarded, basesBeingResolved, basesBeingResolved != null).Symbol;
                    }
                }
            }
 
            return null;
        }
 
        internal override ImmutableArray<Symbol> GetMemberGroupWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken))
        {
            // in case this is right side of a qualified name or member access (or part of a cref)
            node = SyntaxFactory.GetStandaloneNode(node);
 
            var model = this.GetMemberModel(node);
            return model == null ? ImmutableArray<Symbol>.Empty : model.GetMemberGroupWorker(node, options, cancellationToken);
        }
 
        internal override ImmutableArray<IPropertySymbol> GetIndexerGroupWorker(CSharpSyntaxNode node, SymbolInfoOptions options, CancellationToken cancellationToken = default(CancellationToken))
        {
            // in case this is right side of a qualified name or member access (or part of a cref)
            node = SyntaxFactory.GetStandaloneNode(node);
 
            var model = this.GetMemberModel(node);
            return model == null ? ImmutableArray<IPropertySymbol>.Empty : model.GetIndexerGroupWorker(node, options, cancellationToken);
        }
 
        internal override Optional<object> GetConstantValueWorker(CSharpSyntaxNode node, CancellationToken cancellationToken)
        {
            // in case this is right side of a qualified name or member access
            node = SyntaxFactory.GetStandaloneNode(node);
 
            var model = this.GetMemberModel(node);
            return model == null ? default(Optional<object>) : model.GetConstantValueWorker(node, cancellationToken);
        }
 
        public override QueryClauseInfo GetQueryClauseInfo(QueryClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(node);
            var model = this.GetMemberModel(node);
            return (model == null) ? default(QueryClauseInfo) : model.GetQueryClauseInfo(node, cancellationToken);
        }
 
        public override SymbolInfo GetSymbolInfo(SelectOrGroupClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(node);
            var model = this.GetMemberModel(node);
            return (model == null) ? SymbolInfo.None : model.GetSymbolInfo(node, cancellationToken);
        }
 
        public override TypeInfo GetTypeInfo(SelectOrGroupClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(node);
            var model = this.GetMemberModel(node);
            return (model == null) ? CSharpTypeInfo.None : model.GetTypeInfo(node, cancellationToken);
        }
 
        public override IPropertySymbol GetDeclaredSymbol(AnonymousObjectMemberDeclaratorSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declaratorSyntax);
            var model = this.GetMemberModel(declaratorSyntax);
            return (model == null) ? null : model.GetDeclaredSymbol(declaratorSyntax, cancellationToken);
        }
 
        public override INamedTypeSymbol GetDeclaredSymbol(AnonymousObjectCreationExpressionSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declaratorSyntax);
            var model = this.GetMemberModel(declaratorSyntax);
            return (model == null) ? null : model.GetDeclaredSymbol(declaratorSyntax, cancellationToken);
        }
 
        public override INamedTypeSymbol GetDeclaredSymbol(TupleExpressionSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declaratorSyntax);
            var model = this.GetMemberModel(declaratorSyntax);
            return (model == null) ? null : model.GetDeclaredSymbol(declaratorSyntax, cancellationToken);
        }
 
        public override ISymbol GetDeclaredSymbol(ArgumentSyntax declaratorSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declaratorSyntax);
            var model = this.GetMemberModel(declaratorSyntax);
            return (model == null) ? null : model.GetDeclaredSymbol(declaratorSyntax, cancellationToken);
        }
 
        public override IRangeVariableSymbol GetDeclaredSymbol(QueryClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(node);
            var model = this.GetMemberModel(node);
            return (model == null) ? null : model.GetDeclaredSymbol(node, cancellationToken);
        }
 
        public override IRangeVariableSymbol GetDeclaredSymbol(JoinIntoClauseSyntax node, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(node);
            var model = this.GetMemberModel(node);
            return (model == null) ? null : model.GetDeclaredSymbol(node, cancellationToken);
        }
 
        public override IRangeVariableSymbol GetDeclaredSymbol(QueryContinuationSyntax node, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(node);
            var model = this.GetMemberModel(node);
            return (model == null) ? null : model.GetDeclaredSymbol(node, cancellationToken);
        }
 
        public override SymbolInfo GetSymbolInfo(OrderingSyntax node, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(node);
            var model = this.GetMemberModel(node);
            return (model == null) ? SymbolInfo.None : model.GetSymbolInfo(node, cancellationToken);
        }
 
        private ConsList<TypeSymbol> GetBasesBeingResolved(TypeSyntax expression)
        {
            // if the expression is the child of a base-list node, then the expression should be
            // bound in the context of the containing symbols base being resolved.
            for (; expression != null && expression.Parent != null; expression = expression.Parent as TypeSyntax)
            {
                var parent = expression.Parent;
                if (parent is BaseTypeSyntax baseType && parent.Parent != null && parent.Parent.Kind() == SyntaxKind.BaseList && baseType.Type == expression)
                {
                    // we have a winner
                    var decl = (BaseTypeDeclarationSyntax)parent.Parent.Parent;
                    var symbol = this.GetDeclaredSymbol(decl);
                    return ConsList<TypeSymbol>.Empty.Prepend(symbol.GetSymbol().OriginalDefinition);
                }
            }
 
            return null;
        }
 
        public override Conversion ClassifyConversion(ExpressionSyntax expression, ITypeSymbol destination, bool isExplicitInSource = false)
        {
            TypeSymbol csdestination = destination.EnsureCSharpSymbolOrNull(nameof(destination));
 
            if (expression.Kind() == SyntaxKind.DeclarationExpression)
            {
                // Conversion from a declaration is unspecified.
                return Conversion.NoConversion;
            }
 
            if (isExplicitInSource)
            {
                return ClassifyConversionForCast(expression, csdestination);
            }
 
            CheckSyntaxNode(expression);
 
            if ((object)destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }
 
            // TODO(cyrusn): Check arguments. This is a public entrypoint, so we must do appropriate
            // checks here. However, no other methods in this type do any checking currently. So I'm
            // going to hold off on this until we do a full sweep of the API.
 
            var model = this.GetMemberModel(expression);
            if (model == null)
            {
                // 'expression' must just be reference to a type or namespace name outside of an
                // expression context.  Currently we bail in that case.  However, is this a question
                // that a client would be asking and would expect sensible results for?
                return Conversion.NoConversion;
            }
 
            return model.ClassifyConversion(expression, destination);
        }
 
        internal override Conversion ClassifyConversionForCast(ExpressionSyntax expression, TypeSymbol destination)
        {
            CheckSyntaxNode(expression);
 
            if ((object)destination == null)
            {
                throw new ArgumentNullException(nameof(destination));
            }
 
            var model = this.GetMemberModel(expression);
            if (model == null)
            {
                // 'expression' must just be reference to a type or namespace name outside of an
                // expression context.  Currently we bail in that case.  However, is this a question
                // that a client would be asking and would expect sensible results for?
                return Conversion.NoConversion;
            }
 
            return model.ClassifyConversionForCast(expression, destination);
        }
 
        public override bool IsSpeculativeSemanticModel
        {
            get { return false; }
        }
 
        public override int OriginalPositionForSpeculation
        {
            get { return 0; }
        }
 
        public override CSharpSemanticModel ParentModel
        {
            get { return null; }
        }
 
        internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, TypeSyntax type, SpeculativeBindingOption bindingOption, out PublicSemanticModel speculativeModel)
        {
            position = CheckAndAdjustPosition(position);
 
            var model = this.GetMemberModel(position);
            if (model != null)
            {
                return model.TryGetSpeculativeSemanticModelCore(parentModel, position, type, bindingOption, out speculativeModel);
            }
 
            Binder binder = GetSpeculativeBinder(position, type, bindingOption);
            if (binder != null)
            {
                speculativeModel = SpeculativeSyntaxTreeSemanticModel.Create(parentModel, type, binder, position, bindingOption);
                return true;
            }
 
            speculativeModel = null;
            return false;
        }
 
        internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, CrefSyntax crefSyntax, out PublicSemanticModel speculativeModel)
        {
            position = CheckAndAdjustPosition(position);
 
            Binder binder = GetEnclosingBinder(position);
            if (binder?.InCref == true)
            {
                speculativeModel = SpeculativeSyntaxTreeSemanticModel.Create(parentModel, crefSyntax, binder, position);
                return true;
            }
 
            speculativeModel = null;
            return false;
        }
 
        internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, StatementSyntax statement, out PublicSemanticModel speculativeModel)
        {
            position = CheckAndAdjustPosition(position);
 
            var model = this.GetMemberModel(position);
            if (model != null)
            {
                return model.TryGetSpeculativeSemanticModelCore(parentModel, position, statement, out speculativeModel);
            }
 
            speculativeModel = null;
            return false;
        }
 
        internal sealed override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, BaseMethodDeclarationSyntax method, out PublicSemanticModel speculativeModel)
        {
            position = CheckAndAdjustPosition(position);
 
            var model = this.GetMemberModel(position);
            if (model != null)
            {
                return model.TryGetSpeculativeSemanticModelForMethodBodyCore(parentModel, position, method, out speculativeModel);
            }
 
            speculativeModel = null;
            return false;
        }
 
        internal sealed override bool TryGetSpeculativeSemanticModelForMethodBodyCore(SyntaxTreeSemanticModel parentModel, int position, AccessorDeclarationSyntax accessor, out PublicSemanticModel speculativeModel)
        {
            position = CheckAndAdjustPosition(position);
 
            var model = this.GetMemberModel(position);
            if (model != null)
            {
                return model.TryGetSpeculativeSemanticModelForMethodBodyCore(parentModel, position, accessor, out speculativeModel);
            }
 
            speculativeModel = null;
            return false;
        }
 
        internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, EqualsValueClauseSyntax initializer, out PublicSemanticModel speculativeModel)
        {
            position = CheckAndAdjustPosition(position);
 
            var model = this.GetMemberModel(position);
            if (model != null)
            {
                return model.TryGetSpeculativeSemanticModelCore(parentModel, position, initializer, out speculativeModel);
            }
 
            speculativeModel = null;
            return false;
        }
 
        internal override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ArrowExpressionClauseSyntax expressionBody, out PublicSemanticModel speculativeModel)
        {
            position = CheckAndAdjustPosition(position);
 
            var model = this.GetMemberModel(position);
            if (model != null)
            {
                return model.TryGetSpeculativeSemanticModelCore(parentModel, position, expressionBody, out speculativeModel);
            }
 
            speculativeModel = null;
            return false;
        }
 
        internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, ConstructorInitializerSyntax constructorInitializer, out PublicSemanticModel speculativeModel)
        {
            position = CheckAndAdjustPosition(position);
 
            var existingConstructorInitializer = this.Root.FindToken(position).Parent.AncestorsAndSelf().OfType<ConstructorInitializerSyntax>().FirstOrDefault();
 
            if (existingConstructorInitializer != null)
            {
                var model = this.GetMemberModel(position);
                if (model != null)
                {
                    return model.TryGetSpeculativeSemanticModelCore(parentModel, position, constructorInitializer, out speculativeModel);
                }
            }
 
            speculativeModel = null;
            return false;
        }
 
        internal sealed override bool TryGetSpeculativeSemanticModelCore(SyntaxTreeSemanticModel parentModel, int position, PrimaryConstructorBaseTypeSyntax constructorInitializer, out PublicSemanticModel speculativeModel)
        {
            position = CheckAndAdjustPosition(position);
 
            var existingConstructorInitializer = this.Root.FindToken(position).Parent.AncestorsAndSelf().OfType<PrimaryConstructorBaseTypeSyntax>().FirstOrDefault();
 
            if (existingConstructorInitializer != null)
            {
                var model = this.GetMemberModel(existingConstructorInitializer);
                if (model != null)
                {
                    return model.TryGetSpeculativeSemanticModelCore(parentModel, position, constructorInitializer, out speculativeModel);
                }
            }
 
            speculativeModel = null;
            return false;
        }
 
        internal override BoundExpression GetSpeculativelyBoundExpression(int position, ExpressionSyntax expression, SpeculativeBindingOption bindingOption, out Binder binder, out ImmutableArray<Symbol> crefSymbols)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
 
            // If the given position is in a member that we can get a semantic model for, we want to defer to that implementation
            // of GetSpeculativelyBoundExpression so it can take nullability into account.
            if (bindingOption == SpeculativeBindingOption.BindAsExpression)
            {
                position = CheckAndAdjustPosition(position);
                var model = GetMemberModel(position);
                if (model is object)
                {
                    return model.GetSpeculativelyBoundExpression(position, expression, bindingOption, out binder, out crefSymbols);
                }
            }
 
            return GetSpeculativelyBoundExpressionWithoutNullability(position, expression, bindingOption, out binder, out crefSymbols);
        }
 
        internal PublicSemanticModel CreateSpeculativeAttributeSemanticModel(int position, AttributeSyntax attribute, Binder binder, AliasSymbol aliasOpt, NamedTypeSymbol attributeType)
        {
            var memberModel = IsNullableAnalysisEnabledAtSpeculativePosition(position, attribute) ? GetMemberModel(position) : null;
            return AttributeSemanticModel.CreateSpeculative(this, attribute, attributeType, aliasOpt, binder, memberModel?.GetRemappedSymbols(), position);
        }
 
        internal bool IsNullableAnalysisEnabledAtSpeculativePosition(int position, SyntaxNode speculativeSyntax)
        {
            Debug.Assert(speculativeSyntax.SyntaxTree != SyntaxTree);
 
            // https://github.com/dotnet/roslyn/issues/50234: CSharpSyntaxTree.IsNullableAnalysisEnabled() does not differentiate
            // between no '#nullable' directives and '#nullable restore' - it returns null in both cases. Since we fallback to the
            // directives in the original syntax tree, we're not handling '#nullable restore' correctly in the speculative text.
            return ((CSharpSyntaxTree)speculativeSyntax.SyntaxTree).IsNullableAnalysisEnabled(speculativeSyntax.Span) ??
                Compilation.IsNullableAnalysisEnabledIn((CSharpSyntaxTree)SyntaxTree, new TextSpan(position, 0));
        }
 
        private MemberSemanticModel GetMemberModel(int position)
        {
            AssertPositionAdjusted(position);
            CSharpSyntaxNode node = (CSharpSyntaxNode)Root.FindTokenIncludingCrefAndNameAttributes(position).Parent;
            CSharpSyntaxNode memberDecl = GetMemberDeclaration(node);
 
            bool outsideMemberDecl = false;
            if (memberDecl != null)
            {
                switch (memberDecl.Kind())
                {
                    case SyntaxKind.AddAccessorDeclaration:
                    case SyntaxKind.RemoveAccessorDeclaration:
                    case SyntaxKind.GetAccessorDeclaration:
                    case SyntaxKind.SetAccessorDeclaration:
                    case SyntaxKind.InitAccessorDeclaration:
                        // NOTE: not UnknownAccessorDeclaration since there's no corresponding method symbol from which to build a member model.
                        outsideMemberDecl = !LookupPosition.IsInBody(position, (AccessorDeclarationSyntax)memberDecl);
                        break;
                    case SyntaxKind.ConstructorDeclaration:
                        var constructorDecl = (ConstructorDeclarationSyntax)memberDecl;
                        outsideMemberDecl =
                            !LookupPosition.IsInConstructorParameterScope(position, constructorDecl) &&
                            !LookupPosition.IsInParameterList(position, constructorDecl);
                        break;
                    case SyntaxKind.ClassDeclaration:
                    case SyntaxKind.RecordDeclaration:
                        {
                            var typeDecl = (TypeDeclarationSyntax)memberDecl;
 
                            if (typeDecl.ParameterList is null)
                            {
                                outsideMemberDecl = true;
                            }
                            else
                            {
                                var argumentList = typeDecl.PrimaryConstructorBaseTypeIfClass?.ArgumentList;
                                outsideMemberDecl = argumentList is null || !LookupPosition.IsBetweenTokens(position, argumentList.OpenParenToken, argumentList.CloseParenToken);
                            }
                        }
                        break;
                    case SyntaxKind.ConversionOperatorDeclaration:
                    case SyntaxKind.DestructorDeclaration:
                    case SyntaxKind.MethodDeclaration:
                    case SyntaxKind.OperatorDeclaration:
                        var methodDecl = (BaseMethodDeclarationSyntax)memberDecl;
                        outsideMemberDecl =
                            !LookupPosition.IsInBody(position, methodDecl) &&
                            !LookupPosition.IsInParameterList(position, methodDecl);
                        break;
                }
            }
 
            return outsideMemberDecl ? null : GetMemberModel(node);
        }
 
        // Try to get a member semantic model that encloses "node". If there is not an enclosing
        // member semantic model, return null.
        internal override MemberSemanticModel GetMemberModel(SyntaxNode node)
        {
            // Documentation comments can never legally appear within members, so there's no point
            // in building out the MemberSemanticModel to handle them.  Instead, just say have
            // SyntaxTreeSemanticModel handle them, regardless of location.
            if (IsInDocumentationComment(node))
            {
                return null;
            }
 
            var memberDecl = GetMemberDeclaration(node) ?? (node as CompilationUnitSyntax);
            if (memberDecl != null)
            {
                var span = node.Span;
 
                switch (memberDecl.Kind())
                {
                    case SyntaxKind.MethodDeclaration:
                    case SyntaxKind.ConversionOperatorDeclaration:
                    case SyntaxKind.OperatorDeclaration:
                        {
                            var methodDecl = (BaseMethodDeclarationSyntax)memberDecl;
                            var expressionBody = methodDecl.GetExpressionBodySyntax();
                            return (expressionBody?.FullSpan.Contains(span) == true || methodDecl.Body?.FullSpan.Contains(span) == true) ?
                                   GetOrAddModel(methodDecl) : null;
                        }
 
                    case SyntaxKind.ConstructorDeclaration:
                        {
                            ConstructorDeclarationSyntax constructorDecl = (ConstructorDeclarationSyntax)memberDecl;
                            var expressionBody = constructorDecl.GetExpressionBodySyntax();
                            return (constructorDecl.Initializer?.FullSpan.Contains(span) == true ||
                                    expressionBody?.FullSpan.Contains(span) == true ||
                                    constructorDecl.Body?.FullSpan.Contains(span) == true) ?
                                   GetOrAddModel(constructorDecl) : null;
                        }
 
                    case SyntaxKind.ClassDeclaration:
                    case SyntaxKind.RecordDeclaration:
                        {
                            var typeDecl = (TypeDeclarationSyntax)memberDecl;
                            return typeDecl.ParameterList is object &&
                                   typeDecl.PrimaryConstructorBaseTypeIfClass is PrimaryConstructorBaseTypeSyntax baseWithArguments &&
                                   (node == baseWithArguments || baseWithArguments.ArgumentList.FullSpan.Contains(span)) ? GetOrAddModel(memberDecl) : null;
                        }
 
                    case SyntaxKind.DestructorDeclaration:
                        {
                            DestructorDeclarationSyntax destructorDecl = (DestructorDeclarationSyntax)memberDecl;
                            var expressionBody = destructorDecl.GetExpressionBodySyntax();
                            return (expressionBody?.FullSpan.Contains(span) == true || destructorDecl.Body?.FullSpan.Contains(span) == true) ?
                                   GetOrAddModel(destructorDecl) : null;
                        }
 
                    case SyntaxKind.GetAccessorDeclaration:
                    case SyntaxKind.SetAccessorDeclaration:
                    case SyntaxKind.InitAccessorDeclaration:
                    case SyntaxKind.AddAccessorDeclaration:
                    case SyntaxKind.RemoveAccessorDeclaration:
                        // NOTE: not UnknownAccessorDeclaration since there's no corresponding method symbol from which to build a member model.
                        {
                            var accessorDecl = (AccessorDeclarationSyntax)memberDecl;
                            return (accessorDecl.ExpressionBody?.FullSpan.Contains(span) == true || accessorDecl.Body?.FullSpan.Contains(span) == true) ?
                                   GetOrAddModel(accessorDecl) : null;
                        }
 
                    case SyntaxKind.IndexerDeclaration:
                        {
                            var indexerDecl = (IndexerDeclarationSyntax)memberDecl;
                            return GetOrAddModelIfContains(indexerDecl.ExpressionBody, span);
                        }
 
                    case SyntaxKind.FieldDeclaration:
                    case SyntaxKind.EventFieldDeclaration:
                        {
                            var fieldDecl = (BaseFieldDeclarationSyntax)memberDecl;
                            foreach (var variableDecl in fieldDecl.Declaration.Variables)
                            {
                                var binding = GetOrAddModelIfContains(variableDecl.Initializer, span);
                                if (binding != null)
                                {
                                    return binding;
                                }
                            }
                        }
                        break;
 
                    case SyntaxKind.EnumMemberDeclaration:
                        {
                            var enumDecl = (EnumMemberDeclarationSyntax)memberDecl;
                            return (enumDecl.EqualsValue != null) ?
                                GetOrAddModelIfContains(enumDecl.EqualsValue, span) :
                                null;
                        }
 
                    case SyntaxKind.PropertyDeclaration:
                        {
                            var propertyDecl = (PropertyDeclarationSyntax)memberDecl;
                            return GetOrAddModelIfContains(propertyDecl.Initializer, span) ??
                                GetOrAddModelIfContains(propertyDecl.ExpressionBody, span);
                        }
 
                    case SyntaxKind.GlobalStatement:
                        if (SyntaxFacts.IsSimpleProgramTopLevelStatement((GlobalStatementSyntax)memberDecl))
                        {
                            return GetOrAddModel((CompilationUnitSyntax)memberDecl.Parent);
                        }
 
                        return GetOrAddModel(memberDecl);
 
                    case SyntaxKind.CompilationUnit:
                        if (SynthesizedSimpleProgramEntryPointSymbol.GetSimpleProgramEntryPoint(Compilation, (CompilationUnitSyntax)memberDecl, fallbackToMainEntryPoint: false) is object)
                        {
                            return GetOrAddModel(memberDecl);
                        }
                        break;
 
                    case SyntaxKind.Attribute:
                        return GetOrAddModelForAttribute((AttributeSyntax)memberDecl);
 
                    case SyntaxKind.Parameter:
                        if (node != memberDecl)
                        {
                            return GetOrAddModelForParameter((ParameterSyntax)memberDecl, span);
                        }
                        else
                        {
                            return GetMemberModel(memberDecl.Parent);
                        }
                }
            }
 
            return null;
        }
 
        /// <summary>
        /// Internal for test purposes only
        /// </summary>
        internal ImmutableDictionary<CSharpSyntaxNode, MemberSemanticModel> TestOnlyMemberModels => _memberModels;
 
        private MemberSemanticModel GetOrAddModelForAttribute(AttributeSyntax attribute)
        {
            MemberSemanticModel containing = attribute.Parent != null ? GetMemberModel(attribute.Parent) : null;
 
            if (containing == null)
            {
                return GetOrAddModel(attribute);
            }
 
            return ImmutableInterlocked.GetOrAdd(ref _memberModels, attribute,
                                                 (node, binderAndModel) => CreateModelForAttribute(binderAndModel.binder, (AttributeSyntax)node, binderAndModel.model),
                                                 (binder: containing.GetEnclosingBinder(attribute.SpanStart), model: containing));
        }
 
        private static bool IsInDocumentationComment(SyntaxNode node)
        {
            for (SyntaxNode curr = node; curr != null; curr = curr.Parent)
            {
                if (SyntaxFacts.IsDocumentationCommentTrivia(curr.Kind()))
                {
                    return true;
                }
            }
 
            return false;
        }
 
        // Check parameter for a default value containing span, and create an InitializerSemanticModel for binding the default value if so.
        // Otherwise, return model for enclosing context.
        private MemberSemanticModel GetOrAddModelForParameter(ParameterSyntax paramDecl, TextSpan span)
        {
            EqualsValueClauseSyntax defaultValueSyntax = paramDecl.Default;
            MemberSemanticModel containing = paramDecl.Parent != null ? GetMemberModel(paramDecl.Parent) : null;
 
            if (containing == null)
            {
                return GetOrAddModelIfContains(defaultValueSyntax, span);
            }
 
            if (defaultValueSyntax != null && defaultValueSyntax.FullSpan.Contains(span))
            {
                var parameterSymbol = containing.GetDeclaredSymbol(paramDecl).GetSymbol<ParameterSymbol>();
                if ((object)parameterSymbol != null)
                {
                    return ImmutableInterlocked.GetOrAdd(ref _memberModels, defaultValueSyntax,
                                                         (equalsValue, tuple) =>
                                                            InitializerSemanticModel.Create(
                                                                this,
                                                                tuple.paramDecl,
                                                                tuple.parameterSymbol,
                                                                tuple.containing.GetEnclosingBinder(tuple.paramDecl.SpanStart).
                                                                    CreateBinderForParameterDefaultValue(tuple.parameterSymbol,
                                                                                            (EqualsValueClauseSyntax)equalsValue),
                                                                tuple.containing.GetRemappedSymbols()),
                                                         (compilation: this.Compilation,
                                                          paramDecl,
                                                          parameterSymbol,
                                                          containing)
                                                         );
                }
            }
 
            return containing;
        }
 
        private static CSharpSyntaxNode GetMemberDeclaration(SyntaxNode node)
        {
            return node.FirstAncestorOrSelf(s_isMemberDeclarationFunction);
        }
 
        private MemberSemanticModel GetOrAddModelIfContains(CSharpSyntaxNode node, TextSpan span)
        {
            if (node != null && node.FullSpan.Contains(span))
            {
                return GetOrAddModel(node);
            }
            return null;
        }
 
        private MemberSemanticModel GetOrAddModel(CSharpSyntaxNode node)
        {
            var createMemberModelFunction = _createMemberModelFunction ??
                                            (_createMemberModelFunction = this.CreateMemberModel);
 
            return GetOrAddModel(node, createMemberModelFunction);
        }
 
        internal MemberSemanticModel GetOrAddModel(CSharpSyntaxNode node, Func<CSharpSyntaxNode, MemberSemanticModel> createMemberModelFunction)
        {
            return ImmutableInterlocked.GetOrAdd(ref _memberModels, node, createMemberModelFunction);
        }
 
        // Create a member model for the given declaration syntax. In certain very malformed
        // syntax trees, there may not be a symbol that can have a member model associated with it
        // (although we try to minimize such cases). In such cases, null is returned.
        private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node)
        {
            Binder defaultOuter() => _binderFactory.GetBinder(node).WithAdditionalFlags(this.IgnoresAccessibility ? BinderFlags.IgnoreAccessibility : BinderFlags.None);
 
            switch (node.Kind())
            {
                case SyntaxKind.CompilationUnit:
                    return createMethodBodySemanticModel(node, SynthesizedSimpleProgramEntryPointSymbol.GetSimpleProgramEntryPoint(Compilation, (CompilationUnitSyntax)node, fallbackToMainEntryPoint: false));
 
                case SyntaxKind.MethodDeclaration:
                case SyntaxKind.ConversionOperatorDeclaration:
                case SyntaxKind.OperatorDeclaration:
                case SyntaxKind.ConstructorDeclaration:
                case SyntaxKind.DestructorDeclaration:
                    {
                        var memberDecl = (MemberDeclarationSyntax)node;
                        var symbol = GetDeclaredSymbol(memberDecl).GetSymbol<SourceMemberMethodSymbol>();
                        return createMethodBodySemanticModel(memberDecl, symbol);
                    }
 
                case SyntaxKind.ClassDeclaration:
                case SyntaxKind.RecordDeclaration:
                    {
                        SynthesizedPrimaryConstructor symbol = TryGetSynthesizedPrimaryConstructor((TypeDeclarationSyntax)node);
 
                        if (symbol is null)
                        {
                            return null;
                        }
 
                        return createMethodBodySemanticModel(node, symbol);
                    }
 
                case SyntaxKind.GetAccessorDeclaration:
                case SyntaxKind.SetAccessorDeclaration:
                case SyntaxKind.InitAccessorDeclaration:
                case SyntaxKind.AddAccessorDeclaration:
                case SyntaxKind.RemoveAccessorDeclaration:
                    {
                        var accessorDecl = (AccessorDeclarationSyntax)node;
                        var symbol = GetDeclaredSymbol(accessorDecl).GetSymbol<SourceMemberMethodSymbol>();
                        return createMethodBodySemanticModel(accessorDecl, symbol);
                    }
 
                case SyntaxKind.Block:
                    // Don't throw, just use for the assert
                    ExceptionUtilities.UnexpectedValue(node.Parent);
                    break;
 
                case SyntaxKind.EqualsValueClause:
                    switch (node.Parent.Kind())
                    {
                        case SyntaxKind.VariableDeclarator:
                            {
                                var variableDecl = (VariableDeclaratorSyntax)node.Parent;
                                FieldSymbol fieldSymbol = GetDeclaredFieldSymbol(variableDecl);
 
                                return InitializerSemanticModel.Create(
                                    this,
                                    variableDecl,   //pass in the entire field initializer to permit region analysis. 
                                    fieldSymbol,
                                    //if we're in regular C#, then insert an extra binder to perform field initialization checks
                                    GetFieldOrPropertyInitializerBinder(fieldSymbol, defaultOuter(), variableDecl.Initializer));
                            }
 
                        case SyntaxKind.PropertyDeclaration:
                            {
                                var propertyDecl = (PropertyDeclarationSyntax)node.Parent;
                                var propertySymbol = GetDeclaredSymbol(propertyDecl).GetSymbol<SourcePropertySymbol>();
                                return InitializerSemanticModel.Create(
                                    this,
                                    propertyDecl,
                                    propertySymbol,
                                    GetFieldOrPropertyInitializerBinder(propertySymbol.BackingField, defaultOuter(), propertyDecl.Initializer));
                            }
 
                        case SyntaxKind.Parameter:
                            {
                                // NOTE: we don't need to create a member model for lambda parameter default value
                                // because lambdas only appear in code with associated member models.
                                ParameterSyntax parameterDecl = (ParameterSyntax)node.Parent;
                                ParameterSymbol parameterSymbol = GetDeclaredNonLambdaParameterSymbol(parameterDecl);
                                if ((object)parameterSymbol == null)
                                    return null;
 
                                return InitializerSemanticModel.Create(
                                    this,
                                    parameterDecl,
                                    parameterSymbol,
                                    defaultOuter().CreateBinderForParameterDefaultValue(parameterSymbol, (EqualsValueClauseSyntax)node),
                                    parentRemappedSymbolsOpt: null);
                            }
 
                        case SyntaxKind.EnumMemberDeclaration:
                            {
                                var enumDecl = (EnumMemberDeclarationSyntax)node.Parent;
                                var enumSymbol = GetDeclaredSymbol(enumDecl).GetSymbol<FieldSymbol>();
                                if ((object)enumSymbol == null)
                                    return null;
 
                                return InitializerSemanticModel.Create(
                                    this,
                                    enumDecl,
                                    enumSymbol,
                                    GetFieldOrPropertyInitializerBinder(enumSymbol, defaultOuter(), enumDecl.EqualsValue));
                            }
                        default:
                            throw ExceptionUtilities.UnexpectedValue(node.Parent.Kind());
                    }
 
                case SyntaxKind.ArrowExpressionClause:
                    {
                        SourceMemberMethodSymbol symbol = null;
 
                        var exprDecl = (ArrowExpressionClauseSyntax)node;
 
                        if (node.Parent is BasePropertyDeclarationSyntax)
                        {
                            symbol = GetDeclaredSymbol(exprDecl).GetSymbol<SourceMemberMethodSymbol>();
                        }
                        else
                        {
                            // Don't throw, just use for the assert
                            ExceptionUtilities.UnexpectedValue(node.Parent);
                        }
 
                        ExecutableCodeBinder binder = symbol?.TryGetBodyBinder(_binderFactory, this.IgnoresAccessibility);
 
                        if (binder == null)
                        {
                            return null;
                        }
 
                        return MethodBodySemanticModel.Create(this, symbol, new MethodBodySemanticModel.InitialState(exprDecl, binder: binder));
                    }
 
                case SyntaxKind.GlobalStatement:
                    {
                        var parent = node.Parent;
                        // TODO (tomat): handle misplaced global statements
                        if (parent.Kind() == SyntaxKind.CompilationUnit &&
                            !this.IsRegularCSharp &&
                            (object)_compilation.ScriptClass != null)
                        {
                            var scriptInitializer = _compilation.ScriptClass.GetScriptInitializer();
                            Debug.Assert((object)scriptInitializer != null);
                            if ((object)scriptInitializer == null)
                            {
                                return null;
                            }
 
                            // Share labels across all global statements.
                            if (_globalStatementLabels == null)
                            {
                                Interlocked.CompareExchange(ref _globalStatementLabels, new ScriptLocalScopeBinder.Labels(scriptInitializer, (CompilationUnitSyntax)parent), null);
                            }
 
                            return MethodBodySemanticModel.Create(
                                this,
                                scriptInitializer,
                                new MethodBodySemanticModel.InitialState(node, binder: new ExecutableCodeBinder(node, scriptInitializer, new ScriptLocalScopeBinder(_globalStatementLabels, defaultOuter()))));
                        }
                    }
                    break;
 
                case SyntaxKind.Attribute:
                    return CreateModelForAttribute(defaultOuter(), (AttributeSyntax)node, containingModel: null);
            }
 
            return null;
 
            MemberSemanticModel createMethodBodySemanticModel(CSharpSyntaxNode memberDecl, SourceMemberMethodSymbol symbol)
            {
                ExecutableCodeBinder binder = symbol?.TryGetBodyBinder(_binderFactory, this.IgnoresAccessibility);
 
                if (binder == null)
                {
                    return null;
                }
 
                return MethodBodySemanticModel.Create(this, symbol, new MethodBodySemanticModel.InitialState(memberDecl, binder: binder));
            }
        }
 
        private SynthesizedPrimaryConstructor TryGetSynthesizedPrimaryConstructor(TypeDeclarationSyntax node)
            => TryGetSynthesizedPrimaryConstructor(node, GetDeclaredType(node));
 
        private FieldSymbol GetDeclaredFieldSymbol(VariableDeclaratorSyntax variableDecl)
        {
            var declaredSymbol = GetDeclaredSymbol(variableDecl);
 
            if ((object)declaredSymbol != null)
            {
                switch (variableDecl.Parent.Parent.Kind())
                {
                    case SyntaxKind.FieldDeclaration:
                        return declaredSymbol.GetSymbol<FieldSymbol>();
 
                    case SyntaxKind.EventFieldDeclaration:
                        return (declaredSymbol.GetSymbol<EventSymbol>()).AssociatedField;
                }
            }
 
            return null;
        }
 
        private Binder GetFieldOrPropertyInitializerBinder(FieldSymbol symbol, Binder outer, EqualsValueClauseSyntax initializer)
        {
            // NOTE: checking for a containing script class is sufficient, but the regular C# test is quick and easy.
            outer = outer.GetFieldInitializerBinder(symbol, suppressBinderFlagsFieldInitializer: !this.IsRegularCSharp && symbol.ContainingType.IsScriptClass);
 
            if (initializer != null)
            {
                outer = new ExecutableCodeBinder(initializer, symbol, outer);
            }
 
            return outer;
        }
 
        private static bool IsMemberDeclaration(CSharpSyntaxNode node)
        {
            return (node is MemberDeclarationSyntax) || (node is AccessorDeclarationSyntax) ||
                   (node.Kind() == SyntaxKind.Attribute) || (node.Kind() == SyntaxKind.Parameter);
        }
 
        private bool IsRegularCSharp
        {
            get
            {
                return this.SyntaxTree.Options.Kind == SourceCodeKind.Regular;
            }
        }
 
        #region "GetDeclaredSymbol overloads for MemberDeclarationSyntax and its subtypes"
 
        /// <inheritdoc/>
        public override INamespaceSymbol GetDeclaredSymbol(NamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            return GetDeclaredNamespace(declarationSyntax).GetPublicSymbol();
        }
 
        /// <inheritdoc/>
        public override INamespaceSymbol GetDeclaredSymbol(FileScopedNamespaceDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default)
        {
            CheckSyntaxNode(declarationSyntax);
 
            return GetDeclaredNamespace(declarationSyntax).GetPublicSymbol();
        }
 
        private NamespaceSymbol GetDeclaredNamespace(BaseNamespaceDeclarationSyntax declarationSyntax)
        {
            Debug.Assert(declarationSyntax != null);
 
            NamespaceOrTypeSymbol container;
            if (declarationSyntax.Parent.Kind() == SyntaxKind.CompilationUnit)
            {
                container = _compilation.Assembly.GlobalNamespace;
            }
            else
            {
                container = GetDeclaredNamespaceOrType(declarationSyntax.Parent);
            }
 
            Debug.Assert((object)container != null);
 
            // We should get a namespace symbol since we match the symbol location with a namespace declaration syntax location.
            var symbol = GetDeclaredNamespace(container, declarationSyntax.Span, declarationSyntax.Name);
            Debug.Assert((object)symbol != null);
 
            // Map to compilation-scoped namespace (Roslyn bug 9538)
            symbol = _compilation.GetCompilationNamespace(symbol);
            Debug.Assert((object)symbol != null);
 
            return symbol;
        }
 
        /// <summary>
        /// Given a type declaration, get the corresponding type symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a type.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The type symbol that was declared.</returns>
        /// <remarks>
        /// NOTE:   We have no GetDeclaredSymbol overloads for subtypes of BaseTypeDeclarationSyntax as all of them return a NamedTypeSymbol.
        /// </remarks>
        public override INamedTypeSymbol GetDeclaredSymbol(BaseTypeDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            return GetDeclaredType(declarationSyntax).GetPublicSymbol();
        }
 
        /// <summary>
        /// Given a delegate declaration, get the corresponding type symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a delegate.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The type symbol that was declared.</returns>
        public override INamedTypeSymbol GetDeclaredSymbol(DelegateDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            return GetDeclaredType(declarationSyntax).GetPublicSymbol();
        }
 
        private NamedTypeSymbol GetDeclaredType(BaseTypeDeclarationSyntax declarationSyntax)
        {
            Debug.Assert(declarationSyntax != null);
 
            var name = declarationSyntax.Identifier.ValueText;
            return GetDeclaredNamedType(declarationSyntax, name);
        }
 
        private NamedTypeSymbol GetDeclaredType(DelegateDeclarationSyntax declarationSyntax)
        {
            Debug.Assert(declarationSyntax != null);
 
            var name = declarationSyntax.Identifier.ValueText;
            return GetDeclaredNamedType(declarationSyntax, name);
        }
 
        private NamedTypeSymbol GetDeclaredNamedType(CSharpSyntaxNode declarationSyntax, string name)
        {
            Debug.Assert(declarationSyntax != null);
 
            var container = GetDeclaredTypeMemberContainer(declarationSyntax);
            Debug.Assert((object)container != null);
 
            // try cast as we might get a non-type in error recovery scenarios:
            return GetDeclaredMember(container, declarationSyntax.Span, isKnownToBeANamespace: false, name) as NamedTypeSymbol;
        }
 
        private NamespaceOrTypeSymbol GetDeclaredNamespaceOrType(CSharpSyntaxNode declarationSyntax)
        {
            var namespaceDeclarationSyntax = declarationSyntax as BaseNamespaceDeclarationSyntax;
            if (namespaceDeclarationSyntax != null)
            {
                return GetDeclaredNamespace(namespaceDeclarationSyntax);
            }
 
            var typeDeclarationSyntax = declarationSyntax as BaseTypeDeclarationSyntax;
            if (typeDeclarationSyntax != null)
            {
                return GetDeclaredType(typeDeclarationSyntax);
            }
 
            var delegateDeclarationSyntax = declarationSyntax as DelegateDeclarationSyntax;
            if (delegateDeclarationSyntax != null)
            {
                return GetDeclaredType(delegateDeclarationSyntax);
            }
 
            return null;
        }
 
        /// <summary>
        /// Given a member declaration syntax, get the corresponding symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a member.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        /// <remarks>
        /// NOTE:   We have no GetDeclaredSymbol overloads for following subtypes of MemberDeclarationSyntax:
        /// NOTE:   (1) GlobalStatementSyntax as they don't declare any symbols.
        /// NOTE:   (2) IncompleteMemberSyntax as there are no symbols for incomplete members.
        /// NOTE:   (3) BaseFieldDeclarationSyntax or its subtypes as these declarations can contain multiple variable declarators.
        /// NOTE:       GetDeclaredSymbol should be called on the variable declarators directly.
        /// </remarks>
        public override ISymbol GetDeclaredSymbol(MemberDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            switch (declarationSyntax.Kind())
            {
                // Few subtypes of MemberDeclarationSyntax don't declare any symbols or declare multiple symbols, return null for these cases.
 
                case SyntaxKind.GlobalStatement:
                    // Global statements don't declare anything, even though they inherit from MemberDeclarationSyntax.
                    return null;
 
                case SyntaxKind.IncompleteMember:
                    // Incomplete members don't declare any symbols.
                    return null;
 
                case SyntaxKind.EventFieldDeclaration:
                case SyntaxKind.FieldDeclaration:
                    // these declarations can contain multiple variable declarators. GetDeclaredSymbol should be called on them directly.
                    return null;
 
                default:
                    return (GetDeclaredNamespaceOrType(declarationSyntax) ?? GetDeclaredMemberSymbol(declarationSyntax)).GetPublicSymbol();
            }
        }
 
        public override IMethodSymbol GetDeclaredSymbol(CompilationUnitSyntax declarationSyntax, CancellationToken cancellationToken = default)
        {
            CheckSyntaxNode(declarationSyntax);
 
            return SynthesizedSimpleProgramEntryPointSymbol.GetSimpleProgramEntryPoint(Compilation, declarationSyntax, fallbackToMainEntryPoint: false).GetPublicSymbol();
        }
 
        /// <summary>
        /// Given a local function declaration syntax, get the corresponding symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a member.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        public override IMethodSymbol GetDeclaredSymbol(LocalFunctionStatementSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            return this.GetMemberModel(declarationSyntax)?.GetDeclaredSymbol(declarationSyntax, cancellationToken);
        }
 
        /// <summary>
        /// Given a enum member declaration, get the corresponding field symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares an enum member.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        public override IFieldSymbol GetDeclaredSymbol(EnumMemberDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            return ((FieldSymbol)GetDeclaredMemberSymbol(declarationSyntax)).GetPublicSymbol();
        }
 
        /// <summary>
        /// Given a base method declaration syntax, get the corresponding method symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a method.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        /// <remarks>
        /// NOTE:   We have no GetDeclaredSymbol overloads for subtypes of BaseMethodDeclarationSyntax as all of them return a MethodSymbol.
        /// </remarks>
        public override IMethodSymbol GetDeclaredSymbol(BaseMethodDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            return ((MethodSymbol)GetDeclaredMemberSymbol(declarationSyntax)).GetPublicSymbol();
        }
 
        #region "GetDeclaredSymbol overloads for BasePropertyDeclarationSyntax and its subtypes"
 
        /// <summary>
        /// Given a syntax node that declares a property, indexer or an event, get the corresponding declared symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a property, indexer or an event.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        public override ISymbol GetDeclaredSymbol(BasePropertyDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            return GetDeclaredMemberSymbol(declarationSyntax).GetPublicSymbol();
        }
 
        /// <summary>
        /// Given a syntax node that declares a property, get the corresponding declared symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a property, indexer or an event.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        public override IPropertySymbol GetDeclaredSymbol(PropertyDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            return ((PropertySymbol)GetDeclaredMemberSymbol(declarationSyntax)).GetPublicSymbol();
        }
 
        /// <summary>
        /// Given a syntax node that declares an indexer, get the corresponding declared symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares an indexer.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        public override IPropertySymbol GetDeclaredSymbol(IndexerDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            return ((PropertySymbol)GetDeclaredMemberSymbol(declarationSyntax)).GetPublicSymbol();
        }
 
        /// <summary>
        /// Given a syntax node that declares a (custom) event, get the corresponding event symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a event.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        public override IEventSymbol GetDeclaredSymbol(EventDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            return ((EventSymbol)GetDeclaredMemberSymbol(declarationSyntax)).GetPublicSymbol();
        }
 
        #endregion
 
        #endregion
 
        /// <summary>
        /// Given a syntax node that declares a property or member accessor, get the corresponding symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares an accessor.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        public override IMethodSymbol GetDeclaredSymbol(AccessorDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            if (declarationSyntax.Kind() == SyntaxKind.UnknownAccessorDeclaration)
            {
                // this is not a real accessor, so we shouldn't return anything.
                return null;
            }
 
            var propertyOrEventDecl = declarationSyntax.Parent.Parent;
 
            switch (propertyOrEventDecl.Kind())
            {
                case SyntaxKind.PropertyDeclaration:
                case SyntaxKind.IndexerDeclaration:
                case SyntaxKind.EventDeclaration:
                case SyntaxKind.EventFieldDeclaration:
                    // NOTE: it's an error for field-like events to have accessors, 
                    // but we want to bind them anyway for error tolerance reasons.
                    var container = GetDeclaredTypeMemberContainer(propertyOrEventDecl);
                    Debug.Assert((object)container != null);
                    Debug.Assert(declarationSyntax.Keyword.Kind() != SyntaxKind.IdentifierToken);
                    return (this.GetDeclaredMember(container, declarationSyntax.Span, isKnownToBeANamespace: false) as MethodSymbol).GetPublicSymbol();
 
                default:
                    throw ExceptionUtilities.UnexpectedValue(propertyOrEventDecl.Kind());
            }
        }
 
        public override IMethodSymbol GetDeclaredSymbol(ArrowExpressionClauseSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            var containingMemberSyntax = declarationSyntax.Parent;
 
            NamespaceOrTypeSymbol container;
            switch (containingMemberSyntax.Kind())
            {
                case SyntaxKind.PropertyDeclaration:
                case SyntaxKind.IndexerDeclaration:
                    container = GetDeclaredTypeMemberContainer(containingMemberSyntax);
                    Debug.Assert((object)container != null);
                    // We are looking for the SourcePropertyAccessorSymbol here,
                    // not the SourcePropertySymbol, so use declarationSyntax
                    // to exclude the property symbol from being retrieved.
                    return (this.GetDeclaredMember(container, declarationSyntax.Span, isKnownToBeANamespace: false) as MethodSymbol).GetPublicSymbol();
 
                default:
                    // Don't throw, use only for the assert
                    ExceptionUtilities.UnexpectedValue(containingMemberSyntax.Kind());
                    return null;
            }
        }
 
        private string GetDeclarationName(CSharpSyntaxNode declaration)
        {
            switch (declaration.Kind())
            {
                case SyntaxKind.MethodDeclaration:
                    {
                        var methodDecl = (MethodDeclarationSyntax)declaration;
                        return GetDeclarationName(declaration, methodDecl.ExplicitInterfaceSpecifier, methodDecl.Identifier.ValueText);
                    }
 
                case SyntaxKind.PropertyDeclaration:
                    {
                        var propertyDecl = (PropertyDeclarationSyntax)declaration;
                        return GetDeclarationName(declaration, propertyDecl.ExplicitInterfaceSpecifier, propertyDecl.Identifier.ValueText);
                    }
 
                case SyntaxKind.IndexerDeclaration:
                    {
                        var indexerDecl = (IndexerDeclarationSyntax)declaration;
                        return GetDeclarationName(declaration, indexerDecl.ExplicitInterfaceSpecifier, WellKnownMemberNames.Indexer);
                    }
 
                case SyntaxKind.EventDeclaration:
                    {
                        var eventDecl = (EventDeclarationSyntax)declaration;
                        return GetDeclarationName(declaration, eventDecl.ExplicitInterfaceSpecifier, eventDecl.Identifier.ValueText);
                    }
 
                case SyntaxKind.DelegateDeclaration:
                    return ((DelegateDeclarationSyntax)declaration).Identifier.ValueText;
 
                case SyntaxKind.InterfaceDeclaration:
                case SyntaxKind.StructDeclaration:
                case SyntaxKind.ClassDeclaration:
                case SyntaxKind.EnumDeclaration:
                case SyntaxKind.RecordDeclaration:
                case SyntaxKind.RecordStructDeclaration:
                    return ((BaseTypeDeclarationSyntax)declaration).Identifier.ValueText;
 
                case SyntaxKind.VariableDeclarator:
                    return ((VariableDeclaratorSyntax)declaration).Identifier.ValueText;
 
                case SyntaxKind.EnumMemberDeclaration:
                    return ((EnumMemberDeclarationSyntax)declaration).Identifier.ValueText;
 
                case SyntaxKind.DestructorDeclaration:
                    return WellKnownMemberNames.DestructorName;
 
                case SyntaxKind.ConstructorDeclaration:
                    if (((ConstructorDeclarationSyntax)declaration).Modifiers.Any(SyntaxKind.StaticKeyword))
                    {
                        return WellKnownMemberNames.StaticConstructorName;
                    }
                    else
                    {
                        return WellKnownMemberNames.InstanceConstructorName;
                    }
 
                case SyntaxKind.OperatorDeclaration:
                    {
                        var operatorDecl = (OperatorDeclarationSyntax)declaration;
                        return GetDeclarationName(declaration, operatorDecl.ExplicitInterfaceSpecifier, OperatorFacts.OperatorNameFromDeclaration(operatorDecl));
                    }
 
                case SyntaxKind.ConversionOperatorDeclaration:
                    {
                        var operatorDecl = (ConversionOperatorDeclarationSyntax)declaration;
                        return GetDeclarationName(declaration, operatorDecl.ExplicitInterfaceSpecifier, OperatorFacts.OperatorNameFromDeclaration(operatorDecl));
                    }
 
                case SyntaxKind.EventFieldDeclaration:
                case SyntaxKind.FieldDeclaration:
                    throw new ArgumentException(CSharpResources.InvalidGetDeclarationNameMultipleDeclarators);
 
                case SyntaxKind.IncompleteMember:
                    // There is no name - that's why it's an incomplete member.
                    return null;
 
                default:
                    throw ExceptionUtilities.UnexpectedValue(declaration.Kind());
            }
        }
 
        private string GetDeclarationName(CSharpSyntaxNode declaration, ExplicitInterfaceSpecifierSyntax explicitInterfaceSpecifierOpt, string memberName)
        {
            if (explicitInterfaceSpecifierOpt == null)
            {
                return memberName;
            }
 
            // For an explicit interface implementation, we actually have several options:
            //  Option 1: do nothing - it will retry without the name
            //  Option 2: detect explicit impl and return null
            //  Option 3: get a binder and figure out the name
            // For now, we're going with Option 3
            return ExplicitInterfaceHelpers.GetMemberName(_binderFactory.GetBinder(declaration), explicitInterfaceSpecifierOpt, memberName);
        }
 
        private NamespaceSymbol GetDeclaredNamespace(NamespaceOrTypeSymbol container, TextSpan declarationSpan, NameSyntax name)
        {
            switch (name.Kind())
            {
                case SyntaxKind.GenericName:
                case SyntaxKind.IdentifierName:
                    return (NamespaceSymbol)GetDeclaredMember(container, declarationSpan, isKnownToBeANamespace: true, ((SimpleNameSyntax)name).Identifier.ValueText);
 
                case SyntaxKind.QualifiedName:
                    var qn = (QualifiedNameSyntax)name;
                    var left = GetDeclaredNamespace(container, declarationSpan, qn.Left) as NamespaceOrTypeSymbol;
                    Debug.Assert((object)left != null);
                    return GetDeclaredNamespace(left, declarationSpan, qn.Right);
 
                case SyntaxKind.AliasQualifiedName:
                    // this is not supposed to happen, but we allow for errors don't we!
                    var an = (AliasQualifiedNameSyntax)name;
                    return GetDeclaredNamespace(container, declarationSpan, an.Name);
 
                default:
                    throw ExceptionUtilities.UnexpectedValue(name.Kind());
            }
        }
 
        /// <summary>
        /// Finds the member in the containing symbol which is inside the given declaration span.
        /// </summary>
        /// <param name="isKnownToBeANamespace"><see langword="true"/> if the result is known to be a
        /// <see cref="NamespaceSymbol"/> (e.g. when the caller is <see cref="GetDeclaredNamespace(BaseNamespaceDeclarationSyntax)"/>;
        /// otherwise, <see langword="false"/> if the symbol kind is either unknown or known to not be a
        /// <see cref="NamespaceSymbol"/>.</param>
        private Symbol GetDeclaredMember(NamespaceOrTypeSymbol container, TextSpan declarationSpan, bool isKnownToBeANamespace, string name = null)
        {
            if ((object)container == null)
            {
                return null;
            }
 
            // look for any member with same declaration location
            var collection = name != null ? container.GetMembers(name) : container.GetMembersUnordered();
            if (isKnownToBeANamespace)
            {
                // Filter the collection to only include namespace symbols. This will not allocate a new instance for
                // the common case where all symbols in the collection are already namespace symbols.
                var namespaces = collection.WhereAsArray(symbol => symbol is NamespaceSymbol);
 
                Debug.Assert(name is not null, "Should only be looking for a known namespace by name.");
                Debug.Assert(namespaces is [NamespaceSymbol], "Namespace declarations of the same name are expected to appear as a single merged symbol.");
 
                if (name != null && namespaces is [NamespaceSymbol knownNamespace])
                {
                    Debug.Assert(knownNamespace.HasLocationContainedWithin(SyntaxTree, declarationSpan, out _), "Namespace symbols should include all syntax declaration locations.");
 
                    // Avoid O(n²) lookup for merged namespaces with a large number of parts
                    // https://github.com/dotnet/roslyn/issues/49769
                    return knownNamespace;
                }
            }
 
            Symbol zeroWidthMatch = null;
            foreach (var symbol in collection)
            {
                var namedType = symbol as ImplicitNamedTypeSymbol;
                if ((object)namedType != null && namedType.IsImplicitClass)
                {
                    // look inside wrapper around illegally placed members in namespaces
                    var result = GetDeclaredMember(namedType, declarationSpan, isKnownToBeANamespace, name);
                    if ((object)result != null)
                    {
                        return result;
                    }
                }
 
                if (symbol.HasLocationContainedWithin(this.SyntaxTree, declarationSpan, out var wasZeroWidthMatch))
                {
                    if (!wasZeroWidthMatch)
                        return symbol;
 
                    // exclude decls created via syntax recovery
                    zeroWidthMatch = symbol;
                }
 
                // Handle the case of the implementation of a partial member.
                Symbol partial = symbol switch
                {
                    MethodSymbol method => method.PartialImplementationPart,
                    SourcePropertySymbol property => property.PartialImplementationPart,
                    _ => null
                };
 
                if ((object)partial != null)
                {
                    var loc = partial.GetFirstLocation();
                    if (loc.IsInSource && loc.SourceTree == this.SyntaxTree && declarationSpan.Contains(loc.SourceSpan))
                    {
                        return partial;
                    }
                }
            }
 
            // If we didn't find anything better than the symbol that matched because of syntax error recovery, then return that.
            // Otherwise, if there's a name, try again without a name.
            // Otherwise, give up.
            return zeroWidthMatch ??
                (name != null ? GetDeclaredMember(container, declarationSpan, isKnownToBeANamespace, name: null) : null);
        }
 
        /// <summary>
        /// Given a variable declarator syntax, get the corresponding symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a variable.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The symbol that was declared.</returns>
        public override ISymbol GetDeclaredSymbol(VariableDeclaratorSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            var field = declarationSyntax.Parent == null ? null : declarationSyntax.Parent.Parent as BaseFieldDeclarationSyntax;
            if (field != null)
            {
                var container = GetDeclaredTypeMemberContainer(field);
                Debug.Assert((object)container != null);
 
                var result = this.GetDeclaredMember(container, declarationSyntax.Span, isKnownToBeANamespace: false, declarationSyntax.Identifier.ValueText);
                Debug.Assert((object)result != null);
 
                return result.GetPublicSymbol();
            }
 
            // Might be a local variable.
            var memberModel = this.GetMemberModel(declarationSyntax);
            return memberModel?.GetDeclaredSymbol(declarationSyntax, cancellationToken);
        }
 
        public override ISymbol GetDeclaredSymbol(SingleVariableDesignationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            // Might be a local variable.
            var memberModel = this.GetMemberModel(declarationSyntax);
            ISymbol local = memberModel?.GetDeclaredSymbol(declarationSyntax, cancellationToken);
 
            if (local != null)
            {
                return local;
            }
 
            // Might be a field
            Binder binder = GetEnclosingBinder(declarationSyntax.Position);
            return binder?.LookupDeclaredField(declarationSyntax).GetPublicSymbol();
        }
 
        internal override LocalSymbol GetAdjustedLocalSymbol(SourceLocalSymbol originalSymbol)
        {
            var position = originalSymbol.IdentifierToken.SpanStart;
            return GetMemberModel(position)?.GetAdjustedLocalSymbol(originalSymbol) ?? originalSymbol;
        }
 
        /// <summary>
        /// Given a labeled statement syntax, get the corresponding label symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node of the labeled statement.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The label symbol for that label.</returns>
        public override ILabelSymbol GetDeclaredSymbol(LabeledStatementSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            var memberModel = this.GetMemberModel(declarationSyntax);
            return memberModel == null ? null : memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken);
        }
 
        /// <summary>
        /// Given a switch label syntax, get the corresponding label symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node of the switch label.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The label symbol for that label.</returns>
        public override ILabelSymbol GetDeclaredSymbol(SwitchLabelSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            var memberModel = this.GetMemberModel(declarationSyntax);
            return memberModel == null ? null : memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken);
        }
 
        /// <summary>
        /// Given a using declaration get the corresponding symbol for the using alias that was introduced.  
        /// </summary>
        /// <param name="declarationSyntax"></param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The alias symbol that was declared.</returns>
        /// <remarks>
        /// If the using directive is an error because it attempts to introduce an alias for which an existing alias was
        /// previously declared in the same scope, the result is a newly-constructed AliasSymbol (i.e. not one from the
        /// symbol table).
        /// </remarks>
        public override IAliasSymbol GetDeclaredSymbol(
            UsingDirectiveSyntax declarationSyntax,
            CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            if (declarationSyntax.Alias == null)
            {
                return null;
            }
 
            Binder binder = _binderFactory.GetInNamespaceBinder(declarationSyntax.Parent);
 
            for (; binder != null; binder = binder.Next)
            {
                var usingAliases = binder.UsingAliases;
 
                if (!usingAliases.IsDefault)
                {
                    foreach (var alias in usingAliases)
                    {
                        if (alias.Alias.GetFirstLocation().SourceSpan == declarationSyntax.Alias.Name.Span)
                        {
                            return alias.Alias.GetPublicSymbol();
                        }
                    }
 
                    break;
                }
            }
 
            return null;
        }
 
        /// <summary>
        /// Given an extern alias declaration get the corresponding symbol for the alias that was introduced.
        /// </summary>
        /// <param name="declarationSyntax"></param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The alias symbol that was declared, or null if a duplicate alias symbol was declared.</returns>
        public override IAliasSymbol GetDeclaredSymbol(ExternAliasDirectiveSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            var binder = _binderFactory.GetInNamespaceBinder(declarationSyntax.Parent);
 
            for (; binder != null; binder = binder.Next)
            {
                var externAliases = binder.ExternAliases;
 
                if (!externAliases.IsDefault)
                {
                    foreach (var alias in externAliases)
                    {
                        if (alias.Alias.GetFirstLocation().SourceSpan == declarationSyntax.Identifier.Span)
                        {
                            return alias.Alias.GetPublicSymbol();
                        }
                    }
 
                    break;
                }
            }
 
            return null;
        }
 
        /// <summary>
        /// Given a base field declaration syntax, get the corresponding symbols.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares one or more fields or events.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The field symbols that were declared.</returns>
        internal override ImmutableArray<ISymbol> GetDeclaredSymbols(BaseFieldDeclarationSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            var builder = new ArrayBuilder<ISymbol>();
 
            foreach (var declarator in declarationSyntax.Declaration.Variables)
            {
                var field = this.GetDeclaredSymbol(declarator, cancellationToken) as ISymbol;
                if (field != null)
                {
                    builder.Add(field);
                }
            }
 
            return builder.ToImmutableAndFree();
        }
 
        private ParameterSymbol GetMethodParameterSymbol(
            ParameterSyntax parameter,
            CancellationToken cancellationToken)
        {
            Debug.Assert(parameter != null);
 
            var paramList = parameter.Parent as ParameterListSyntax;
            if (paramList == null)
            {
                return null;
            }
 
            var memberDecl = paramList.Parent as MemberDeclarationSyntax;
            if (memberDecl == null)
            {
                return null;
            }
 
            MethodSymbol method;
 
            if (memberDecl is TypeDeclarationSyntax typeDecl && typeDecl.ParameterList == paramList)
            {
                method = TryGetSynthesizedPrimaryConstructor(typeDecl);
            }
            else
            {
                method = (GetDeclaredSymbol(memberDecl, cancellationToken) as IMethodSymbol).GetSymbol();
            }
 
            if ((object)method == null)
            {
                return null;
            }
 
            return GetParameterSymbol(method.Parameters, parameter, cancellationToken);
        }
 
        private ParameterSymbol GetIndexerParameterSymbol(
            ParameterSyntax parameter,
            CancellationToken cancellationToken)
        {
            Debug.Assert(parameter != null);
 
            var paramList = parameter.Parent as BracketedParameterListSyntax;
            if (paramList == null)
            {
                return null;
            }
 
            var memberDecl = paramList.Parent as MemberDeclarationSyntax;
            if (memberDecl == null)
            {
                return null;
            }
 
            var property = (GetDeclaredSymbol(memberDecl, cancellationToken) as IPropertySymbol).GetSymbol();
            if ((object)property == null)
            {
                return null;
            }
 
            return GetParameterSymbol(property.Parameters, parameter, cancellationToken);
        }
 
        private ParameterSymbol GetDelegateParameterSymbol(
            ParameterSyntax parameter,
            CancellationToken cancellationToken)
        {
            Debug.Assert(parameter != null);
 
            var paramList = parameter.Parent as ParameterListSyntax;
            if (paramList == null)
            {
                return null;
            }
 
            var memberDecl = paramList.Parent as DelegateDeclarationSyntax;
            if (memberDecl == null)
            {
                return null;
            }
 
            var delegateType = (GetDeclaredSymbol(memberDecl, cancellationToken) as INamedTypeSymbol).GetSymbol();
            if ((object)delegateType == null)
            {
                return null;
            }
 
            var delegateInvoke = delegateType.DelegateInvokeMethod;
            if ((object)delegateInvoke == null || delegateInvoke.HasUseSiteError)
            {
                return null;
            }
 
            return GetParameterSymbol(delegateInvoke.Parameters, parameter, cancellationToken);
        }
 
        /// <summary>
        /// Given a parameter declaration syntax node, get the corresponding symbol.
        /// </summary>
        /// <param name="declarationSyntax">The syntax node that declares a parameter.</param>
        /// <param name="cancellationToken">The cancellation token.</param>
        /// <returns>The parameter that was declared.</returns>
        public override IParameterSymbol GetDeclaredSymbol(ParameterSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            CheckSyntaxNode(declarationSyntax);
 
            MemberSemanticModel memberModel = this.GetMemberModel(declarationSyntax);
            if (memberModel != null)
            {
                // Could be parameter of lambda.
                return memberModel.GetDeclaredSymbol(declarationSyntax, cancellationToken);
            }
 
            return GetDeclaredNonLambdaParameterSymbol(declarationSyntax, cancellationToken).GetPublicSymbol();
        }
 
        private ParameterSymbol GetDeclaredNonLambdaParameterSymbol(ParameterSyntax declarationSyntax, CancellationToken cancellationToken = default(CancellationToken))
        {
            return
                GetMethodParameterSymbol(declarationSyntax, cancellationToken) ??
                GetIndexerParameterSymbol(declarationSyntax, cancellationToken) ??
                GetDelegateParameterSymbol(declarationSyntax, cancellationToken);
        }
 
        /// <summary>
        /// Given a type parameter declaration (on a type or method), get the corresponding symbol
        /// </summary>
        public override ITypeParameterSymbol GetDeclaredSymbol(TypeParameterSyntax typeParameter, CancellationToken cancellationToken = default(CancellationToken))
        {
            if (typeParameter == null)
            {
                throw new ArgumentNullException(nameof(typeParameter));
            }
 
            if (!IsInTree(typeParameter))
            {
                throw new ArgumentException("typeParameter not within tree");
            }
 
            if (typeParameter.Parent is TypeParameterListSyntax typeParamList)
            {
                ISymbol parameterizedSymbol = null;
                switch (typeParamList.Parent)
                {
                    case MemberDeclarationSyntax memberDecl:
                        parameterizedSymbol = GetDeclaredSymbol(memberDecl, cancellationToken);
                        break;
                    case LocalFunctionStatementSyntax localDecl:
                        parameterizedSymbol = GetDeclaredSymbol(localDecl, cancellationToken);
                        break;
                    default:
                        throw ExceptionUtilities.UnexpectedValue(typeParameter.Parent.Kind());
                }
 
                switch (parameterizedSymbol.GetSymbol())
                {
                    case NamedTypeSymbol typeSymbol:
                        return this.GetTypeParameterSymbol(typeSymbol.TypeParameters, typeParameter).GetPublicSymbol();
 
                    case MethodSymbol methodSymbol:
                        return this.GetTypeParameterSymbol(methodSymbol.TypeParameters, typeParameter).GetPublicSymbol();
                }
            }
 
            return null;
        }
 
        private TypeParameterSymbol GetTypeParameterSymbol(ImmutableArray<TypeParameterSymbol> parameters, TypeParameterSyntax parameter)
        {
            foreach (var symbol in parameters)
            {
                foreach (var location in symbol.Locations)
                {
                    if (location.SourceTree == this.SyntaxTree && parameter.Span.Contains(location.SourceSpan))
                    {
                        return symbol;
                    }
                }
            }
 
            return null;
        }
 
        public override ControlFlowAnalysis AnalyzeControlFlow(StatementSyntax firstStatement, StatementSyntax lastStatement)
        {
            ValidateStatementRange(firstStatement, lastStatement);
            var context = RegionAnalysisContext(firstStatement, lastStatement);
            var result = new CSharpControlFlowAnalysis(context);
            return result;
        }
 
        private void ValidateStatementRange(StatementSyntax firstStatement, StatementSyntax lastStatement)
        {
            if (firstStatement == null)
            {
                throw new ArgumentNullException(nameof(firstStatement));
            }
 
            if (lastStatement == null)
            {
                throw new ArgumentNullException(nameof(lastStatement));
            }
 
            if (!IsInTree(firstStatement))
            {
                throw new ArgumentException("statements not within tree");
            }
 
            // Global statements don't have their parent in common, but should belong to the same compilation unit
            bool isGlobalStatement = firstStatement.Parent is GlobalStatementSyntax;
            if (isGlobalStatement && (lastStatement.Parent is not GlobalStatementSyntax || firstStatement.Parent.Parent != lastStatement.Parent.Parent))
            {
                throw new ArgumentException("global statements not within the same compilation unit");
            }
 
            // Non-global statements, the parents should be the same
            if (!isGlobalStatement && (firstStatement.Parent == null || firstStatement.Parent != lastStatement.Parent))
            {
                throw new ArgumentException("statements not within the same statement list");
            }
 
            if (firstStatement.SpanStart > lastStatement.SpanStart)
            {
                throw new ArgumentException("first statement does not precede last statement");
            }
        }
 
        public override DataFlowAnalysis AnalyzeDataFlow(ExpressionSyntax expression)
        {
            if (expression == null)
            {
                throw new ArgumentNullException(nameof(expression));
            }
 
            if (!IsInTree(expression))
            {
                throw new ArgumentException("expression not within tree");
            }
 
            var context = RegionAnalysisContext(expression);
            var result = new CSharpDataFlowAnalysis(context);
            return result;
        }
 
        public override DataFlowAnalysis AnalyzeDataFlow(ConstructorInitializerSyntax constructorInitializer)
        {
            if (constructorInitializer == null)
            {
                throw new ArgumentNullException(nameof(constructorInitializer));
            }
 
            if (!IsInTree(constructorInitializer))
            {
                throw new ArgumentException("node not within tree");
            }
 
            var context = RegionAnalysisContext(constructorInitializer);
            var result = new CSharpDataFlowAnalysis(context);
            return result;
        }
 
        public override DataFlowAnalysis AnalyzeDataFlow(PrimaryConstructorBaseTypeSyntax primaryConstructorBaseType)
        {
            if (primaryConstructorBaseType == null)
            {
                throw new ArgumentNullException(nameof(primaryConstructorBaseType));
            }
 
            if (!IsInTree(primaryConstructorBaseType))
            {
                throw new ArgumentException("node not within tree");
            }
 
            var context = RegionAnalysisContext(primaryConstructorBaseType);
            var result = new CSharpDataFlowAnalysis(context);
            return result;
        }
 
        public override DataFlowAnalysis AnalyzeDataFlow(StatementSyntax firstStatement, StatementSyntax lastStatement)
        {
            ValidateStatementRange(firstStatement, lastStatement);
            var context = RegionAnalysisContext(firstStatement, lastStatement);
            var result = new CSharpDataFlowAnalysis(context);
            return result;
        }
 
        private static BoundNode GetBoundRoot(MemberSemanticModel memberModel, out Symbol member)
        {
            member = memberModel.MemberSymbol;
            return memberModel.GetBoundRoot();
        }
 
        private NamespaceOrTypeSymbol GetDeclaredTypeMemberContainer(CSharpSyntaxNode memberDeclaration)
        {
            if (memberDeclaration.Parent.Kind() == SyntaxKind.CompilationUnit)
            {
                // top-level namespace:
                if (memberDeclaration.Kind() is SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration)
                {
                    return _compilation.Assembly.GlobalNamespace;
                }
 
                // top-level members in script or interactive code:
                if (this.SyntaxTree.Options.Kind != SourceCodeKind.Regular)
                {
                    return this.Compilation.ScriptClass;
                }
 
                // top-level type in an explicitly declared namespace:
                if (SyntaxFacts.IsTypeDeclaration(memberDeclaration.Kind()))
                {
                    return _compilation.Assembly.GlobalNamespace;
                }
 
                // other top-level members:
                return _compilation.Assembly.GlobalNamespace.ImplicitType;
            }
 
            var container = GetDeclaredNamespaceOrType(memberDeclaration.Parent);
            Debug.Assert((object)container != null);
 
            // member in a type:
            if (!container.IsNamespace)
            {
                return container;
            }
 
            // a namespace or a type in an explicitly declared namespace:
            if (memberDeclaration.Kind() is SyntaxKind.NamespaceDeclaration or SyntaxKind.FileScopedNamespaceDeclaration
                || SyntaxFacts.IsTypeDeclaration(memberDeclaration.Kind()))
            {
                return container;
            }
 
            // another member in a namespace:
            return ((NamespaceSymbol)container).ImplicitType;
        }
 
        private Symbol GetDeclaredMemberSymbol(CSharpSyntaxNode declarationSyntax)
        {
            CheckSyntaxNode(declarationSyntax);
 
            var container = GetDeclaredTypeMemberContainer(declarationSyntax);
            var name = GetDeclarationName(declarationSyntax);
            return this.GetDeclaredMember(container, declarationSyntax.Span, isKnownToBeANamespace: false, name);
        }
 
        public override AwaitExpressionInfo GetAwaitExpressionInfo(AwaitExpressionSyntax node)
        {
            MemberSemanticModel memberModel = GetMemberModel(node);
            return memberModel == null ? default(AwaitExpressionInfo) : memberModel.GetAwaitExpressionInfo(node);
        }
 
        public override ForEachStatementInfo GetForEachStatementInfo(ForEachStatementSyntax node)
        {
            MemberSemanticModel memberModel = GetMemberModel(node);
            return memberModel == null ? default(ForEachStatementInfo) : memberModel.GetForEachStatementInfo(node);
        }
 
        public override ForEachStatementInfo GetForEachStatementInfo(CommonForEachStatementSyntax node)
        {
            MemberSemanticModel memberModel = GetMemberModel(node);
            return memberModel == null ? default(ForEachStatementInfo) : memberModel.GetForEachStatementInfo(node);
        }
 
        public override DeconstructionInfo GetDeconstructionInfo(AssignmentExpressionSyntax node)
        {
            MemberSemanticModel memberModel = GetMemberModel(node);
            return memberModel?.GetDeconstructionInfo(node) ?? default;
        }
 
        public override DeconstructionInfo GetDeconstructionInfo(ForEachVariableStatementSyntax node)
        {
            MemberSemanticModel memberModel = GetMemberModel(node);
            return memberModel?.GetDeconstructionInfo(node) ?? default;
        }
 
        internal override Symbol RemapSymbolIfNecessaryCore(Symbol symbol)
        {
            Debug.Assert(symbol is LocalSymbol or ParameterSymbol or MethodSymbol { MethodKind: MethodKind.LambdaMethod });
 
            if (symbol.TryGetFirstLocation() is not Location location)
            {
                return symbol;
            }
 
            // The symbol may be from a distinct syntax tree - perhaps the
            // symbol was returned from LookupSymbols() for instance.
            if (location.SourceTree != this.SyntaxTree)
            {
                return symbol;
            }
 
            var position = CheckAndAdjustPosition(location.SourceSpan.Start);
            var memberModel = GetMemberModel(position);
            return memberModel?.RemapSymbolIfNecessaryCore(symbol) ?? symbol;
        }
 
        internal override Func<SyntaxNode, bool> GetSyntaxNodesToAnalyzeFilter(SyntaxNode declaredNode, ISymbol declaredSymbol)
        {
            switch (declaredNode)
            {
                case CompilationUnitSyntax unit when SynthesizedSimpleProgramEntryPointSymbol.GetSimpleProgramEntryPoint(Compilation, unit, fallbackToMainEntryPoint: false) is SynthesizedSimpleProgramEntryPointSymbol entryPoint:
                    switch (declaredSymbol.Kind)
                    {
                        case SymbolKind.Namespace:
                            Debug.Assert(((INamespaceSymbol)declaredSymbol).IsGlobalNamespace);
                            // Do not include top level global statements into a global namespace
                            return (node) => node.Kind() != SyntaxKind.GlobalStatement || node.Parent != unit;
 
                        case SymbolKind.Method:
                            Debug.Assert((object)declaredSymbol.GetSymbol() == (object)entryPoint);
                            // Include only global statements at the top level
                            return (node) => node.Parent != unit || node.Kind() == SyntaxKind.GlobalStatement;
 
                        case SymbolKind.NamedType:
                            Debug.Assert((object)declaredSymbol.GetSymbol() == (object)entryPoint.ContainingSymbol);
                            return (node) => false;
 
                        default:
                            ExceptionUtilities.UnexpectedValue(declaredSymbol.Kind);
                            break;
                    }
                    break;
 
                case TypeDeclarationSyntax typeDeclaration when TryGetSynthesizedPrimaryConstructor(typeDeclaration) is SynthesizedPrimaryConstructor ctor:
                    if (typeDeclaration.Kind() is (SyntaxKind.RecordDeclaration or SyntaxKind.ClassDeclaration))
                    {
                        switch (declaredSymbol.Kind)
                        {
                            case SymbolKind.Method:
                                Debug.Assert((object)declaredSymbol.GetSymbol() == (object)ctor);
                                return (node) =>
                                       {
                                           // Accept only nodes that either match, or above/below of a 'parameter list'/'base arguments list'.
                                           if (node.Parent == typeDeclaration)
                                           {
                                               return node == typeDeclaration.ParameterList || node == typeDeclaration.BaseList;
                                           }
                                           else if (node.Parent is BaseListSyntax baseList)
                                           {
                                               return node == typeDeclaration.PrimaryConstructorBaseTypeIfClass;
                                           }
                                           else if (node.Parent is PrimaryConstructorBaseTypeSyntax baseType && baseType == typeDeclaration.PrimaryConstructorBaseTypeIfClass)
                                           {
                                               return node == baseType.ArgumentList;
                                           }
 
                                           return true;
                                       };
 
                            case SymbolKind.NamedType:
                                Debug.Assert((object)declaredSymbol.GetSymbol() == (object)ctor.ContainingSymbol);
                                // Accept nodes that do not match a 'parameter list'/'base arguments list'.
                                return (node) => node != typeDeclaration.ParameterList &&
                                                 !(node.Kind() == SyntaxKind.ArgumentList && node == typeDeclaration.PrimaryConstructorBaseTypeIfClass?.ArgumentList);
 
                            default:
                                ExceptionUtilities.UnexpectedValue(declaredSymbol.Kind);
                                break;
                        }
                    }
                    else
                    {
                        switch (declaredSymbol.Kind)
                        {
                            case SymbolKind.Method:
                                Debug.Assert((object)declaredSymbol.GetSymbol() == (object)ctor);
                                return (node) =>
                                {
                                    // Accept only nodes that either match, or above/below of a 'parameter list'.
                                    if (node.Parent == typeDeclaration)
                                    {
                                        return node == typeDeclaration.ParameterList;
                                    }
 
                                    return true;
                                };
 
                            case SymbolKind.NamedType:
                                Debug.Assert((object)declaredSymbol.GetSymbol() == (object)ctor.ContainingSymbol);
                                // Accept nodes that do not match a 'parameter list'.
                                return (node) => node != typeDeclaration.ParameterList;
 
                            default:
                                ExceptionUtilities.UnexpectedValue(declaredSymbol.Kind);
                                break;
                        }
                    }
                    break;
 
                case PrimaryConstructorBaseTypeSyntax { Parent: BaseListSyntax { Parent: TypeDeclarationSyntax typeDeclaration } } baseType
                        when typeDeclaration.PrimaryConstructorBaseTypeIfClass == declaredNode && TryGetSynthesizedPrimaryConstructor(typeDeclaration) is SynthesizedPrimaryConstructor ctor:
                    if ((object)declaredSymbol.GetSymbol() == (object)ctor)
                    {
                        // Only 'base arguments list' or nodes below it
                        return (node) => node != baseType.Type;
                    }
                    break;
 
                case ParameterSyntax param when declaredSymbol.Kind == SymbolKind.Property && param.Parent?.Parent is RecordDeclarationSyntax recordDeclaration && recordDeclaration.ParameterList == param.Parent:
                    Debug.Assert(declaredSymbol.GetSymbol() is SynthesizedRecordPropertySymbol);
                    return (node) => false;
            }
 
            return null;
        }
 
        internal override bool ShouldSkipSyntaxNodeAnalysis(SyntaxNode node, ISymbol containingSymbol)
        {
            switch (containingSymbol.Kind)
            {
                case SymbolKind.Method:
                    switch (node)
                    {
                        case TypeDeclarationSyntax:
                            // Skip the topmost type declaration syntax node when analyzing primary constructor
                            // to avoid duplicate syntax node callbacks.
                            // We will analyze this node when analyzing the type declaration type symbol.
                            return true;
 
                        case CompilationUnitSyntax:
                            // Skip compilation unit syntax node when analyzing synthesized top level entry point method
                            // to avoid duplicate syntax node callbacks.
                            // We will analyze this node when analyzing the global namespace symbol.
                            return true;
 
                        case BaseListSyntax:
                            // Skip the base list syntax node when analyzing primary constructor
                            // to avoid duplicate syntax node callbacks.
                            // We will analyze this node when analyzing the type declaration type symbol.
                            return true;
                    }
 
                    break;
 
                case SymbolKind.NamedType:
                    if (node is PrimaryConstructorBaseTypeSyntax)
                    {
                        // Skip the PrimaryConstructorBaseTypeSyntax when analyzing type declaration symbol
                        // to avoid duplicate syntax node callbacks.
                        // We will analyze this node when analyzing the primary constructor symbol.
                        return true;
                    }
 
                    break;
            }
 
            return false;
        }
    }
}