/***************************************************************************** ;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()); } }
/************************************************************************************************** ;ValidateWithEventsVar Makes sure the WithEvents var sources at least one visible non-shared event. Also checks to make sure the type behind the WithEvents var is a class/interface ***************************************************************************************************/ bool // true - WithEvents var is good Bindable::ValidateWithEventsVar ( BCSYM_Variable *WithEventsVar ) { // We don't want to mark withevents variables in references assemblies as bad // because we want users to be able to use these withevents variables at least // in non-withevents context if (WithEventsVar->IsBad()) { return false; } VSASSERT( WithEventsVar->GetType(), "How can a withevents variable not have atleast a bad type ?"); if (WithEventsVar->GetType()->IsBad()) { WithEventsVar->SetIsBad(); // Also, indicate that the problem here is with a type of the with events variable. // WithEventsVar->PVariable()->SetIsBadVariableType(true); return false; } BCSYM *TypeOfWithEventsVar = WithEventsVar->GetType(); // The type of a WITHEVENTS variable must be either a // - a type parameter with a class constraint or // - class or an interface, // if (!IsClassOrInterface(TypeOfWithEventsVar) && !(TypeOfWithEventsVar->IsGenericParam() && TypeOfWithEventsVar->PGenericParam()->IsReferenceType())) { ReportErrorOnSymbol( ERRID_WithEventsAsStruct, CurrentErrorLog(WithEventsVar), // Intrinsic types don't have locations, so report error on the withevents var itself // WithEventsVar->GetRawType()->IsNamedType()? WithEventsVar->GetRawType() : WithEventsVar); // Indicate that the problem here is with the type of the withevents variable, but don't // mark the variable itself as completely bad because we still want the user to be able // to use it like a normal variable. // WithEventsVar->PVariable()->SetIsBadVariableType(true); return false; } // The WithEvents variable must source at least one non-shared event that is visible // to the container in which it is defined. // // Errors are no longer reported for this scenario. - see bug VSWhidbey 542456. // Because of this CheckForAccessibleEvents is no longer required, but this indirectly/subtly // results in calls to ResolveShadowingOverloadingAndOverridingForContainer, // ----AttributesOnAllSymbolsInContainer and other such tasks in bindable which later consumers // of these withevent variable might be dependent on. So to minimize code churn and risk for // whidbey, not removing this call. ----AttributesOnAllSymbolsInContainer is infact known to // be required for withevents of interfaces with the CoClass attributes. // // bool AccessibilityIssue = false; CheckForAccessibleEvents( TypeOfWithEventsVar, // Consider EventSource properties too as being accessible events true, AccessibilityIssue); return true; }