void CLSComplianceChecker::VerifyConstraintsAreCLSCompliant(BCSYM_NamedRoot * ContainerOrProc) { VSASSERT(ContainerOrProc->IsContainer() || ContainerOrProc->IsProc(), "Symbol kind unexpected during generic constraint CLS compliance checking!!!"); // Check the Generic parameter constraint types too for CLS Compliance. // If not a generic type or method, it will not have any generic // parameters. for(BCSYM_GenericParam *GenericParam = ContainerOrProc->GetFirstGenericParam(); GenericParam; GenericParam = GenericParam->GetNextParam()) { for (BCSYM_GenericTypeConstraint *Constraint = GenericParam->GetTypeConstraints(); Constraint; Constraint = Constraint->Next()) { BCSYM *ConstraintType = Constraint->GetRawType(); if (IsTypeCLSCompliant(ConstraintType, GenericParam)) { continue; } ReportErrorOnSymbol( WRNID_GenericConstraintNotCLSCompliant1, Constraint, GenericParam, ConstraintType->ChaseToType()->GetErrorName(m_Compiler)); } } }
BCSYM* Bindable::BasesIter::GetFirst() { BCSYM *Base = NULL; m_LinkToCurrentBase = NULL; if (m_ClassOrInterface->IsClass()) { Base = m_ClassOrInterface->PClass()->GetBaseClass(); if (Base && (Base->IsBad() || !Base->IsClass())) { Base = NULL; } } else if (m_ClassOrInterface->IsInterface()) { m_LinkToCurrentBase = m_ClassOrInterface->PInterface()->GetFirstImplements(); Base = GetBaseInterface(m_LinkToCurrentBase); } return Base; }
BCSYM_Container* Bindable::BasesIter::GetNextBase ( BCSYM_GenericTypeBinding **BaseGenericBinding ) { BCSYM *Base; if (!m_IteratorStarted) { m_IteratorStarted = true; Base = GetFirst(); } else { Base = GetNext(); } if (BaseGenericBinding) { if (Base && Base->IsGenericTypeBinding()) { *BaseGenericBinding = Base->PGenericTypeBinding(); } else { *BaseGenericBinding = NULL; } } return Base->PContainer(); }
void CLSComplianceChecker::VerifyBasesForCLSCompliance(BCSYM_Container * Container) { VSASSERT( Container->IsCLSCompliant(), "Non-CLS compliant container unexpected!!!"); if (Container->IsClass()) { BCSYM *RawBaseType = Container->PClass()->GetRawBase(); // Report an error if this inherited class is not compliant. // if (!IsTypeCLSCompliant(RawBaseType, Container)) { ReportErrorOnSymbol( WRNID_BaseClassNotCLSCompliant2, Container, Container->GetName(), RawBaseType->ChaseToType()->GetErrorName(m_Compiler)); } } else if (Container->IsInterface()) { for (BCSYM_Implements *Impl = Container->PInterface()->GetFirstImplements(); Impl; Impl = Impl->GetNext()) { if (Impl->IsBad()) { continue; } BCSYM *RawBaseType = Impl->GetRawRoot(); // Report an error if this inherited interface is not compliant. // if (!IsTypeCLSCompliant(RawBaseType, Container)) { ReportErrorOnSymbol( WRNID_InheritedInterfaceNotCLSCompliant2, Container, Container->GetName(), RawBaseType->ChaseToType()->GetErrorName(m_Compiler)); } } } }
bool TypeExtensionIterator::MoveNext() { BCSYM_NamedRoot * pNamed = NULL; do { pNamed = m_childIterator.GetNext(); if (pNamed && pNamed->IsContainer()) { BCSYM_Container *pContainer = pNamed->PContainer(); // Perf: We are only interested in looking at types marked as containing extension methods. So only load the // type's children if the type says it contains extension methods. BCSYM *pContainerAfterDiggingThroughAlias = pContainer->DigThroughAlias(); if (pContainerAfterDiggingThroughAlias->IsClass()) { if (pContainerAfterDiggingThroughAlias->PClass()->ContainsExtensionMethods()) { pContainer->EnsureChildrenLoaded(); } } else if (!pContainer->GetCompilerFile() || (pContainer->GetCompilerFile()->IsMetaDataFile() && pContainer->GetCompilerFile()->ContainsExtensionMethods())) { pContainer->EnsureChildrenLoaded(); } } } while (pNamed && ! pNamed->IsTypeExtension()); if (pNamed) { m_pCurrent = pNamed->PClass(); } else { m_pCurrent = NULL; } return m_pCurrent; }
void CLSComplianceChecker::VerifyEnumUnderlyingTypeForCLSCompliance(BCSYM_Container * PossibleEnum) { VSASSERT( PossibleEnum->IsCLSCompliant(), "Non-CLS compliant container unexpected!!!"); if (!PossibleEnum->IsEnum()) { return; } BCSYM *UnderlyingType = PossibleEnum->PClass()->GetUnderlyingTypeForEnum(); if (!IsTypeCLSCompliant(UnderlyingType, PossibleEnum)) { // Underlying type '|1' of enum is not CLS Compliant. ReportErrorOnSymbol( WRNID_EnumUnderlyingTypeNotCLS1, PossibleEnum, UnderlyingType->GetErrorName(m_Compiler)); } }
BCSYM* Bindable::BasesIter::GetBaseInterface ( BCSYM_Implements *&LinkToBase ) { BCSYM *Base = NULL; do { do { if (!LinkToBase) { return NULL; } if (!LinkToBase->IsBad()) { break; } LinkToBase = LinkToBase->GetNext(); } while(true); Base = LinkToBase->GetInterfaceIfExists(); if (Base && !Base->IsBad()) { break; } LinkToBase = LinkToBase->GetNext(); } while(true); return Base; }
/***************************************************************************** ;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 // true - there are events defined on the WithEvents variable AND they are visible to ContainerOfWithEventsVar Bindable::CheckForAccessibleEvents ( BCSYM *TypeOfWithEventsVar, bool ConsiderEventSourcePropertiesToo, bool &AnyEventDefined ) { // Note: the calling function is expected to initialize AnyEventDefine to false. // We don't do this here because the function is recursive. if (TypeOfWithEventsVar->IsBad()) { // This has the effect of sometimes missing an event def we could have found had we not punted. // But does it make sense to dig into an interface that is junk? return false; } BCSYM *TypePossiblyContainingEvents; if (TypeOfWithEventsVar->IsGenericParam()) { TypePossiblyContainingEvents = GetClassConstraint( TypeOfWithEventsVar->PGenericParam(), CurrentCompilerHost(), CurrentAllocator(), true, // ReturnArraysAs"System.Array" true // ReturnValuesAs"System.ValueType"or"System.Enum" ); // See if there are any events in the class constraint // // Note that the class constraint needs to be checked separately to // preserve the shadowing semantics for the events found. // if (TypePossiblyContainingEvents && !TypePossiblyContainingEvents->IsBad() && CheckForAccessibleEventsInContainer( TypePossiblyContainingEvents, TypeOfWithEventsVar, ConsiderEventSourcePropertiesToo, AnyEventDefined)) { return true; } VSASSERT(TypePossiblyContainingEvents || TypeOfWithEventsVar->PGenericParam()->IsReferenceType(), "Unexpected withevents type!!!"); // See if there are any events in the Interface constraints BCITER_Constraints ConstraintsIter(TypeOfWithEventsVar->PGenericParam(), true, CurrentCompilerInstance()); while (BCSYM_GenericConstraint *Constraint = ConstraintsIter.Next()) { VSASSERT(!Constraint->IsBadConstraint(), "Bad constraint unexpected!!!"); if (!Constraint->IsGenericTypeConstraint()) { continue; } TypePossiblyContainingEvents = Constraint->PGenericTypeConstraint()->GetType(); if (!TypePossiblyContainingEvents || TypePossiblyContainingEvents->IsBad() || !TypePossiblyContainingEvents->IsInterface()) { continue; } if (CheckForAccessibleEventsInContainer( TypePossiblyContainingEvents, TypeOfWithEventsVar, ConsiderEventSourcePropertiesToo, AnyEventDefined)) { return true; } } return false; } else { TypePossiblyContainingEvents = TypeOfWithEventsVar; return CheckForAccessibleEventsInContainer( TypePossiblyContainingEvents, TypeOfWithEventsVar, ConsiderEventSourcePropertiesToo, AnyEventDefined); } return false; }
BCSYM_Property* Bindable::GetEventSourceProperty ( BCSYM *TypeOfWithEventsVar, _In_z_ STRING *PropertyName ) { // Need to find a property that sources an event // To handle events on subobjects, (internal use only), you must supply a Class // type for the WithEvents variable. But for completeness with respect to generics, // adding support type parameters with class constraints too. BCSYM *TypeToFindEventSourcePropertyIn; if (TypeOfWithEventsVar->IsGenericParam()) { // TypeToFindEventSourcePropertyIn = GetClassConstraint( TypeOfWithEventsVar->PGenericParam(), CurrentCompilerHost(), CurrentAllocator(), false, // don't ReturnArraysAs"System.Array" true // ReturnValuesAs"System.ValueType"or"System.Enum" ); } else { TypeToFindEventSourcePropertyIn = TypeOfWithEventsVar; } if (!TypeToFindEventSourcePropertyIn || !TypeToFindEventSourcePropertyIn->IsClass()) { return NULL; } // ---- attributes on all symbols in the TypeOfWithEventsVar container. This is needed // in order to verify if a property is an EventSource which is determined by // an attribute on the property. // ----AttributesOnAllSymbolsInContainer(TypeToFindEventSourcePropertyIn->PClass(), m_CompilationCaches); BCSYM_NamedRoot *Property = TypeToFindEventSourcePropertyIn->PClass()->SimpleBind(NULL, PropertyName); while (Property && Property->IsProperty()) { if (ValidEventSourceProperty(Property->PProperty()) && IsAccessible( Property->PProperty()->GetProperty(), TypeToFindEventSourcePropertyIn->IsGenericBinding() ? TypeToFindEventSourcePropertyIn->PGenericBinding() : NULL, CurrentContainer(), TypeOfWithEventsVar)) { return Property->PProperty(); // found it } Property = Property->GetNextOfSameName(); // Note: // - we don't support finding the Property if it is overloaded // across classes. // - Also note that we don't support digging into bases. This was // how the previous impl. was. // Given that this is not a user feature, we don't bother doing // this extra work. } return NULL; }
/************************************************************************************************** ;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; }
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(); }
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); }