Exemple #1
0
        internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, DiagnosticBag diagnostics)
        {
            switch (node.Kind())
            {
            case SyntaxKind.ArrowExpressionClause:
                return(binder.BindExpressionBodyAsBlock((ArrowExpressionClauseSyntax)node, diagnostics));

            case SyntaxKind.BaseConstructorInitializer:
            case SyntaxKind.ThisConstructorInitializer:
                return(binder.BindConstructorInitializer((ConstructorInitializerSyntax)node, diagnostics));

            case SyntaxKind.MethodDeclaration:
            case SyntaxKind.ConversionOperatorDeclaration:
            case SyntaxKind.OperatorDeclaration:
            case SyntaxKind.ConstructorDeclaration:
            case SyntaxKind.DestructorDeclaration:
            case SyntaxKind.GetAccessorDeclaration:
            case SyntaxKind.SetAccessorDeclaration:
            case SyntaxKind.AddAccessorDeclaration:
            case SyntaxKind.RemoveAccessorDeclaration:
                return(binder.BindMethodBody(node, diagnostics));
            }

            return(base.Bind(binder, node, diagnostics));
        }
        internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, DiagnosticBag diagnostics)
        {
            EqualsValueClauseSyntax equalsValue = null;

            switch (node.Kind())
            {
            case SyntaxKind.EqualsValueClause:
                equalsValue = (EqualsValueClauseSyntax)node;
                break;

            case SyntaxKind.VariableDeclarator:
                equalsValue = ((VariableDeclaratorSyntax)node).Initializer;
                break;

            case SyntaxKind.PropertyDeclaration:
                equalsValue = ((PropertyDeclarationSyntax)node).Initializer;
                break;

            case SyntaxKind.Parameter:
                equalsValue = ((ParameterSyntax)node).Default;
                break;

            case SyntaxKind.EnumMemberDeclaration:
                equalsValue = ((EnumMemberDeclarationSyntax)node).EqualsValue;
                break;

            case SyntaxKind.BaseConstructorInitializer:
            case SyntaxKind.ThisConstructorInitializer:
                return(binder.BindConstructorInitializer(((ConstructorInitializerSyntax)node).ArgumentList, (MethodSymbol)MemberSymbol, diagnostics));

            case SyntaxKind.ArgumentList:
                return(binder.BindConstructorInitializer((ArgumentListSyntax)node, (MethodSymbol)MemberSymbol, diagnostics));
            }

            if (equalsValue != null)
            {
                return(BindEqualsValue(binder, equalsValue, diagnostics));
            }

            return(base.Bind(binder, node, diagnostics));
        }
        internal override BoundNode Bind(Binder binder, CSharpSyntaxNode node, DiagnosticBag diagnostics)
        {
            EqualsValueClauseSyntax equalsValue = null;

            switch (node.Kind())
            {
                case SyntaxKind.EqualsValueClause:
                    equalsValue = (EqualsValueClauseSyntax)node;
                    break;

                case SyntaxKind.VariableDeclarator:
                    equalsValue = ((VariableDeclaratorSyntax)node).Initializer;
                    break;

                case SyntaxKind.PropertyDeclaration:
                    equalsValue = ((PropertyDeclarationSyntax)node).Initializer;
                    break;

                case SyntaxKind.Parameter:
                    equalsValue = ((ParameterSyntax)node).Default;
                    break;

                case SyntaxKind.EnumMemberDeclaration:
                    equalsValue = ((EnumMemberDeclarationSyntax)node).EqualsValue;
                    break;

                case SyntaxKind.BaseConstructorInitializer:
                case SyntaxKind.ThisConstructorInitializer:
                    return binder.BindConstructorInitializer(((ConstructorInitializerSyntax)node).ArgumentList, (MethodSymbol)MemberSymbol, diagnostics);

                case SyntaxKind.ArgumentList:
                    return binder.BindConstructorInitializer((ArgumentListSyntax)node, (MethodSymbol)MemberSymbol, diagnostics);
            }

            if (equalsValue != null)
            {
                return BindEqualsValue(binder, equalsValue, diagnostics);
            }

            return base.Bind(binder, node, diagnostics);
        }
