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); } } } }
/***************************************************************************** ;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()); } }
bool CLSComplianceChecker::IsTypeCLSCompliant( BCSYM * RawType, BCSYM_NamedRoot * NamedContext) { BCSYM *ActualType = RawType->ChaseToType(); if (!ActualType || (ActualType->IsNamedRoot() && ActualType->PNamedRoot()->IsBadNamedRoot())) { return true; } // Return true for generic params because its constraints are anyway verified separately // if (ActualType->IsGenericParam()) { return true; } VSASSERT( ActualType->IsContainer(), "What else can a chased type be ?"); if (ActualType->IsGenericBinding()) { NameTypeArguments **RawTypeArgumentsSets = RawType->IsNamedType() ? RawType->PNamedType()->GetArgumentsArray() : NULL; unsigned CountOfRawTypeArgumentsSets = RawType->IsNamedType() ? RawType->PNamedType()->GetNameCount() : 0; NameTypeArguments *CurrentRawTypeArgumentsSet = NULL; unsigned CurrentRawTypeArgumentsSetIndex = CountOfRawTypeArgumentsSets; for(BCSYM_GenericTypeBinding *GenericBinding = ActualType->PGenericTypeBinding(); GenericBinding; GenericBinding = GenericBinding->GetParentBinding()) { if (RawTypeArgumentsSets && CurrentRawTypeArgumentsSetIndex > 0) { CurrentRawTypeArgumentsSet = RawTypeArgumentsSets[--CurrentRawTypeArgumentsSetIndex]; if (CurrentRawTypeArgumentsSet && CurrentRawTypeArgumentsSet->m_BoundGenericBinding != GenericBinding) { // Lost the one to one mapping between actual type and raw type, so // invalidate and do not use the raw type argument locations. CurrentRawTypeArgumentsSet = NULL; } } unsigned GenericArgumentCount = GenericBinding->GetArgumentCount(); for(unsigned Index = 0; Index < GenericArgumentCount; Index++) { BCSYM *ArgumentType = GenericBinding->GetArgument(Index); if (!IsTypeCLSCompliant(ArgumentType, NamedContext)) { Location *ErrorLocation = NULL; if (CurrentRawTypeArgumentsSet && CurrentRawTypeArgumentsSet->m_ArgumentCount > 0) { ErrorLocation = CurrentRawTypeArgumentsSet->GetArgumentLocation(Index); } if (!ErrorLocation) { ErrorLocation = RawType->IsNamedType() ? RawType->GetLocation() : NamedContext->GetLocation(); } ReportErrorAtLocation( WRNID_TypeNotCLSCompliant1, ErrorLocation, NamedContext, ArgumentType->ChaseToType()->GetErrorName(m_Compiler)); } } } return IsTypeCLSCompliant(ActualType->PGenericTypeBinding()->GetGeneric(), NamedContext); } return ActualType->PContainer()->IsCLSCompliant(); }