// Create a member model for the given declaration syntax. In certain very malformed
        // syntax trees, there may not be a symbol that can have a member model associated with it
        // (although we try to minimize such cases). In such cases, null is returned.
        private MemberSemanticModel CreateMemberModel(CSharpSyntaxNode node)
        {
            var outer = this.binderFactory.GetBinder(node);
            switch (node.Kind)
            {
                case SyntaxKind.Block:
                    if (node.Parent != null && node.Parent.Kind == SyntaxKind.PrimaryConstructorBody)
                    {
                        if (node.Parent.Parent != null && (node.Parent.Parent.Kind == SyntaxKind.ClassDeclaration || node.Parent.Parent.Kind == SyntaxKind.StructDeclaration))
                        {
                            var typeDecl = (TypeDeclarationSyntax)node.Parent.Parent;
                            var constructorSymbol = (SourceMethodSymbol)GetDeclaredConstructorSymbol(typeDecl);

                            if ((object)constructorSymbol == null)
                                return null;

                            // We need to share locals declared in constructor initializer with 
                            // constructor initializer member model. We want both models to use the same symbols for the locals.
                            var localsDeclaredInInitializer = ImmutableArray<LocalSymbol>.Empty;

                            if (typeDecl.Kind == SyntaxKind.ClassDeclaration)
                            {
                                var classDecl = (ClassDeclarationSyntax)typeDecl;

                                if (classDecl.BaseList != null && classDecl.BaseList.Types.Count > 0 && classDecl.BaseList.Types[0].Kind == SyntaxKind.BaseClassWithArguments)
                                {
                                    ArgumentListSyntax argList = ((BaseClassWithArgumentsSyntax)classDecl.BaseList.Types[0]).ArgumentList;
                                    MemberSemanticModel initializerModel = GetOrAddModel(argList);

                                    if (initializerModel != null)
                                    {
                                        localsDeclaredInInitializer = initializerModel.RootBinder.GetDeclaredLocalsForScope(argList);
                                    }
                                }
                            }

                            // Locals declared in instance initializers within the current partial class declaration
                            // should be in scope within the body.
                            outer = AddInitializersLocalsScope(outer, typeDecl, constructorSymbol);

                            if (!localsDeclaredInInitializer.IsDefaultOrEmpty)
                            {
                                outer = new SimpleLocalScopeBinder(localsDeclaredInInitializer, outer);
                            }

                            return MethodBodySemanticModel.Create(this.Compilation, constructorSymbol, outer, node);
                        }

                        return null;
                    }
                    else
                    {
                        MemberDeclarationSyntax memberDecl;
                        AccessorDeclarationSyntax accessorDecl;
                        if ((memberDecl = node.Parent as MemberDeclarationSyntax) != null)
                        {
                            var symbol = (SourceMethodSymbol)GetDeclaredSymbol(memberDecl);
                            if ((object)symbol == null)
                                return null;

                            // In case of constructor, we need to share locals declared in constructor initializer with 
                            // constructor initializer member model. We want both models to use the same symbols for the locals.
                            if (node.Parent.Kind == SyntaxKind.ConstructorDeclaration && !symbol.IsStatic)
                            {
                                var decl = (ConstructorDeclarationSyntax)node.Parent;
                                if (decl.Initializer != null)
                                {
                                    MemberSemanticModel initializerModel = GetOrAddModel(decl.Initializer);
                                    if (initializerModel != null)
                                    {
                                        var localsDeclaredInInitializer = initializerModel.RootBinder.GetDeclaredLocalsForScope(decl);
                                        if (!localsDeclaredInInitializer.IsDefaultOrEmpty)
                                        {
                                            outer = new SimpleLocalScopeBinder(localsDeclaredInInitializer, outer);
                                        }
                                    }
                                }
                            }

                            return MethodBodySemanticModel.Create(this.Compilation, symbol, outer, memberDecl);
                        }
                        else if ((accessorDecl = node.Parent as AccessorDeclarationSyntax) != null)
                        {
                            var symbol = (SourceMethodSymbol)GetDeclaredSymbol(accessorDecl);
                            if ((object)symbol == null)
                                return null;

                            return MethodBodySemanticModel.Create(this.Compilation, symbol, outer, accessorDecl);
                        }
                        else
                        {
                            Debug.Assert(false, "Unexpected node: " + node.Parent);
                            return null;
                        }
                    }

                case SyntaxKind.EqualsValueClause:
                    switch (node.Parent.Kind)
                    {
                        case SyntaxKind.VariableDeclarator:
                            {
                                var variableDecl = (VariableDeclaratorSyntax)node.Parent;
                                SourceMemberFieldSymbol fieldSymbol = GetDeclaredFieldSymbol(variableDecl);

                                return InitializerSemanticModel.Create(
                                    this.Compilation,
                                    variableDecl,   //pass in the entire field initializer to permit region analysis. 
                                    fieldSymbol,
                                    //if we're in regular C#, then insert an extra binder to perform field initialization checks
                                    GetFieldOrPropertyInitializerBinder(fieldSymbol, outer));
                            }

                        case SyntaxKind.PropertyDeclaration:
                            {
                                var propertyDecl = (PropertyDeclarationSyntax)node.Parent;
                                var propertySymbol = (SourcePropertySymbol)GetDeclaredSymbol(propertyDecl);
                                return InitializerSemanticModel.Create(
                                    this.Compilation,
                                    propertyDecl,
                                    propertySymbol,
                                    GetFieldOrPropertyInitializerBinder(propertySymbol.BackingField, outer));
                            }

                        case SyntaxKind.Parameter:
                            {
                                // NOTE: we don't need to create a member model for lambda parameter default value
                                // (which is bad code anyway) because lambdas only appear in code with associated
                                // member models.
                                ParameterSyntax parameterDecl = (ParameterSyntax)node.Parent;
                                ParameterSymbol parameterSymbol = GetDeclaredNonLambdaParameterSymbol(parameterDecl);
                                if ((object)parameterSymbol == null)
                                    return null;

                                return InitializerSemanticModel.Create(
                                    this.Compilation,
                                    parameterDecl,
                                    parameterSymbol,
                                    outer.CreateBinderForParameterDefaultValue(parameterSymbol, (EqualsValueClauseSyntax)node));
                            }

                        case SyntaxKind.EnumMemberDeclaration:
                            {
                                var enumDecl = (EnumMemberDeclarationSyntax)node.Parent;
                                var enumSymbol = (FieldSymbol)GetDeclaredSymbol(enumDecl);
                                if ((object)enumSymbol == null)
                                    return null;

                                return InitializerSemanticModel.Create(
                                    this.Compilation,
                                    enumDecl,
                                    enumSymbol,
                                    GetFieldOrPropertyInitializerBinder(enumSymbol, outer));
                            }
                        default:
                            Debug.Assert(false, "Unexpected node: " + node.Parent);
                            return null;
                    }

                case SyntaxKind.ArrowExpressionClause:
                    {
                        SourceMethodSymbol symbol = null;
                        MemberDeclarationSyntax memberSyntax;
                        var exprDecl = (ArrowExpressionClauseSyntax)node;

                        if (node.Parent is BasePropertyDeclarationSyntax)
                        {
                            symbol = (SourceMethodSymbol)GetDeclaredSymbol(exprDecl);
                        }
                        else if ((memberSyntax = node.Parent as MemberDeclarationSyntax) != null)
                        {
                            symbol = (SourceMethodSymbol)GetDeclaredSymbol(node.Parent as MemberDeclarationSyntax);
                        }
                        else
                        {
                            // Don't throw, just use for the assert
                            ExceptionUtilities.UnexpectedValue(node.Parent);
                        }

                        if ((object)symbol == null)
                            return null;
                        return MethodBodySemanticModel.Create(
                            this.compilation, symbol, outer.WithContainingMemberOrLambda(symbol), exprDecl);
                    }

                case SyntaxKind.GlobalStatement:
                    {
                        Debug.Assert(!this.IsRegularCSharp);
                        // TODO (tomat): handle misplaced global statements
                        if (node.Parent.Kind == SyntaxKind.CompilationUnit)
                        {
                            var scriptConstructor = this.Compilation.ScriptClass.InstanceConstructors.First();
                            return MethodBodySemanticModel.Create(
                                this.Compilation,
                                scriptConstructor,
                                outer,
                                node);
                        }
                    }
                    break;

                case SyntaxKind.BaseConstructorInitializer:
                case SyntaxKind.ThisConstructorInitializer:
                    {
                        var constructorDecl = (ConstructorDeclarationSyntax)node.Parent;
                        var constructorSymbol = (SourceMethodSymbol)GetDeclaredSymbol(constructorDecl);
                        if ((object)constructorSymbol == null)
                            return null;

                        return InitializerSemanticModel.Create(
                            this.Compilation,
                            (ConstructorInitializerSyntax)node,
                            constructorSymbol,
                            //insert an extra binder to perform constructor initialization checks
                            new WithConstructorInitializerLocalsBinder(outer.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.ConstructorInitializer, constructorSymbol),
                                                                       constructorDecl));
                    }

                case SyntaxKind.ArgumentList:
                    CSharpSyntaxNode parent = node.Parent;
                    if (parent != null && parent.Kind == SyntaxKind.BaseClassWithArguments)
                    {
                        var initializer = (BaseClassWithArgumentsSyntax)parent;
                        parent = initializer.Parent;
                        if (parent != null && parent.Kind == SyntaxKind.BaseList && initializer == ((BaseListSyntax)parent).Types[0])
                        {
                            parent = parent.Parent;
                            if (parent != null && parent.Kind == SyntaxKind.ClassDeclaration)
                            {
                                var classDecl = (ClassDeclarationSyntax)parent;
                                var constructorSymbol = (SourceMethodSymbol)GetDeclaredConstructorSymbol(classDecl);

                                if ((object)constructorSymbol == null)
                                    return null;

                                // Locals declared in instance initializers within the current partial class declaration
                                // should be in scope within the argument list.
                                outer = AddInitializersLocalsScope(outer, classDecl, constructorSymbol);

                                //insert an extra binder to perform constructor initialization checks
                                outer = outer.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.ConstructorInitializer, constructorSymbol);
                                outer = new WithConstructorInitializerLocalsBinder(outer, initializer.ArgumentList);

                                return InitializerSemanticModel.Create(
                                    this.Compilation,
                                    initializer.ArgumentList,
                                    constructorSymbol,
                                    outer);
                            }
                        }
                    }
                    break;

                case SyntaxKind.Attribute:
                    {
                        var attribute = (AttributeSyntax)node;
                        AliasSymbol aliasOpt;
                        DiagnosticBag discarded = DiagnosticBag.GetInstance();
                        var attributeType = (NamedTypeSymbol)outer.BindType(attribute.Name, discarded, out aliasOpt);
                        discarded.Free();

                        return AttributeSemanticModel.Create(
                            this.compilation,
                            attribute,
                            attributeType,
                            aliasOpt,
                            outer.WithAdditionalFlags(BinderFlags.AttributeArgument));
                    }
            }

            return null;
        }
