/// <summary>
        /// This overload exists for callers who
        ///   a) Already have a node in hand and don't want to search through the tree
        ///   b) May want to search from an indirect container (e.g. node containing node
        ///      containing position).
        /// </summary>
        private Binder GetEnclosingBinder(CSharpSyntaxNode node, int position)
        {
            AssertPositionAdjusted(position);

            if (node == this.root)
            {
                return RootBinder;
            }

            ExpressionSyntax typeOfArgument = null;
            CSharpSyntaxNode unexpectedAnonymousFunction = null;

            // Keep track of which fix-up should be applied first.  If we see a typeof expression inside an unexpected
            // anonymous function, that the typeof binder should be innermost (i.e. should have the unexpected
            // anonymous function binder as its Next).
            // NOTE: only meaningful if typeOfArgument is non-null;
            bool typeOfEncounteredBeforeUnexpectedAnonymousFunction = false;

            Binder binder = null;
            for (var current = node; binder == null; current = current.ParentOrStructuredTriviaParent)
            {
                Debug.Assert(current != null); // Why were we asked for an enclosing binder for a node outside our root?

                StatementSyntax stmt = current as StatementSyntax;
                if (stmt != null)
                {
                    if (LookupPosition.IsInStatementScope(position, stmt))
                    {
                        binder = RootBinder.GetBinder(current);

                        if (binder != null)
                        {
                            binder = AdjustBinderForPositionWithinStatement(position, binder, stmt);
                        }
                    }
                }
                else if (current.Kind == SyntaxKind.CatchClause)
                {
                    if (LookupPosition.IsInCatchBlockScope(position, (CatchClauseSyntax)current))
                    {
                        binder = RootBinder.GetBinder(current);
                    }
                }
                else if (current.Kind == SyntaxKind.CatchFilterClause)
                {
                    if (LookupPosition.IsInCatchFilterScope(position, (CatchFilterClauseSyntax)current))
                    {
                        binder = RootBinder.GetBinder(current);
                    }
                }
                else if (current.IsAnonymousFunction())
                {
                    if (LookupPosition.IsInAnonymousFunctionOrQuery(position, current))
                    {
                        binder = RootBinder.GetBinder(current);

                        // This should only happen in error scenarios.  For example, C# does not allow array rank
                        // specifiers in types, (e.g. int[1] x;), but the syntax model does.  In order to construct
                        // an appropriate binder chain for the anonymous method body, we need to construct an
                        // ExecutableCodeBinder.
                        if (binder == null && unexpectedAnonymousFunction == null)
                        {
                            unexpectedAnonymousFunction = current;
                        }
                    }
                }
                else if (current.Kind == SyntaxKind.TypeOfExpression && typeOfArgument == null)
                {
                    typeOfArgument = ((TypeOfExpressionSyntax)current).Type;
                    typeOfEncounteredBeforeUnexpectedAnonymousFunction = unexpectedAnonymousFunction == null;
                }
                else
                {
                    // If this ever breaks, make sure that all callers of
                    // CanHaveAssociatedLocalBinder are in sync.
                    Debug.Assert(!current.CanHaveAssociatedLocalBinder());
                }

                if (current == this.root)
                {
                    break;
                }
            }

            binder = binder ?? RootBinder;
            Debug.Assert(binder != null);

            if (typeOfArgument != null && !typeOfEncounteredBeforeUnexpectedAnonymousFunction)
            {
                binder = new TypeofBinder(typeOfArgument, binder);
            }

            if (unexpectedAnonymousFunction != null)
            {
                binder = new ExecutableCodeBinder(unexpectedAnonymousFunction, ErrorMethodSymbol.UnknownMethod, binder);
            }

            if (typeOfArgument != null && typeOfEncounteredBeforeUnexpectedAnonymousFunction)
            {
                binder = new TypeofBinder(typeOfArgument, binder);
            }

            return binder.WithAdditionalFlags(BinderFlags.SemanticModel);
        }
        private static Binder GetEnclosingBinder(SyntaxNode node, int position, Binder rootBinder, SyntaxNode root)
        {
            if (node == root)
            {
                return rootBinder.GetBinder(node) ?? rootBinder;
            }

            Debug.Assert(root.Contains(node));

            ExpressionSyntax typeOfArgument = null;
            SyntaxNode unexpectedAnonymousFunction = null;

            // Keep track of which fix-up should be applied first.  If we see a typeof expression inside an unexpected
            // anonymous function, that the typeof binder should be innermost (i.e. should have the unexpected
            // anonymous function binder as its Next).
            // NOTE: only meaningful if typeOfArgument is non-null;
            bool typeOfEncounteredBeforeUnexpectedAnonymousFunction = false;

            Binder binder = null;
            for (var current = node; binder == null; current = current.ParentOrStructuredTriviaParent)
            {
                Debug.Assert(current != null); // Why were we asked for an enclosing binder for a node outside our root?
                StatementSyntax stmt = current as StatementSyntax;
                TypeOfExpressionSyntax typeOfExpression;
                if (stmt != null)
                {
                    if (LookupPosition.IsInStatementScope(position, stmt))
                    {
                        binder = rootBinder.GetBinder(current);

                        if (binder != null)
                        {
                            binder = AdjustBinderForPositionWithinStatement(position, binder, stmt);
                        }
                    }
                }
                else if (current.Kind() == SyntaxKind.CatchClause)
                {
                    if (LookupPosition.IsInCatchBlockScope(position, (CatchClauseSyntax)current))
                    {
                        binder = rootBinder.GetBinder(current);
                    }
                }
                else if (current.Kind() == SyntaxKind.CatchFilterClause)
                {
                    if (LookupPosition.IsInCatchFilterScope(position, (CatchFilterClauseSyntax)current))
                    {
                        binder = rootBinder.GetBinder(current);
                    }
                }
                else if (current.IsAnonymousFunction())
                {
                    if (LookupPosition.IsInAnonymousFunctionOrQuery(position, current))
                    {
                        binder = rootBinder.GetBinder(current);

                        // This should only happen in error scenarios.  For example, C# does not allow array rank
                        // specifiers in types, (e.g. int[1] x;), but the syntax model does.  In order to construct
                        // an appropriate binder chain for the anonymous method body, we need to construct an
                        // ExecutableCodeBinder.
                        if (binder == null && unexpectedAnonymousFunction == null && current != root)
                        {
                            unexpectedAnonymousFunction = current;
                        }
                    }
                }
                else if (current.Kind() == SyntaxKind.TypeOfExpression &&
                    typeOfArgument == null &&
                    LookupPosition.IsBetweenTokens(
                        position,
                        (typeOfExpression = (TypeOfExpressionSyntax)current).OpenParenToken,
                        typeOfExpression.CloseParenToken))
                {
                    typeOfArgument = typeOfExpression.Type;
                    typeOfEncounteredBeforeUnexpectedAnonymousFunction = unexpectedAnonymousFunction == null;
                }
                else if (current.Kind() == SyntaxKind.SwitchSection)
                {
                    if (LookupPosition.IsInSwitchSectionScope(position, (SwitchSectionSyntax)current))
                    {
                        binder = rootBinder.GetBinder(current);
                    }
                }
                else if (current.Kind() == SyntaxKind.ArgumentList)
                {
                    var argList = (ArgumentListSyntax)current;

                    if (LookupPosition.IsBetweenTokens(position, argList.OpenParenToken, argList.CloseParenToken))
                    {
                        binder = rootBinder.GetBinder(current);
                    }
                }
                else if (current.Kind() == SyntaxKind.EqualsValueClause)
                {
                    binder = rootBinder.GetBinder(current);
                }
                else if (current.Kind() == SyntaxKind.Attribute)
                {
                    binder = rootBinder.GetBinder(current);
                }
                else if (current.Kind() == SyntaxKind.ArrowExpressionClause)
                {
                    binder = rootBinder.GetBinder(current);
                }
                else if (current is ExpressionSyntax && 
                            ((current.Parent as LambdaExpressionSyntax)?.Body == current ||
                             (current.Parent as SwitchStatementSyntax)?.Expression == current ||
                             (current.Parent as CommonForEachStatementSyntax)?.Expression == current))
                {
                    binder = rootBinder.GetBinder(current);
                }
                else if (current is VariableComponentSyntax &&
                             (current.Parent as ForEachComponentStatementSyntax)?.VariableComponent == current)
                {
                    binder = rootBinder.GetBinder(current.Parent);
                }
                else if (current is VariableComponentSyntax &&
                             (current.Parent is VariableComponentAssignmentSyntax) &&
                             (current.Parent.Parent as ForStatementSyntax)?.Deconstruction == current)
                {
                    binder = rootBinder.GetBinder(current.Parent.Parent);
                }
                else if (current is VariableComponentSyntax &&
                             (current.Parent is VariableComponentAssignmentSyntax) &&
                             (current.Parent.Parent as DeconstructionDeclarationStatementSyntax)?.Assignment.VariableComponent == current)
                {
                    binder = rootBinder.GetBinder(current.Parent.Parent);
                }
                else
                {
                    // If this ever breaks, make sure that all callers of
                    // CanHaveAssociatedLocalBinder are in sync.
                    Debug.Assert(!current.CanHaveAssociatedLocalBinder());
                }

                if (current == root)
                {
                    break;
                }
            }

            binder = binder ?? rootBinder.GetBinder(root) ?? rootBinder;
            Debug.Assert(binder != null);

            if (typeOfArgument != null && !typeOfEncounteredBeforeUnexpectedAnonymousFunction)
            {
                binder = new TypeofBinder(typeOfArgument, binder);
            }

            if (unexpectedAnonymousFunction != null)
            {
                binder = new ExecutableCodeBinder(unexpectedAnonymousFunction,
                                                  new LambdaSymbol(binder.ContainingMemberOrLambda,
                                                                   ImmutableArray<ParameterSymbol>.Empty,
                                                                   RefKind.None,
                                                                   ErrorTypeSymbol.UnknownResultType,
                                                                   unexpectedAnonymousFunction.Kind() == SyntaxKind.AnonymousMethodExpression ? MessageID.IDS_AnonMethod : MessageID.IDS_Lambda,
                                                                   unexpectedAnonymousFunction,
                                                                   isSynthesized: false),
                                                  binder);
            }

            if (typeOfArgument != null && typeOfEncounteredBeforeUnexpectedAnonymousFunction)
            {
                binder = new TypeofBinder(typeOfArgument, binder);
            }

            return binder;
        }
Beispiel #3
0
        internal Binder GetSpeculativeBinder(int position, ExpressionSyntax expression, SpeculativeBindingOption bindingOption)
        {
            Debug.Assert(expression != null);

            position = CheckAndAdjustPosition(position);

            if (bindingOption == SpeculativeBindingOption.BindAsTypeOrNamespace)
            {
                if (!(expression is TypeSyntax))
                {
                    return null;
                }
            }

            Binder binder = this.GetEnclosingBinder(position);
            if (binder == null)
            {
                return null;
            }

            if (bindingOption == SpeculativeBindingOption.BindAsTypeOrNamespace && IsInTypeofExpression(position))
            {
                // If position is within a typeof expression, GetEnclosingBinder may return a
                // TypeofBinder.  However, this TypeofBinder will have been constructed with the
                // actual syntax of the typeof argument and we want to use the given syntax.
                // Wrap the binder in another TypeofBinder to overrule its description of where
                // unbound generic types are allowed.
                //Debug.Assert(binder is TypeofBinder); // Expectation, not requirement.
                binder = new TypeofBinder(expression, binder);
            }

            // May be binding an expression in a context that doesn't have a LocalScopeBinder in the chain.
            return new LocalScopeBinder(binder);
        }