Exemple #4
0
        /// <summary>
        /// Bind the (implicit or explicit) constructor initializer of a constructor symbol.
        /// </summary>
        /// <param name="constructor">Constructor method.</param>
        /// <param name="diagnostics">Accumulates errors (e.g. access "this" in constructor initializer).</param>
        /// <param name="compilation">Used to retrieve binder.</param>
        /// <returns>A bound expression for the constructor initializer call.</returns>
        private static BoundExpression BindConstructorInitializer(MethodSymbol constructor, DiagnosticBag diagnostics, CSharpCompilation compilation)
        {
            // Note that the base type can be null if we're compiling System.Object in source.
            NamedTypeSymbol baseType = constructor.ContainingType.BaseTypeNoUseSiteDiagnostics;

            SourceMethodSymbol sourceConstructor          = constructor as SourceMethodSymbol;
            CSharpSyntaxNode   syntax                     = null;
            ArgumentListSyntax initializerArgumentListOpt = null;

            if ((object)sourceConstructor != null)
            {
                syntax = sourceConstructor.SyntaxNode;

                if (syntax.Kind == SyntaxKind.ConstructorDeclaration)
                {
                    var constructorSyntax = (ConstructorDeclarationSyntax)syntax;
                    if (constructorSyntax.Initializer != null)
                    {
                        initializerArgumentListOpt = constructorSyntax.Initializer.ArgumentList;
                    }

                    ErrorCode reportIfHavePrimaryCtor = ErrorCode.Void;

                    if (initializerArgumentListOpt == null || initializerArgumentListOpt.Parent.Kind != SyntaxKind.ThisConstructorInitializer)
                    {
                        reportIfHavePrimaryCtor = ErrorCode.ERR_InstanceCtorMustHaveThisInitializer;
                    }
                    else if (initializerArgumentListOpt.Arguments.Count == 0 && constructor.ContainingType.TypeKind == TypeKind.Struct)
                    {
                        // Based on C# Design Notes for Oct 21, 2013:
                        reportIfHavePrimaryCtor = ErrorCode.ERR_InstanceCtorCannotHaveDefaultThisInitializer;
                    }

                    if (reportIfHavePrimaryCtor != ErrorCode.Void)
                    {
                        var container = constructor.ContainingType as SourceMemberContainerTypeSymbol;

                        if ((object)container != null && (object)container.PrimaryCtor != null)
                        {
                            diagnostics.Add(reportIfHavePrimaryCtor, constructor.Locations[0]);
                        }
                    }
                }
                else
                {
                    // Primary constuctor case.
                    Debug.Assert(syntax.Kind == SyntaxKind.ParameterList);
                    if (syntax.Parent.Kind == SyntaxKind.ClassDeclaration)
                    {
                        var classDecl = (ClassDeclarationSyntax)syntax.Parent;

                        if (classDecl.BaseList != null && classDecl.BaseList.Types.Count > 0)
                        {
                            TypeSyntax baseTypeSyntax = classDecl.BaseList.Types[0];
                            if (baseTypeSyntax.Kind == SyntaxKind.BaseClassWithArguments)
                            {
                                initializerArgumentListOpt = ((BaseClassWithArgumentsSyntax)baseTypeSyntax).ArgumentList;
                            }
                        }
                    }
                    else
                    {
                        Debug.Assert(syntax.Parent.Kind == SyntaxKind.StructDeclaration);
                    }
                }
            }

            // The common case is that we have no constructor initializer and the type inherits directly from object.
            // Also, we might be trying to generate a constructor for an entirely compiler-generated class such
            // as a closure class; in that case it is vexing to try to find a suitable binder for the non-existing
            // constructor syntax so that we can do unnecessary overload resolution on the non-existing initializer!
            // Simply take the early out: bind directly to the parameterless object ctor rather than attempting
            // overload resolution.
            if (initializerArgumentListOpt == null && (object)baseType != null)
            {
                if (baseType.SpecialType == SpecialType.System_Object)
                {
                    return(GenerateObjectConstructorInitializer(constructor, diagnostics));
                }
                else if (baseType.IsErrorType() || baseType.IsStatic)
                {
                    // If the base type is bad and there is no initializer then we can just bail.
                    // We have no expressions we need to analyze to report errors on.
                    return(null);
                }
            }

            // Either our base type is not object, or we have an initializer syntax, or both. We're going to
            // need to do overload resolution on the set of constructors of the base type, either on
            // the provided initializer syntax, or on an implicit ": base()" syntax.

            // SPEC ERROR: The specification states that if you have the situation
            // SPEC ERROR: class B { ... } class D1 : B {} then the default constructor
            // SPEC ERROR: generated for D1 must call an accessible *parameterless* constructor
            // SPEC ERROR: in B. However, it also states that if you have
            // SPEC ERROR: class B { ... } class D2 : B { D2() {} }  or
            // SPEC ERROR: class B { ... } class D3 : B { D3() : base() {} }  then
            // SPEC ERROR: the compiler performs *overload resolution* to determine
            // SPEC ERROR: which accessible constructor of B is called. Since B might have
            // SPEC ERROR: a ctor with all optional parameters, overload resolution might
            // SPEC ERROR: succeed even if there is no parameterless constructor. This
            // SPEC ERROR: is unintentionally inconsistent, and the native compiler does not
            // SPEC ERROR: implement this behavior. Rather, we should say in the spec that
            // SPEC ERROR: if there is no ctor in D1, then a ctor is created for you exactly
            // SPEC ERROR: as though you'd said "D1() : base() {}".
            // SPEC ERROR: This is what we now do in Roslyn.

            // Now, in order to do overload resolution, we're going to need a binder. There are
            // three possible situations:
            //
            // class D1 : B { }
            // class D2 : B { D2(int x) { } }
            // class D3 : B { D3(int x) : base(x) { } }
            //
            // In the first case the binder needs to be the binder associated with
            // the *body* of D1 because if the base class ctor is protected, we need
            // to be inside the body of a derived class in order for it to be in the
            // accessibility domain of the protected base class ctor.
            //
            // In the second case the binder could be the binder associated with
            // the body of D2; since the implicit call to base() will have no arguments
            // there is no need to look up "x".
            //
            // In the third case the binder must be the binder that knows about "x"
            // because x is in scope.

            Binder outerBinder;

            if ((object)sourceConstructor == null)
            {
                // The constructor is implicit. We need to get the binder for the body
                // of the enclosing class.
                CSharpSyntaxNode containerNode = constructor.GetNonNullSyntaxNode();
                SyntaxToken      bodyToken;
                if (containerNode.Kind == SyntaxKind.ClassDeclaration)
                {
                    bodyToken = ((ClassDeclarationSyntax)containerNode).OpenBraceToken;
                }
                else if (containerNode.Kind == SyntaxKind.StructDeclaration)
                {
                    bodyToken = ((StructDeclarationSyntax)containerNode).OpenBraceToken;
                }
                else if (containerNode.Kind == SyntaxKind.EnumDeclaration)
                {
                    // We're not going to find any non-default ctors, but we'll look anyway.
                    bodyToken = ((EnumDeclarationSyntax)containerNode).OpenBraceToken;
                }
                else
                {
                    Debug.Assert(false, "How did we get an implicit constructor added to something that is neither a class nor a struct?");
                    bodyToken = containerNode.GetFirstToken();
                }

                outerBinder = compilation.GetBinderFactory(containerNode.SyntaxTree).GetBinder(containerNode, bodyToken.Position);
            }
            else if (initializerArgumentListOpt == null)
            {
                // We have a ctor in source but no explicit constructor initializer.  We can't just use the binder for the
                // type containing the ctor because the ctor might be marked unsafe.  Use the binder for the parameter list
                // as an approximation - the extra symbols won't matter because there are no identifiers to bind.

                outerBinder = compilation.GetBinderFactory(sourceConstructor.SyntaxTree).GetBinder(syntax.Kind == SyntaxKind.ParameterList ?
                                                                                                   syntax :
                                                                                                   ((ConstructorDeclarationSyntax)syntax).ParameterList);
            }
            else
            {
                outerBinder = compilation.GetBinderFactory(sourceConstructor.SyntaxTree).GetBinder(initializerArgumentListOpt);
            }

            //wrap in ConstructorInitializerBinder for appropriate errors
            Binder initializerBinder = outerBinder.WithAdditionalFlagsAndContainingMemberOrLambda(BinderFlags.ConstructorInitializer, constructor);

            return(initializerBinder.BindConstructorInitializer(initializerArgumentListOpt, constructor, diagnostics));
        }