private void ComputeBinderMap()
        {
            SmallDictionary <SyntaxNode, Binder> map;
            ImmutableArray <MethodSymbol>        methodSymbolsWithYield;

            // Ensure that the member symbol is a method symbol.
            if ((object)_memberSymbol != null && _root != null)
            {
                var methodsWithYield = ArrayBuilder <SyntaxNode> .GetInstance();

                var symbolsWithYield = ArrayBuilder <MethodSymbol> .GetInstance();

                map = LocalBinderFactory.BuildMap(_memberSymbol, _root, this, methodsWithYield, _binderUpdatedHandler);
                foreach (var methodWithYield in methodsWithYield)
                {
                    Binder binder = this;
                    if (methodWithYield.Kind() != SyntaxKind.GlobalStatement &&
                        (methodWithYield == _root || map.TryGetValue(methodWithYield, out binder)))
                    {
                        Symbol containing = binder.ContainingMemberOrLambda;

                        // get the closest enclosing InMethodBinder and make it an iterator
                        InMethodBinder inMethod = null;
                        while (binder != null)
                        {
                            inMethod = binder as InMethodBinder;
                            if (inMethod != null)
                            {
                                break;
                            }
                            binder = binder.Next;
                        }
                        if (inMethod != null && (object)inMethod.ContainingMemberOrLambda == containing)
                        {
                            inMethod.MakeIterator();
                            symbolsWithYield.Add((MethodSymbol)inMethod.ContainingMemberOrLambda);
                        }
                        else
                        {
                            Debug.Assert(methodWithYield == _root && methodWithYield is ExpressionSyntax);
                        }
                    }
                    else
                    {
                        // skip over it, this is an error
                    }
                }
                methodsWithYield.Free();
                methodSymbolsWithYield = symbolsWithYield.ToImmutableAndFree();
            }
            else
            {
                map = SmallDictionary <SyntaxNode, Binder> .Empty;
                methodSymbolsWithYield = ImmutableArray <MethodSymbol> .Empty;
            }

            Interlocked.CompareExchange(ref _lazyBinderMap, map, null);
            ImmutableInterlocked.InterlockedCompareExchange(ref _methodSymbolsWithYield, methodSymbolsWithYield, default(ImmutableArray <MethodSymbol>));
        }
Beispiel #2
0
        // methodsWithYields will contain all function-declaration-like CSharpSyntaxNodes with yield statements contained within them.
        // Currently the types of these are restricted to only be whatever the syntax parameter is, plus any LocalFunctionStatementSyntax contained within it.
        // This may change if the language is extended to allow iterator lambdas, in which case the lambda would also be returned.
        // (lambdas currently throw a diagnostic in WithLambdaParametersBinder.GetIteratorElementType when a yield is used within them)
        public static SmallDictionary <SyntaxNode, Binder> BuildMap(
            Symbol containingMemberOrLambda,
            SyntaxNode syntax,
            Binder enclosing,
            ArrayBuilder <SyntaxNode> methodsWithYields,
            Action <Binder, SyntaxNode> binderUpdatedHandler = null)
        {
            var builder = new LocalBinderFactory(containingMemberOrLambda, syntax, enclosing, methodsWithYields);

            StatementSyntax statement;
            var             expressionSyntax = syntax as ExpressionSyntax;

            if (expressionSyntax != null)
            {
                enclosing = new ExpressionVariableBinder(syntax, enclosing);

                if ((object)binderUpdatedHandler != null)
                {
                    binderUpdatedHandler(enclosing, syntax);
                }

                builder.AddToMap(syntax, enclosing);
                builder.Visit(expressionSyntax, enclosing);
            }
            else if (syntax.Kind() != SyntaxKind.Block && (statement = syntax as StatementSyntax) != null)
            {
                CSharpSyntaxNode embeddedScopeDesignator;
                enclosing = builder.GetBinderForPossibleEmbeddedStatement(statement, enclosing, out embeddedScopeDesignator);

                if ((object)binderUpdatedHandler != null)
                {
                    binderUpdatedHandler(enclosing, embeddedScopeDesignator);
                }

                if (embeddedScopeDesignator != null)
                {
                    builder.AddToMap(embeddedScopeDesignator, enclosing);
                }

                builder.Visit(statement, enclosing);
            }
            else
            {
                if ((object)binderUpdatedHandler != null)
                {
                    binderUpdatedHandler(enclosing, null);
                }

                builder.Visit((CSharpSyntaxNode)syntax, enclosing);
            }

            // the other place this is possible is in a local function
            if (builder._sawYield)
            {
                methodsWithYields.Add(syntax);
            }
            return(builder._map);
        }