예제 #1
0
        // We have a lambda; we want to find a syntax node or statement which can be bound such that
        // we can get the type of the lambda, if there is one. For example if given
        //
        // A().B(x=>M(x)).C();  then we want to find  A().B(x=>M())
        // object d = (D)(x=>M(x)); then we want to find (D)(x=>M(x))
        // D d = x=>M(x); then we want to find the whole thing.
        //
        protected virtual SyntaxNode GetBindableSyntaxNodeOfLambdaOrQuery(SyntaxNode node)
        {
            Debug.Assert(node != null);
            Debug.Assert(node != this.Root);
            Debug.Assert(node.IsAnonymousFunction() || node.IsQuery());

            SyntaxNode current = node.Parent;

            for (; current != this.Root; current = current.Parent)
            {
                Debug.Assert(current != null, "How did we get outside the root?");

                if (current is StatementSyntax)
                {
                    return(current);
                }

                if (current.Kind == SyntaxKind.ParenthesizedExpression)
                {
                    continue;
                }

                if (current is ExpressionSyntax)
                {
                    return(GetBindableSyntaxNode(current));
                }
            }

            // We made it up to the root without finding a viable expression or statement. Just bind
            // the lambda and hope for the best.
            return(node);
        }
예제 #2
0
        /// <summary>
        /// Performs the same function as GetEnclosingBinder, but is known to take place within a
        /// specified lambda.  Walks up the syntax hierarchy until a node with an associated binder
        /// is found.
        /// </summary>
        /// <remarks>
        /// CONSIDER: can this share code with MemberSemanticModel.GetEnclosingBinder?
        /// </remarks>
        private Binder GetLambdaEnclosingBinder(int position, SyntaxNode startingNode, SyntaxNode containingLambda, ExecutableCodeBinder lambdaBinder)
        {
            AssertPositionAdjusted(position);
            Debug.Assert(containingLambda.IsAnonymousFunction());
            Debug.Assert(LookupPosition.IsInAnonymousFunctionOrQuery(position, containingLambda));

            var current = startingNode;

            while (current != containingLambda)
            {
                Debug.Assert(current != null);

                StatementSyntax stmt = current as StatementSyntax;
                if (stmt != null)
                {
                    if (LookupPosition.IsInStatementScope(position, stmt))
                    {
                        Binder binder = lambdaBinder.GetBinder(current);
                        if (binder != null)
                        {
                            return(binder);
                        }
                    }
                }
                else if (current.Kind == SyntaxKind.CatchClause)
                {
                    if (LookupPosition.IsInCatchClauseScope(position, (CatchClauseSyntax)current))
                    {
                        Binder binder = lambdaBinder.GetBinder(current);
                        if (binder != null)
                        {
                            return(binder);
                        }
                    }
                }
                else if (current.IsAnonymousFunction())
                {
                    if (LookupPosition.IsInAnonymousFunctionOrQuery(position, current))
                    {
                        Binder binder = lambdaBinder.GetBinder(current);
                        if (binder != null)
                        {
                            return(binder);
                        }
                    }
                }
                else
                {
                    // If this ever breaks, make sure that all callers of
                    // CanHaveAssociatedLocalBinder are in sync.
                    Debug.Assert(!current.CanHaveAssociatedLocalBinder());
                }

                current = current.Parent;
            }

            return(lambdaBinder);
        }
예제 #3
0
        private static bool NodeIsExplicitType(SyntaxNode node, SyntaxNode lambda)
        {
            Debug.Assert(node != null);
            Debug.Assert(lambda != null);
            Debug.Assert(lambda.IsAnonymousFunction() || lambda.IsQuery());

            // UNDONE;
            return(false);
        }
