Exemple #1
0
        /// <summary>
        /// For "receiver.event += expr", produce "receiver.add_event(expr)".
        /// For "receiver.event -= expr", produce "receiver.remove_event(expr)".
        /// </summary>
        /// <remarks>
        /// Performs some validation of the accessor that couldn't be done in CheckEventValueKind, because
        /// the specific accessor wasn't known.
        /// </remarks>
        private BoundExpression BindEventAssignment(AssignmentExpressionSyntax node, BoundEventAccess left, BoundExpression right, BinaryOperatorKind opKind, DiagnosticBag diagnostics)
        {
            Debug.Assert(opKind == BinaryOperatorKind.Addition || opKind == BinaryOperatorKind.Subtraction);

            bool hasErrors = false;

            EventSymbol eventSymbol = left.EventSymbol;
            BoundExpression receiverOpt = left.ReceiverOpt;

            TypeSymbol delegateType = left.Type;

            HashSet<DiagnosticInfo> useSiteDiagnostics = null;
            Conversion argumentConversion = this.Conversions.ClassifyConversionFromExpression(right, delegateType, ref useSiteDiagnostics);

            if (!argumentConversion.IsImplicit || !argumentConversion.IsValid) // NOTE: dev10 appears to allow user-defined conversions here.
            {
                hasErrors = true;
                if (delegateType.IsDelegateType()) // Otherwise, suppress cascading.
                {
                    GenerateImplicitConversionError(diagnostics, node, argumentConversion, right, delegateType);
                }
            }

            BoundExpression argument = CreateConversion(right, argumentConversion, delegateType, diagnostics);

            bool isAddition = opKind == BinaryOperatorKind.Addition;
            MethodSymbol method = isAddition ? eventSymbol.AddMethod : eventSymbol.RemoveMethod;

            TypeSymbol type;
            if ((object)method == null)
            {
                type = this.GetSpecialType(SpecialType.System_Void, diagnostics, node); //we know the return type would have been void

                // There will be a diagnostic on the declaration if it is from source.
                if (!eventSymbol.OriginalDefinition.IsFromCompilation(this.Compilation))
                {
                    // CONSIDER: better error code?  ERR_EventNeedsBothAccessors?
                    Error(diagnostics, ErrorCode.ERR_MissingPredefinedMember, node, delegateType, SourceEventSymbol.GetAccessorName(eventSymbol.Name, isAddition));
                }
            }
            else if (eventSymbol.IsWindowsRuntimeEvent)
            {
                // Return type is actually void because this call will be later encapsulated in a call
                // to WindowsRuntimeMarshal.AddEventHandler or RemoveEventHandler, which has the return
                // type of void.
                type = this.GetSpecialType(SpecialType.System_Void, diagnostics, node);
            }
            else
            {
                type = method.ReturnType;
                if (!this.IsAccessible(method, ref useSiteDiagnostics, this.GetAccessThroughType(receiverOpt)))
                {
                    // CONSIDER: depending on the accessibility (e.g. if it's private), dev10 might just report the whole event bogus.
                    Error(diagnostics, ErrorCode.ERR_BadAccess, node, method);
                    hasErrors = true;
                }
            }

            diagnostics.Add(node, useSiteDiagnostics);

            return new BoundEventAssignmentOperator(
                syntax: node,
                @event: eventSymbol,
                isAddition: isAddition,
                isDynamic: right.HasDynamicType(),
                receiverOpt: receiverOpt,
                argument: argument,
                type: type,
                hasErrors: hasErrors);
        }
 public override BoundNode VisitEventAccess(BoundEventAccess node)
 {
     _syntaxWithReceiver = node.Syntax;
     return base.VisitEventAccess(node);
 }
        private bool CheckEventValueKind(BoundEventAccess boundEvent, BindValueKind valueKind, DiagnosticBag diagnostics)
        {
            // Compound assignment (actually "event assignment") is allowed "everywhere", subject to the restrictions of
            // accessibility, use site errors, and receiver variable-ness (for structs).
            // Other operations are allowed only for field-like events and only where the backing field is accessible
            // (i.e. in the declaring type) - subject to use site errors and receiver variable-ness.

            BoundExpression receiver;
            CSharpSyntaxNode eventSyntax; //does not include receiver
            EventSymbol eventSymbol = GetEventSymbol(boundEvent, out receiver, out eventSyntax);

            switch (valueKind)
            {
                case BindValueKind.CompoundAssignment:
                    {
                        // NOTE: accessibility has already been checked by lookup.
                        // NOTE: availability of well-known members is checked in BindEventAssignment because
                        // we don't have the context to determine whether addition or subtraction is being performed.

                        if (ReportUseSiteDiagnostics(eventSymbol, diagnostics, eventSyntax))
                        {
                            // NOTE: BindEventAssignment checks use site errors on the specific accessor 
                            // (since we don't know which is being used).
                            return false;
                        }

                        Debug.Assert(!RequiresVariableReceiver(receiver, eventSymbol));
                        return true;
                    }
                case BindValueKind.Assignment:
                case BindValueKind.RValue:
                case BindValueKind.RValueOrMethodGroup:
                case BindValueKind.OutParameter:
                case BindValueKind.IncrementDecrement:
                case BindValueKind.AddressOf:
                    {
                        if (!boundEvent.IsUsableAsField)
                        {
                            // Dev10 reports this in addition to ERR_BadAccess, but we won't even reach this point if the event isn't accessible (caught by lookup).
                            Error(diagnostics, GetBadEventUsageDiagnosticInfo(eventSymbol), eventSyntax);
                            return false;
                        }
                        else if (ReportUseSiteDiagnostics(eventSymbol, diagnostics, eventSyntax))
                        {
                            return false;
                        }
                        else if (RequiresSettingValue(valueKind))
                        {
                            if (eventSymbol.IsWindowsRuntimeEvent && valueKind != BindValueKind.Assignment)
                            {
                                // NOTE: Dev11 reports ERR_RefProperty, as if this were a property access (since that's how it will be lowered).
                                // Roslyn reports a new, more specific, error code.
                                ErrorCode errorCode = valueKind == BindValueKind.OutParameter ? ErrorCode.ERR_WinRtEventPassedByRef : GetStandardLvalueError(valueKind);
                                Error(diagnostics, errorCode, eventSyntax, eventSymbol);

                                return false;
                            }
                            else if (RequiresVariableReceiver(receiver, eventSymbol.AssociatedField) && // NOTE: using field, not event
                                !CheckIsValidReceiverForVariable(eventSyntax, receiver, BindValueKind.Assignment, diagnostics))
                            {
                                return false;
                            }
                        }

                        return true;
                    }
                default:
                    throw ExceptionUtilities.UnexpectedValue(valueKind);
            }
        }
        private BoundExpression VisitWindowsRuntimeEventFieldAssignmentOperator(SyntaxNode syntax, BoundEventAccess left, BoundExpression right)
        {
            Debug.Assert(left.IsUsableAsField);

            EventSymbol eventSymbol = left.EventSymbol;
            Debug.Assert(eventSymbol.HasAssociatedField);
            Debug.Assert(eventSymbol.IsWindowsRuntimeEvent);

            BoundExpression rewrittenReceiverOpt = left.ReceiverOpt == null ? null : VisitExpression(left.ReceiverOpt);
            BoundExpression rewrittenRight = VisitExpression(right);

            const bool isDynamic = false;
            return RewriteWindowsRuntimeEventAssignmentOperator(
                syntax,
                eventSymbol,
                EventAssignmentKind.Assignment,
                isDynamic,
                rewrittenReceiverOpt,
                rewrittenRight);
        }
        public override BoundNode VisitEventAccess(BoundEventAccess node)
        {
            // We didn't get here via VisitEventAssignmentOperator (i.e. += or -=),
            // so the event better be field-like.
            Debug.Assert(node.IsUsableAsField);

            BoundExpression rewrittenReceiver = VisitExpression(node.ReceiverOpt);
            return MakeEventAccess(node.Syntax, rewrittenReceiver, node.EventSymbol, node.ConstantValue, node.ResultKind, node.Type);
        }
