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)); } } }
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 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(); }