/***************************************************************************** ;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 Bindable::ValidateWithEventsVarsInHandlesListsAndSynthesizePropertiesIfRequired() { BCSYM_Container *ContainerOfHandlingMethods = CurrentContainer(); if (!IsClass(ContainerOfHandlingMethods) && !IsStructure(ContainerOfHandlingMethods) && !IsStdModule(ContainerOfHandlingMethods)) { return; } Symbols SymbolFactory( CurrentCompilerInstance(), CurrentAllocator(), NULL, CurrentGenericBindingCache()); BCITER_CHILD Members(ContainerOfHandlingMethods); while(BCSYM_NamedRoot *Member = Members.GetNext()) { // only method implementations can have handles clauses if (!Member->IsMethodImpl()) { continue; } BCSYM_Proc *Proc = Member->PProc(); BCITER_Handles iterHandles(Member->PMethodImpl()); BCSYM_HandlesList *Handles = iterHandles.GetNext(); if (!Handles) { continue; } ErrorTable *ErrorLog = CurrentErrorLog(Proc); for(; Handles; Handles = iterHandles.GetNext()) { if (Handles->IsMyBase() || Handles->IsEventFromMeOrMyClass()) { continue; } bool FoundInBase; BCSYM_Variable *WithEventsVar = GetWithEventsVarReferredToInHandlesClause( Handles, FoundInBase); if (!WithEventsVar) { // "Handles clause requires a WithEvents variable." ReportErrorAtLocation( ERRID_NoWithEventsVarOnHandlesList, ErrorLog, Handles->GetLocationOfWithEventsVar()); Handles->SetIsBad(); } else if (WithEventsVar->IsBad() || WithEventsVar->IsBadVariableType() || // the type of the variable is good, but is not a class or interface WithEventsVar->GetType()->IsBad()) // the type of the variable is bad { // Any metadata errors on a symbol should be reported at the location // the symbol is used in source code // if (DefinedInMetaData(WithEventsVar->GetContainer())) { VSASSERT( !DefinedInMetaData(CurrentContainer()), "How can Current Context for handles clauses not be in VB Source Code ?!"); WithEventsVar->ReportError( CurrentCompilerInstance(), ErrorLog, Handles->GetLocationOfWithEventsVar()); } Handles->SetIsBad(); } else { // get the withevents property if possible BCSYM_Property *WithEventsProperty = GetWithEventsPropertyForWithEventsVariable(WithEventsVar->PVariable()); // Create it if it doesn't exist (for handling events defined on // WithEvent vars that exist on a base class). // if (!WithEventsProperty) { VSASSERT(FoundInBase, "Why do we have to synthesize a property for a withevents variable in the current class ? It should already have been synthesized in declared!!"); WithEventsProperty = SynthesizeWithEventsProperty(WithEventsVar->PVariable(), SymbolFactory); WithEventsProperty->SetCreatedByHandlesClause(Handles); } Handles->SetWithEventsProperty(WithEventsProperty); } } } }
BCSYM_Property* Bindable::SynthesizeWithEventsProperty ( BCSYM_Variable *WithEventsVar, Symbols &SymbolFactory ) { VSASSERT(CurrentContainer()->IsClass(), "why would a non-class need to synthesize withevents properties ?"); BCSYM_Class *Class = CurrentContainer()->PClass(); BCSYM_Property *WithEventsProperty; WithEventsProperty = Declared::BuildWithEventsProperty( WithEventsVar->PVariable(), DeriveGenericBindingForMemberReference( IsGenericOrHasGenericParent(CurrentContainer()) ? (BCSYM *)SynthesizeOpenGenericBinding(Class, SymbolFactory) : CurrentContainer(), WithEventsVar, SymbolFactory, CurrentCompilerHost()), &SymbolFactory, // note to GenSyntheticCode() that generated code should call the base class. // Always safe because we only get here if we tried to handle an event that // was defined in a base class of the current one // true, Class->IsStdModule(), CurrentCompilerInstance(), NULL, // No symbols list to put the property in, we put it in the hash manually below NULL); // No symbols list to put the get, set in, we put it in the hash manually below WithEventsProperty->SetMemberThatCreatedSymbol(WithEventsVar); WithEventsProperty->GetProperty()->SetMemberThatCreatedSymbol(WithEventsVar); WithEventsProperty->SetProperty()->SetMemberThatCreatedSymbol(WithEventsVar); // Add the Property to the container's hash // Symbols::AddSymbolToHash( Class->GetHash(), WithEventsProperty, true, // set the parent of this member Class->IsStdModule(), false); // container is not namespace VSASSERT( Class->GetUnBindableChildrenHash(), "How can a class not have an unbindable members hash ?"); // Add the get accessor of the Property to the container's unbindable members hash // Symbols::AddSymbolToHash( Class->GetUnBindableChildrenHash(), WithEventsProperty->GetProperty(), true, // set the parent of this member Class->IsStdModule(), false); // container is not namespace // Add the set accessor of the Property to the container's unbindable members hash // Symbols::AddSymbolToHash( Class->GetUnBindableChildrenHash(), WithEventsProperty->SetProperty(), true, // set the parent of this member Class->IsStdModule(), false); // container is not namespace #if IDE // Add these to the list of symbols created in bindable. // This list is used to delete these from their respective hashes during decompilation // from bindable. // SymbolFactory.GetAliasOfSymbol( WithEventsProperty, ACCESS_Private, CurrentContainer()->GetBindableSymbolList()); SymbolFactory.GetAliasOfSymbol( WithEventsProperty->GetProperty(), ACCESS_Private, CurrentContainer()->GetBindableSymbolList()); SymbolFactory.GetAliasOfSymbol( WithEventsProperty->SetProperty(), ACCESS_Private, CurrentContainer()->GetBindableSymbolList()); #endif return WithEventsProperty; }
void ComClassMembersInAContainer::Init ( BCSYM_Container *pContainer ) { // Free the memory. m_nra.FreeHeap(); if (pContainer != NULL) { BCITER_CHILD bichild(pContainer); unsigned cMembers = 0; BCSYM_NamedRoot *pRoot; BCSYM_NamedRoot **ppRoot; while (pRoot = bichild.GetNext()) { if (!Filter(pRoot)) continue; cMembers++; if (pRoot->IsProperty()) { BCSYM_Property *pProperty = pRoot->PProperty(); if (pProperty->GetProperty() && Filter(pProperty->GetProperty())) { cMembers++; } if (pProperty->SetProperty() && Filter(pProperty->SetProperty())) { cMembers++; } } } IfFalseThrow(cMembers + 1 > cMembers); ppRoot = m_ppRoot = m_ppNext = (BCSYM_NamedRoot **)m_nra.Alloc(VBMath::Multiply( (cMembers + 1), sizeof(BCSYM_NamedRoot *))); m_count = cMembers; bichild.Init(pContainer); while (pRoot = bichild.GetNext()) { if (!Filter(pRoot)) continue; *ppRoot = pRoot; ppRoot++; if (pRoot->IsProperty()) { BCSYM_Property *pProperty = pRoot->PProperty(); if (pProperty->GetProperty() && Filter(pProperty->GetProperty())) { *ppRoot = pProperty->GetProperty(); ppRoot++; } if (pProperty->SetProperty() && Filter(pProperty->SetProperty())) { *ppRoot = pProperty->SetProperty(); ppRoot++; } } } // Sort the list in slot number then file definition order. extern int _cdecl SortSymbolsByLocation(const void *arg1, const void *arg2); qsort(m_ppNext, ppRoot - m_ppNext, sizeof(BCSYM_NamedRoot *), SortSymbolsByLocation); } else { m_count = 0; m_ppNext = NULL; m_ppRoot = NULL; } }