Exemple #6
0
 private static CSharpSyntaxNode GetEventName(BoundEventAccess expr)
 {
     CSharpSyntaxNode syntax = expr.Syntax;
     switch (syntax.Kind())
     {
         case SyntaxKind.SimpleMemberAccessExpression:
         case SyntaxKind.PointerMemberAccessExpression:
             return ((MemberAccessExpressionSyntax)syntax).Name;
         case SyntaxKind.QualifiedName:
             // This case is reachable only through SemanticModel
             return ((QualifiedNameSyntax)syntax).Right;
         case SyntaxKind.IdentifierName:
             return syntax;
         case SyntaxKind.MemberBindingExpression:
             return ((MemberBindingExpressionSyntax)syntax).Name;
         default:
             throw ExceptionUtilities.UnexpectedValue(syntax.Kind());
     }
 }
 public override BoundNode VisitEventAccess(BoundEventAccess node)
 {
     // Don't bother reporting an obsolete diagnostic if the access is already wrong for other reasons
     // (specifically, we can't use it as a field here).
     if (node.IsUsableAsField)
     {
         bool hasBaseReceiver = node.ReceiverOpt != null && node.ReceiverOpt.Kind == BoundKind.BaseReference;
         Binder.ReportDiagnosticsIfObsolete(_diagnostics, node.EventSymbol.AssociatedField, node.Syntax, hasBaseReceiver, _containingSymbol, _containingSymbol.ContainingType, BinderFlags.None);
     }
     CheckReceiverIfField(node.ReceiverOpt);
     return base.VisitEventAccess(node);
 }
