Ejemplo n.º 1
0
        /// <summary>
        /// Finds a token according to the following rules:
        /// 1) If position matches the End of the node/s FullSpan and the node is CompilationUnit,
        ///    then EoF is returned.
        ///
        ///  2) If node.FullSpan.Contains(position) then the token that contains given position is
        ///     returned.
        ///
        ///  3) Otherwise an ArgumentOutOfRangeException is thrown
        /// </summary>
        internal SyntaxToken FindTokenIncludingCrefAndNameAttributes(int position)
        {
            SyntaxToken nonTriviaToken = this.FindToken(position, findInsideTrivia: false);

            SyntaxTrivia trivia = GetTriviaFromSyntaxToken(position, nonTriviaToken);

            if (!SyntaxFacts.IsDocumentationCommentTrivia(trivia.Kind()))
            {
                return(nonTriviaToken);
            }

            Debug.Assert(trivia.HasStructure);
            SyntaxToken triviaToken = ((CSharpSyntaxNode)trivia.GetStructure()).FindTokenInternal(position);

            // CONSIDER: We might want to use the trivia token anywhere within a doc comment.
            // Otherwise, we'll fall back on the enclosing scope outside of name and cref
            // attribute values.
            CSharpSyntaxNode curr = (CSharpSyntaxNode)triviaToken.Parent;

            while (curr != null)
            {
                // Don't return a trivia token unless we're in the scope of a cref or name attribute.
                if (curr.Kind() == SyntaxKind.XmlCrefAttribute || curr.Kind() == SyntaxKind.XmlNameAttribute)
                {
                    return(LookupPosition.IsInXmlAttributeValue(position, (XmlAttributeSyntax)curr)
                        ? triviaToken
                        : nonTriviaToken);
                }

                curr = curr.Parent;
            }

            return(nonTriviaToken);
        }
Ejemplo n.º 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);
        }
Ejemplo n.º 3
0
        // In lambda binding scenarios we need to know two things: First,
        // what is the *innermost* lambda that contains the expression we're
        // interested in?  Second, what is the smallest expression that contains
        // the *outermost* lambda that we can bind in order to get a sensible
        // lambda binding?
        //
        // For example, suppose we have the statement:
        //
        // A().B(x=>x.C(y=>y.D().E())).F().G();
        //
        // and the user wants binding information about method group "D".  We must know
        // the bindable expression that is outside of every lambda:
        //
        // A().B(x=>x.C(y=>y.D().E()))
        //
        // By binding that we can determine the type of lambda parameters "x" and "y" and
        // put that information in the bound tree. Once we know those facts then
        // we can obtain the binding object associated with the innermost lambda:
        //
        // y=>y.D().E()
        //
        // And use that binding to obtain the analysis of:
        //
        // y.D
        //
        private SyntaxNode GetInnermostLambdaOrQuery(SyntaxNode node, int position, bool allowStarting = false)
        {
            Debug.Assert(node != null);

            for (var current = node; current != this.Root; current = current.Parent)
            {
                // current can only become null if we somehow got past the root. The only way we
                // could have gotten past the root is to have started outside of it. That's
                // unexpected; the binding should only be asked to provide an opinion on syntax
                // nodes that it knows about.
                Debug.Assert(current != null, "Why are we being asked to find an enclosing lambda outside of our root?");

                if (!(current.IsAnonymousFunction() || current.IsQuery()))
                {
                    continue;
                }

                // If the position is not actually within the scope of the lambda, then keep
                // looking.
                if (!LookupPosition.IsInAnonymousFunctionOrQuery(position, current))
                {
                    continue;
                }

                // If we were asked for the innermost lambda enclosing a lambda then don't return
                // that; it's not enclosing anything. Only return the lambda if it's enclosing the
                // original node.

                if (!allowStarting && current == node)
                {
                    continue;
                }

                // If the lambda that is "enclosing" us is in fact enclosing an explicit lambda
                // parameter type then keep on going; that guy is logically bound outside of the
                // lambda. For example, if we have:
                //
                // D d = (Foo f)=>{int Foo; };
                //
                // Then the type "Foo" is bound in the context outside the lambda body, not inside
                // where it might get confused with local "Foo".
                if (NodeIsExplicitType(node, current))
                {
                    continue;
                }

                return(current);
            }

            // If we made it to the root, then we are not "inside" a lambda even if the root is a
            // lambda. Remember, the point of this code is to get the binding that is associated
            // with the innermost lambda; if we are already in a binding associated with the
            // innermost lambda then we're done.
            return(null);
        }