예제 #4
0
        internal override BoundNode GetBoundNode(SyntaxNode node)
        {
            // If this method is called with a null parameter, that implies that the Root should be
            // bound, but make sure that the Root is bindable.
            if (node == null)
            {
                node = GetBindableSyntaxNode(Root);
            }

            Debug.Assert(node == GetBindableSyntaxNode(node));

            // We have one SemanticModel for each method.
            //
            // The SemanticModel contains a lazily-built immutable map from scope-introducing
            // syntactic statements (such as blocks) to binders, but not from lambdas to binders.
            //
            // The SemanticModel also contains a mutable map from syntax to bound nodes; that is
            // declared here. Since the map is not thread-safe we ensure that it is guarded with a
            // reader-writer lock.
            //
            // Have we already got the desired bound node in the mutable map? If so, return it.
            BoundNode result = GetBoundNodeFromMap(node);

            if (result != null)
            {
                return(result);
            }

            // We didn't have it in the map. Obtain a binder suitable for obtaining the answer.
            Binder binder = GetEnclosingBinder(GetAdjustedNodePosition(node));

            Debug.Assert(binder != null);

            // If the binder we just obtained is for a child lambda then by obtaining the binder we
            // might have as a side effect caused the map to be populated with the answer we seek.
            // Check again.
            result = GetBoundNodeFromMap(node);
            if (result != null)
            {
                return(result);
            }

            // We might not actually have been given an expression or statement even though we were
            // allegedly given something that is "bindable".
            SyntaxNode nodeToBind = GetExpressionOrStatement(node);

            // We are in one of the scenarios where binding the lambda does not populate the map
            // with the desired node. Bind the node in the binder, and then add to the map every
            // syntax/bound node pair in the resulting bound node and its children.
            //
            // It is possible that we're being asked to bind an entire outermost lambda. For example:
            //
            // void M() { Func<int, int> f = x=>x+1; }
            //                     bind this ^----^
            //
            // In that case the enclosing binder is the body binder for M, but we do not simply want
            // to bind the expression "x=>x+1". Rather, we want to bind the whole statement
            // enclosing it, so that we have the right type for x.

            if (nodeToBind.IsAnonymousFunction() && GetInnermostLambdaOrQuery(nodeToBind, node.Span.Start) == null)
            {
                nodeToBind = GetBindableSyntaxNodeOfLambdaOrQuery(nodeToBind);
            }

            BoundNode boundRoot = this.Bind(binder, nodeToBind, this.diagnostics);

            Debug.Assert(boundRoot != null);
            result = AddBoundTreeAndGetBoundNodeFromMap(node, boundRoot);

            // Special case:
            //
            // We might be in a "Color Color" scenario. That is, suppose we have been asked to bind
            // "Color" in "x = Color.Red;" or in "x = Color.ToString();"  The former could be the
            // type "Color" and the latter could be the property "this.Color" or a local variable
            // named Color of type Color.
            //
            // We've just bound "Color"; perhaps it resolved to be the property. Now bind
            // "Color.Red" and re-do the mapping. That might replace the node in the map with the
            // right value, or it might leave it the same, or it might leave it untouched, if the
            // original syntax node does not appear in the new bound tree. Either way, we'll have
            // more accurate information in the tree for this case.
            if (node != this.Root &&
                node.Parent != null &&
                node.Parent.Kind == SyntaxKind.MemberAccessExpression &&
                node.Kind == SyntaxKind.IdentifierName)
            {
                var memberAccess = (MemberAccessExpressionSyntax)node.Parent;
                if (memberAccess.Name.Kind == SyntaxKind.IdentifierName)
                {
                    BoundNode boundMemberAccess = this.Bind(binder, memberAccess, this.diagnostics);
                    result = AddBoundTreeAndGetBoundNodeFromMap(node, boundMemberAccess);
                }
            }

            // It is *still* possible that we haven't gotten the result. For example, consider
            // something like "int x = (a + b) * c;"  If we ask for binding information on the
            // parenthetical expression then we'll get back a bound node for the syntax "a + b", not
            // the syntax "(a + b)"; the binder generates no bound state for the parenthetical. The
            // best we can do in this bad situation is to use the expression we just bound.  Add it
            // to the map in case we're asked again.
            if (result == null)
            {
                AddBoundNodeToMap(node, boundRoot);
                result = boundRoot;
            }

            Debug.Assert(result != null);
            return(result);
        }