Exemple #8
0
 public override BoundNode VisitEventAccess(BoundEventAccess node)
 {
     _syntaxWithReceiver = node.Syntax;
     return(base.VisitEventAccess(node));
 }
Exemple #9
0
        private BoundExpression VisitAssignmentOperator(BoundAssignmentOperator node, bool used)
        {
            var loweredRight = VisitExpression(node.Right);

            BoundExpression left = node.Left;
            BoundExpression loweredLeft;

            switch (left.Kind)
            {
            case BoundKind.PropertyAccess:
                loweredLeft = VisitPropertyAccess((BoundPropertyAccess)left, isLeftOfAssignment: true);
                break;

            case BoundKind.IndexerAccess:
                loweredLeft = VisitIndexerAccess((BoundIndexerAccess)left, isLeftOfAssignment: true);
                break;

            case BoundKind.IndexOrRangePatternIndexerAccess:
                loweredLeft = VisitIndexOrRangePatternIndexerAccess(
                    (BoundIndexOrRangePatternIndexerAccess)left,
                    isLeftOfAssignment: true);
                break;

            case BoundKind.EventAccess:
            {
                BoundEventAccess eventAccess = (BoundEventAccess)left;
                if (eventAccess.EventSymbol.IsWindowsRuntimeEvent)
                {
                    Debug.Assert(!node.IsRef);
                    return(VisitWindowsRuntimeEventFieldAssignmentOperator(node.Syntax, eventAccess, loweredRight));
                }
                goto default;
            }

            case BoundKind.DynamicMemberAccess:
            {
                // dyn.m = expr
                var memberAccess    = (BoundDynamicMemberAccess)left;
                var loweredReceiver = VisitExpression(memberAccess.Receiver);
                return(_dynamicFactory.MakeDynamicSetMember(loweredReceiver, memberAccess.Name, loweredRight).ToExpression());
            }

            case BoundKind.DynamicIndexerAccess:
            {
                // dyn[args] = expr
                var indexerAccess    = (BoundDynamicIndexerAccess)left;
                var loweredReceiver  = VisitExpression(indexerAccess.Receiver);
                var loweredArguments = VisitList(indexerAccess.Arguments);
                return(MakeDynamicSetIndex(
                           indexerAccess,
                           loweredReceiver,
                           loweredArguments,
                           indexerAccess.ArgumentNamesOpt,
                           indexerAccess.ArgumentRefKindsOpt,
                           loweredRight));
            }

            default:
                loweredLeft = VisitExpression(left);
                break;
            }

            return(MakeStaticAssignmentOperator(node.Syntax, loweredLeft, loweredRight, node.IsRef, node.Type, used));
        }
Exemple #10
0
        private BoundExpression VisitWindowsRuntimeEventFieldAssignmentOperator(SyntaxNode syntax, BoundEventAccess left, BoundExpression rewrittenRight)
        {
            Debug.Assert(left.IsUsableAsField);

            EventSymbol eventSymbol = left.EventSymbol;

            Debug.Assert(eventSymbol.HasAssociatedField);
            Debug.Assert(eventSymbol.IsWindowsRuntimeEvent);

            BoundExpression rewrittenReceiverOpt = left.ReceiverOpt == null ? null : VisitExpression(left.ReceiverOpt);

            const bool isDynamic = false;

            return(RewriteWindowsRuntimeEventAssignmentOperator(
                       syntax,
                       eventSymbol,
                       EventAssignmentKind.Assignment,
                       isDynamic,
                       rewrittenReceiverOpt,
                       rewrittenRight));
        }