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