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