예제 #2
0
        /// <summary>
        /// In regular C#, all field initializers are assignments to fields and the assigned expressions
        /// may not reference instance members.
        /// </summary>
        private static void BindRegularCSharpFieldInitializers(
            CSharpCompilation compilation,
            ImmutableArray <FieldInitializers> initializers,
            ArrayBuilder <BoundInitializer> boundInitializers,
            DiagnosticBag diagnostics,
            bool generateDebugInfo,
            out ConsList <Imports> firstDebugImports)
        {
            firstDebugImports = null;

            foreach (FieldInitializers siblingInitializers in initializers)
            {
                // All sibling initializers share the same parent node and tree so we can reuse the binder
                // factory across siblings.  Unfortunately, we cannot reuse the binder itself, because
                // individual fields might have their own binders (e.g. because of being declared unsafe).
                BinderFactory binderFactory = null;

                var infos = ArrayBuilder <FieldInitializerInfo> .GetInstance(); // Exact size is not known up front.

                foreach (FieldInitializer initializer in siblingInitializers.Initializers)
                {
                    FieldSymbol fieldSymbol = initializer.Field;
                    Debug.Assert((object)fieldSymbol != null);

                    // A constant field of type decimal needs a field initializer, so
                    // check if it is a metadata constant, not just a constant to exclude
                    // decimals. Other constants do not need field initializers.
                    if (!fieldSymbol.IsMetadataConstant)
                    {
                        //Can't assert that this is a regular C# compilation, because we could be in a nested type of a script class.
                        SyntaxReference syntaxRef       = initializer.Syntax;
                        var             initializerNode = (EqualsValueClauseSyntax)syntaxRef.GetSyntax();

                        if (binderFactory == null)
                        {
                            binderFactory = compilation.GetBinderFactory(syntaxRef.SyntaxTree);
                        }

                        Binder parentBinder = binderFactory.GetBinder(initializerNode);
                        Debug.Assert(parentBinder.ContainingMemberOrLambda == fieldSymbol.ContainingType || //should be the binder for the type
                                     fieldSymbol.ContainingType.IsImplicitClass);                           //however, we also allow fields in namespaces to help support script scenarios

                        if (generateDebugInfo && firstDebugImports == null)
                        {
                            firstDebugImports = parentBinder.ImportsList;
                        }

                        parentBinder = new LocalScopeBinder(parentBinder).WithAdditionalFlagsAndContainingMemberOrLambda(parentBinder.Flags | BinderFlags.FieldInitializer, fieldSymbol);

                        if (!fieldSymbol.IsConst && !fieldSymbol.IsStatic)
                        {
                            parentBinder = parentBinder.WithPrimaryConstructorParametersIfNecessary(fieldSymbol.ContainingType);
                        }

                        infos.Add(new FieldInitializerInfo(initializer, parentBinder, initializerNode));
                    }
                }

                // See if there are locals that we need to bring into the scope.
                var locals = default(ImmutableArray <LocalSymbol>);
                if (siblingInitializers.TypeDeclarationSyntax != null)
                {
                    locals = GetInitializationScopeLocals(infos);
                }

                ArrayBuilder <BoundInitializer> initializersBuilder = locals.IsDefaultOrEmpty ? boundInitializers : ArrayBuilder <BoundInitializer> .GetInstance(infos.Count);

                foreach (var info in infos)
                {
                    Binder binder = info.Binder;
                    ScopedExpressionBinder scopedExpressionBinder = null;

                    // Constant initializers is not part of the initialization scope.
                    if (info.Initializer.Field.IsConst || locals.IsDefault)
                    {
                        binder = scopedExpressionBinder = new ScopedExpressionBinder(binder, info.EqualsValue.Value);
                    }
                    else if (!locals.IsEmpty)
                    {
                        binder = new SimpleLocalScopeBinder(locals, binder);
                    }

                    BoundFieldInitializer boundInitializer = BindFieldInitializer(binder, info.Initializer.Field, info.EqualsValue, diagnostics);

                    if (scopedExpressionBinder != null && !scopedExpressionBinder.Locals.IsDefaultOrEmpty)
                    {
                        boundInitializer = boundInitializer.Update(boundInitializer.Field, scopedExpressionBinder.AddLocalScopeToExpression(boundInitializer.InitialValue));
                    }

                    initializersBuilder.Add(boundInitializer);
                }

                Debug.Assert(locals.IsDefaultOrEmpty == (initializersBuilder == boundInitializers));
                if (!locals.IsDefaultOrEmpty)
                {
                    boundInitializers.Add(new BoundInitializationScope((CSharpSyntaxNode)siblingInitializers.TypeDeclarationSyntax.GetSyntax(),
                                                                       locals, initializersBuilder.ToImmutableAndFree()));
                }
            }
        }