/// <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); }
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); }
public override BoundNode VisitEventAccess(BoundEventAccess node) { _syntaxWithReceiver = node.Syntax; return(base.VisitEventAccess(node)); }
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)); }
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)); }