/***************************************************************************** ;ValidateHandlesLists Given Method() Handles X1.SomeEvent 1. verify that X1 is a valid WithEvents variable 2. verify that X1 sources SomeEvent() *****************************************************************************/ void Bindable::ValidateAndHookUpHandles ( BCSYM_HandlesList *HandlesEntry, BCSYM_MethodImpl *HandlingMethod ) { VSASSERT( !HandlesEntry->IsBad(), "Bad handles unexpected here!!"); VSASSERT( CurrentContainer()->IsClass(), "Non-classes/non-structures/non-modules cannot have handles clauses!!"); // Dev10#489103: if the handling method is bad, then we can't really tell whether it handles the event: if (HandlingMethod->IsBadParamTypeOrReturnType()) { HandlesEntry->SetIsBad(); return; } Symbols SymbolFactory( CurrentCompilerInstance(), CurrentAllocator(), NULL, CurrentGenericBindingCache()); BCSYM_Class *ContainerOfHandlingMethod = CurrentContainer()->PClass(); BCSYM *TypeToFindEventIn; BCSYM_Property *EventSourceProperty = NULL; BCSYM_Property *WithEventsProperty; BCSYM *InstanceTypeThroughWhichEventIsAccessed; if (HandlesEntry->IsMyBase()) { TypeToFindEventIn = TypeHelpers::GetBaseClass(ContainerOfHandlingMethod, SymbolFactory); // A bad base is no base if (!TypeToFindEventIn) { HandlesEntry->SetIsBad(); return; } InstanceTypeThroughWhichEventIsAccessed = ContainerOfHandlingMethod; } else if (HandlesEntry->IsEventFromMeOrMyClass()) { if (ContainerOfHandlingMethod->IsGeneric()) { TypeToFindEventIn = SynthesizeOpenGenericBinding( ContainerOfHandlingMethod, SymbolFactory); } else { TypeToFindEventIn = ContainerOfHandlingMethod; } InstanceTypeThroughWhichEventIsAccessed = ContainerOfHandlingMethod; } else { WithEventsProperty = HandlesEntry->GetWithEventsProperty(); VSASSERT( WithEventsProperty, "How can a non-bad handles entry not have a withevents property ?"); BCSYM_Variable *WithEventsVar = WithEventsProperty->CreatedByWithEventsDecl(); VSASSERT( WithEventsVar, "How can a non-bad handles entry not refer to a withevents var ?"); if (WithEventsVar->IsBad() || WithEventsVar->IsBadVariableType()) { HandlesEntry->SetIsBad(); return; } BCSYM *TypeOfWithEventsVar = WithEventsProperty->GetType(); VSASSERT( TypeOfWithEventsVar->IsContainer() || (TypeOfWithEventsVar->IsGenericParam() && TypeOfWithEventsVar->PGenericParam()->IsReferenceType()), "What else can the type of a withevents variable be ?"); if (HandlesEntry->GetEventSourcePropertyName()) { // If withevents variable type is type parameter, then search in its class constraint, // else search in the withevents variable type itself. // EventSourceProperty = GetEventSourceProperty( TypeOfWithEventsVar, HandlesEntry->GetEventSourcePropertyName()); if (!EventSourceProperty) { // "'Handles' must specify a 'WithEvents' variable or 'MyBase' qualified with a single identifier." ReportErrorOnSymbol( IsStdModule(CurrentContainer()) ? ERRID_HandlesSyntaxInModule : ERRID_HandlesSyntaxInClass, CurrentErrorLog(HandlingMethod), HandlesEntry); HandlesEntry->SetIsBad(); return; } // HandlesEntry->SetEventSourceProperty(EventSourceProperty); // VSASSERT( EventSourceProperty->GetType()->IsContainer(), "Referring Property - What else can a type that is not a named type be ?"); TypeToFindEventIn = EventSourceProperty->GetType(); } else { TypeToFindEventIn = TypeOfWithEventsVar; } InstanceTypeThroughWhichEventIsAccessed = TypeToFindEventIn; } VSASSERT( TypeToFindEventIn, "No type to find the event in ?"); bool IsBadName; BCSYM_NamedRoot *EventDecl = Semantics::EnsureNamedRoot ( Semantics::InterpretName ( HandlesEntry->GetEventName(), *(HandlesEntry->GetLocationOfEvent()), TypeToFindEventIn->IsContainer() ? TypeToFindEventIn->PContainer()->GetHash() : NULL, TypeToFindEventIn->IsGenericParam() ? TypeToFindEventIn->PGenericParam() : NULL, NameSearchIgnoreParent | NameSearchEventReference | NameSearchIgnoreExtensionMethods, InstanceTypeThroughWhichEventIsAccessed, ContainerOfHandlingMethod->GetHash(), // Current Context CurrentErrorLog(HandlingMethod), CurrentCompilerInstance(), CurrentCompilerHost(), m_CompilationCaches, CurrentSourceFile(HandlingMethod), false, // don't perform obsolete checks IsBadName, NULL, // the binding context is not required here since the synthesized // code has the withevents variable from which the type binding // information is obtained NULL, -1 ) ); if (IsBadName) { HandlesEntry->SetIsBad(); return; } if (!EventDecl || !EventDecl->IsEventDecl()) { ReportErrorAtLocation( ERRID_EventNotFound1, CurrentErrorLog(HandlingMethod), HandlesEntry->GetLocationOfEvent(), HandlesEntry->GetEventName()); HandlesEntry->SetIsBad(); return; } if (EventDecl->IsBad()) { HandlesEntry->SetIsBad(); return; } BCSYM_EventDecl *Event = EventDecl->PEventDecl(); HandlesEntry->SetEvent(Event); // [....] - 11/17/2005 // See Bug # 544269 // The call to ResolveAllNamedTypesForContainer needed to be replaced with a call // to ResolveShadowingOverloadingAndOverridingForContainer because event signatures // are not necessarily setup untill after ResolveShadowingOverloadingAndOverriding // has been called. // Go and bind the event we are comparing against up to the state we need for // validating handles. ResolveShadowingOverloadingOverridingAndCheckGenericsForContainer(Event->GetContainer(), m_CompilationCaches); // Check for bad param types here (VSW#172753). if (Event->GetDelegate() && Event->GetDelegate()->IsContainer() && DefinedInMetaData(Event->GetDelegate()->PContainer())) { for (BCSYM_Param *Param = Event->GetFirstParam(); Param; Param = Param->GetNext()) { if (Param->GetType()->IsBad()) { Param->GetType()->PNamedRoot()->ReportError( CurrentCompilerInstance(), CurrentErrorLog(HandlingMethod), HandlesEntry->GetLocationOfEvent()); HandlesEntry->SetIsBad(); return; } } } BCSYM_GenericBinding *EventGenericBindingContext = DeriveGenericBindingForMemberReference(TypeToFindEventIn, Event, SymbolFactory, CurrentCompilerHost()); MethodConversionClass MethodConversion = Semantics::ClassifyMethodConversion( HandlingMethod, GenericBindingInfo(), Event, EventGenericBindingContext, false, //IgnoreReturnValueErrorsForInference &SymbolFactory, CurrentCompilerHost()); SourceFile * SourceFile = HandlingMethod->GetSourceFile(); if (!Semantics::IsSupportedMethodConversion( SourceFile->GetOptionFlags() & OPTION_OptionStrict, MethodConversion)) { // "Method '|1' cannot handle Event '|2' because they do not have the same signature." StringBuffer HandlingMethodRepresentation; HandlingMethod->GetBasicRep(CurrentCompilerInstance(), NULL, &HandlingMethodRepresentation); StringBuffer EventRepresentation; Event->GetBasicRep(CurrentCompilerInstance(), NULL, &EventRepresentation, EventGenericBindingContext); ReportErrorAtLocation( ERRID_EventHandlerSignatureIncompatible2, CurrentErrorLog(HandlingMethod), HandlesEntry->GetLocationOfEvent(), HandlingMethodRepresentation.GetString(), EventRepresentation.GetString()); HandlesEntry->SetIsBad(); return; } // Hook up handlers to the events they specify in their handles clauses if (HandlesEntry->IsMyBase() || HandlesEntry->IsEventFromMeOrMyClass()) { // For these cases, we search for valid MyBase, Me, MyClass handles clauses and set up the // addhandlers in all constructors that directly call a base constructor. This is done in // semantics in initializefields because that is when the information whether it directly // calls the base constructor is known. // const bool BuildSharedConstructor = true; if (HandlesEntry->GetEvent()->IsShared() && HandlingMethod->IsShared()) { // Make sure a shared constructor is present, else synthesize one if (!ContainerOfHandlingMethod->GetSharedConstructor(CurrentCompilerInstance())) { // Synthesize one SynthesizeConstructor(BuildSharedConstructor); } } else { // Make sure an Instance constructor is present, else synthesize one if (!ContainerOfHandlingMethod->GetFirstInstanceConstructor(CurrentCompilerInstance())) { // Synthesize one SynthesizeConstructor(!BuildSharedConstructor); } } } else { VSASSERT( WithEventsProperty->SetProperty(), "How can there be no set accessor for a withevents property ?"); if (WithEventsProperty->IsShared() && !HandlingMethod->IsShared()) { // "Events of shared WithEvents variables cannot be handled by non-shared methods." ReportErrorAtLocation( ERRID_SharedEventNeedsSharedHandler, CurrentErrorLog(HandlingMethod), HandlesEntry->GetLocationOfWithEventsVar()); HandlesEntry->SetIsBad(); return; } // // hookup the handler list info for the above handles entry on to the WithEvents_Set. // GenWithEventsSetCode() will write synthetic code for these later // WithEventsProperty->SetProperty()->AddToHandlerList( HandlingMethod, Event, EventGenericBindingContext, EventSourceProperty, CurrentAllocator()); } }
void CLSComplianceChecker::VerifyProcForCLSCompliance( BCSYM_Proc * Proc, BCSYM_Container * ParentOfProc) { // We won't do CLS Compliance checking on BeginInvoke or EndInvoke (only Invoke) to avoid // duplicating our efforts. // if (ParentOfProc->IsDelegate() && (ParentOfProc->SimpleBind(NULL, STRING_CONST(m_Compiler, DelegateBeginInvoke)) == Proc || ParentOfProc->SimpleBind(NULL, STRING_CONST(m_Compiler, DelegateEndInvoke)) == Proc)) { return; } // Event specific validation // if (Proc->IsEventDecl()) { BCSYM_EventDecl *Event = Proc->PEventDecl(); BCSYM *RawDelegate = Event->GetRawDelegate(); BCSYM *Delegate = Event->GetDelegate(); VSASSERT(!(Event->AreParametersObtainedFromDelegate() && Event->IsDelegateFromImplements()), "Event parameters obtained from the implemented event's delegate - unexpected!!!"); // The event's delegate also needs to be validated, but only when it is not the implicitly // generated delegate of this event. // if (Delegate && Delegate->IsDelegate() && Delegate->PClass()->CreatedByEventDecl() != Event) { // If this asserts fails, this can possibly cause duplicate errors for type arguments // of the delegate and also for errors to be reported at the wrong locations. // VSASSERT(RawDelegate->IsNamedType() || Event->IsDelegateFromImplements(), "Event delegate should not be the raw delegate type of the implemented event!!!"); if (!IsTypeCLSCompliant(RawDelegate, Event)) { ReportErrorOnSymbol( WRNID_EventDelegateTypeNotCLSCompliant2, RawDelegate->IsNamedType() ? RawDelegate : Event, Event, Delegate->PClass()->GetQualifiedName(true, ParentOfProc), Event->GetName()); } } // If the event's parameters are obtained from its delegate, then its parameters should not // be checked here because they will be validated when the delegate itself is checked. // if (Event->AreParametersObtainedFromDelegate()) { return; } } // Check the return type. // if (!IsTypeCLSCompliant(Proc->GetRawType(), Proc)) { ReportErrorOnSymbol( WRNID_ProcTypeNotCLSCompliant1, Proc, Proc->GetName()); } // Check the parameters. // for(BCSYM_Param *Param = Proc->GetFirstParam(); Param; Param = Param->GetNext()) { if (!IsTypeCLSCompliant(Param->GetRawType(), Proc)) { ReportErrorOnSymbol( WRNID_ParamNotCLSCompliant1, Param, Proc, Param->GetName()); } else if (Param->IsOptional() && Param->IsParamWithValue()) { BCSYM_Expression *OptionalValue = Param->PParamWithValue()->GetExpression(); if (OptionalValue && // SByte, UInt16, Uint32, Uint64 constants are not CLS compliant // (OptionalValue->GetValue().TypeCode == t_i1 || OptionalValue->GetValue().TypeCode == t_ui2 || OptionalValue->GetValue().TypeCode == t_ui4 || OptionalValue->GetValue().TypeCode == t_ui8)) { ReportErrorOnSymbol( WRNID_OptionalValueNotCLSCompliant1, Param->PParamWithValue()->GetExpression()->HasLocation() ? (BCSYM *)Param->PParamWithValue()->GetExpression() : Param, Proc, Param->GetName()); } } } VerifyOverloadsForCLSCompliance(Proc); VerifyConstraintsAreCLSCompliant(Proc); }