/// <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); }
/// <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); }
// 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); }