void CLSComplianceChecker::ValidateNonCLSCompliantMemberInCLSCompliantContainer( BCSYM_NamedRoot * Member, BCSYM_Container * ParentOfMember) { VSASSERT( ParentOfMember->IsCLSCompliant(), "Members of non-CLS compliant types unexpected!!!"); // VSASSERT( Member->IsMember(), "Non-member unexpected!!!"); if (ParentOfMember->IsInterface()) { // Non CLS compliant |1 is not allowed in a CLS compliant interface. ReportErrorOnSymbol( WRNID_NonCLSMemberInCLSInterface1, Member, StringOfSymbol(m_Compiler, Member)); } else if (Member->IsProc() && Member->PProc()->IsMustOverrideKeywordUsed()) { // Non CLS compliant mustoverride member is not allowed in a CLS compliant |1. ReportErrorOnSymbol( WRNID_NonCLSMustOverrideInCLSType1, Member, StringOfSymbol(m_Compiler, ParentOfMember)); } }
Location* Bindable::BindableMemberInfo::GetLocationToReportError() { if (SourceOfSyntheticMember) { if (syntheticContext == HandlesOfBaseWithEvents) { if (Member->IsProperty()) { if (Member->PProperty()->CreatedByHandlesClause()) { return Member->PProperty()->CreatedByHandlesClause()->GetLocationOfWithEventsVar(); } } else { VSASSERT( Member->IsSyntheticMethod(), "What other members can be synthesized for handling a base withevents ?"); VSASSERT( Member->PProc()->GetAssociatedPropertyDef(), "what other synthetic method besides a Propety_Get and a Property_Set can be synthesized for handling a base withevents?"); if (Member->PProc()->GetAssociatedPropertyDef()->CreatedByHandlesClause()) { return Member->PProc()->GetAssociatedPropertyDef()-> CreatedByHandlesClause()->GetLocationOfWithEventsVar(); } } } return SourceOfSyntheticMember->GetLocation(); } return Member->GetLocation(); }
/********** *TemporaryManager::FreeTemporary * Frees one temporary indicating that it is not required. ***********/ void TemporaryManager::FreeTemporary ( BCSYM_Variable *TemporaryToDelete ) { VSASSERT(TemporaryToDelete->IsTemporary(), "Temporary expected!!!"); // Find the temporary and decrement its use count. for (Temporary *Cursor = m_Temporaries; Cursor; Cursor = Cursor->Next) { VSASSERT(Cursor->Symbol, "this temporary doesn't have a symbol!"); if (Cursor->Symbol == TemporaryToDelete) { VSASSERT(Cursor->UseCount != 0, "Inconsistency in temporary variable allocations!!!"); Cursor->UseCount--; if (Cursor->UseCount == 0) { Cursor->IsCurrentlyInUse = false; } break; } } }
BCSYM_Proc* Bindable::SynthesizeConstructor ( bool SynthesizeSharedConstructor ) { VSASSERT(CurrentContainer()->IsClass(), "why would a non-class need to synthesize constructors ?"); BCSYM_Class *Class = CurrentContainer()->PClass(); Symbols SymbolAllocator( CurrentCompilerInstance(), CurrentAllocator(), NULL, CurrentGenericBindingCache()); Declared::SyntheticConstructorTypeEnum makeWhat = Declared::SyntheticConstructorType::Instance; if (SynthesizeSharedConstructor) { makeWhat = Declared::SyntheticConstructorType::Shared; } else if (Class->IsMustInherit()) { makeWhat = Declared::SyntheticConstructorType::MustInherit; } BCSYM_Proc *Constructor = Declared::BuildSyntheticConstructor( &SymbolAllocator, CurrentCompilerInstance(), NULL, makeWhat); // No Symbol list to add this symbol to // We will add it manually to the hash VSASSERT( Constructor, "Unexpected failure in synthesizing constructor"); // Add the Consatructor to the container's hash // Symbols::AddSymbolToHash( Class->GetHash(), Constructor, true, // set the parent of this member Class->IsStdModule(), false); // container is not namespace #if IDE // Add this to the list of symbols created in bindable. // This list is used to delete these from their respective // hashes during decompilation from bindable. // SymbolAllocator.GetAliasOfSymbol( Constructor, ACCESS_Private, CurrentContainer()->GetBindableSymbolList()); #endif return Constructor; }
void CLSComplianceChecker::VerifyOverloadsForCLSCompliance(BCSYM_Proc * PossiblyOverloadedProc) { // Check the Overloads for overloading by Array Rank or // overloading on Array of Arrays // we don't allow bad members because they could have // been bad during overloads verification in bindable. // VSASSERT( !PossiblyOverloadedProc->IsBad(), "Bad members unexpected!!!"); if (!Bindable::IsMethod(PossiblyOverloadedProc) && !Bindable::IsProperty(PossiblyOverloadedProc)) { return; } for(BCSYM_NamedRoot *NextPossibleOverload = PossiblyOverloadedProc->GetNextOverload(); NextPossibleOverload; NextPossibleOverload = NextPossibleOverload->GetNextOverload()) { VSASSERT( NextPossibleOverload->IsProc(), "How can a non-proc be involved in overloads ?"); BCSYM_Proc *NextOverload = NextPossibleOverload->PProc(); if (!IsAccessibleOutsideAssembly(NextOverload)) { continue; } VerifyOverloadsForCLSCompliance( PossiblyOverloadedProc, NextOverload); } // }
bool Bindable::CheckForAccessibleEventsInContainer ( BCSYM *TypePossiblyContainingEvents, 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. VSASSERT(TypePossiblyContainingEvents && TypePossiblyContainingEvents->IsContainer(), "Non-container unexpected!!!"); // will hold a list of members marked as Shadowing in here // MembersHashTable ShadowingMembers; // Resolve shadowing etc. for the type of the withevents variable before looking for accessible events in it ResolveShadowingOverloadingOverridingAndCheckGenericsForContainer(TypePossiblyContainingEvents->PContainer(), m_CompilationCaches); return CheckForAccessibleEventsWorker( TypePossiblyContainingEvents, TypeOfWithEventsVar, &ShadowingMembers, ConsiderEventSourcePropertiesToo, AnyEventDefined); }
int __cdecl SortSymbolsByNameAndExternalAccess ( const void *arg1, const void *arg2 ) { BCSYM_NamedRoot *Member1 = *(BCSYM_NamedRoot **)arg1; BCSYM_NamedRoot *Member2 = *(BCSYM_NamedRoot **)arg2; VSASSERT(Member1 && Member2, "How can the symbols be compared be NULL?"); // We add locations to all members imported from COM typelibs, since we may need the ordering data later if we // need to embed No-PIA local types. In other situations, we expect that metadata members do not have locations. // Exception: as per the comment in MetaData::ImportChildren, we also get locations for members from PIAs. AssertIfTrue(Member1->HasLocation() && !Member1->GetContainingProject()->GetAssemblyIdentity()->IsImportedFromCOMTypeLib() && !Member1->GetContainingProject()->GetAssemblyIdentity()->IsPrimaryInteropAssembly()); AssertIfTrue(Member2->HasLocation() && !Member2->GetContainingProject()->GetAssemblyIdentity()->IsImportedFromCOMTypeLib() && !Member2->GetContainingProject()->GetAssemblyIdentity()->IsPrimaryInteropAssembly()); // First sort by name. int i = SortSymbolsByName(arg1, arg2); // Now sort by access external to this assembly. if (i == 0) { #pragma prefast(suppress: 26010 26011, "If access is outside of the array limits, then the whole symbol is busted") i = MapAccessToAccessOutsideAssembly[Member1->GetAccess()] - MapAccessToAccessOutsideAssembly[Member2->GetAccess()]; } return i; }
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 Location::SetLocation ( _In_ const Location * pNewLocation // the location to copy ) { VSASSERT( pNewLocation, "You can't pass NULL to SetLocation( Location *)"); *this = *pNewLocation; }
bool CLSComplianceChecker::IsAccessibleOutsideAssembly(BCSYM_NamedRoot * Member) { // Namespaces are always public // if (Member->IsNamespace()) { return true; } ACCESS AccessOfMember = Member->GetAccess(); if (AccessOfMember == ACCESS_Private || AccessOfMember == ACCESS_Friend) { return false; } if (AccessOfMember == ACCESS_Protected || AccessOfMember == ACCESS_ProtectedFriend) { BCSYM_Container *ContainerOfMember = Member->GetContainer(); VSASSERT( ContainerOfMember, "How can a non-namespace entity not be enclosed in another container ?"); // If the containing class is notinheritable, then the protected members are // not accessible outside the assembly since nobody can inherit the class. // // Confirmed this with [....] and jsmiller // if (ContainerOfMember->IsClass() && ContainerOfMember->PClass()->IsNotInheritable()) { return false; } return true; } VSASSERT( AccessOfMember == ACCESS_Public, "What else can the access be ?"); return true; }
void CLSComplianceChecker::VerifyThatMembersAreNotMarkedCLSCompliant(BCSYM_Container * Container) { VSASSERT( !Container->IsCLSCompliant(), "CLS compliant container unexpected!!!"); // Members nested inside Non CLS Compliant Types cannot be // marked as CLS Compliant. // // For Top Level types, it is okay to be marked as CLS Compliant // even though inside a Non-CLS Compliant assembly. // if (Container->IsNamespace()) { return; } BCITER_CHILD Members(Container); while (BCSYM_NamedRoot *Member = Members.GetNext()) { if (Member->IsBad()) { continue; } // If the member is not accessible outside the assembly, then // don't bother checking for CLS compliance // if (!IsAccessibleOutsideAssembly(Member)) { continue; } // Need to do this so that we handle the operators. Operators // do not by themselves show up in this (bindable hash) hash // we are looking in, so we will find them through their functions // instead. // if (Member->IsProc() && Member->PProc()->IsUserDefinedOperatorMethod()) { Member = Member->PProc()->GetAssociatedOperatorDef(); } // We don't want to report errors for synthetic members. // Eg: withevents property, the withevents variable _prop, etc. // If we don't skip errors for these, we would end up reporting // the same errors on both these and the original symbols from // which they were synthesized resulting in duplicate errors. // if (IsSyntheticMember(Member)) { continue; } VerifyMemberNotMarkedCLSCompliant(Member); } }
void* NorlsAllocator::_AllocNonZero(size_t& sz) { AssertIfFalse((size_t)nextFree % sizeof(void*) == 0); AssertIfFalse((size_t)limitFree % sizeof(void*) == 0); void * p = nextFree; if (sz == 0 && p == NULL) { sz = 1; } size_t roundSize = VBMath::RoundUpAllocSize(sz); size_t available = limitFree - nextFree; if ( available < roundSize ) { AllocNewPage(sz); } p = nextFree; nextFree += roundSize; // this shouldn't overflow because we got the memory for the request (we would have thrown in AllocNewPage() otherwise) MakeCurrentPageWriteableInternal(); AssertIfFalse((size_t)nextFree % sizeof(void*) == 0); AssertIfFalse((size_t)limitFree % sizeof(void*) == 0); AssertIfFalse((size_t)p % sizeof(void*) == 0); #if NRLSTRACK m_nTotalAllocated += roundSize; m_dwAllocThreadId = 0; #endif NRLSTRACK sz = roundSize; #if NRLSTRACK VSASSERT(m_dwAllocThreadId == 0," NorlsAlloc: only 1 thread allowed at a time"); m_dwAllocThreadId = GetCurrentThreadId(); m_nSeqNo+=1; #if NRLSTRACK_GETSTACKS // NrlsHeapData *pdata = (NrlsHeapData *) VsDebugAllocInternal(TrackingHeapToUse(), HEAP_ZERO_MEMORY | HEAP_GENERATE_EXCEPTIONS, (sizeof (NrlsHeapData )), __FILE__, __LINE__, INSTANCE_GLOBAL, NULL); pdata->m_ptrNextBlock = m_pLastBlock; // linked list of allocations: point to prior one pdata->m_size = sz; // record the size pdata->m_data = p; // record the actual allocation m_pLastBlock = pdata; // track the most recent one #endif NRLSTRACK_GETSTACKS #endif NRLSTRACK return p; }
/* * Allocate (duplicate) a wide char string. */ PWSTR NorlsAllocator::AllocStr(PCWSTR str) { if (str == NULL) return NULL; size_t str_len = wcslen(str); // integer overflow if (!(str_len < str_len + 1)) { VSASSERT(str_len < str_len + 1, "Invalid"); return NULL; } PWSTR strNew = (PWSTR) Alloc((str_len + 1) * sizeof(WCHAR)); HRESULT hr; hr = StringCchCopyW (strNew, str_len + 1, str); VSASSERT (SUCCEEDED (hr), "Invalid"); return strNew; }
// // CryptHash::GetCryptHash() // caller needs to allocate memory for pvHash based on GetHashSize() // bool CryptHash::GetCryptHash(void *pvHash, DWORD cbHash) const { VSASSERT(cbHash == GetCryptHashSize(),"Wrong hash size"); DWORD cbT = cbHash; bool fSucceed = ::CryptGetHashParam(m_hHash, HP_HASHVAL, PBYTE(pvHash), &cbT, 0); if(!fSucceed) { ::memset(pvHash, 0, cbHash); } return fSucceed; }
int __cdecl SortSymbolsByNameAndOperatorAndLocation ( const void *arg1, const void *arg2 ) { // BCSYM_NamedRoot *Member1 = *(BCSYM_NamedRoot **)arg1; BCSYM_NamedRoot *Member2 = *(BCSYM_NamedRoot **)arg2; VSASSERT(Member1 && Member2, "How can the symbols to be compared be NULL?"); // First sort by name. int i = SortSymbolsByName(arg1, arg2); // Now sort by operator kind. if (i == 0) { bool Member1IsOperator = IsUserDefinedOperator(Member1); bool Member2IsOperator = IsUserDefinedOperator(Member2); if (Member1IsOperator) { if (Member2IsOperator) { UserDefinedOperators Operator1 = Member1->PUserDefinedOperator()->GetOperator(); UserDefinedOperators Operator2 = Member2->PUserDefinedOperator()->GetOperator(); i = (Operator1 == Operator2) ? 0 : (Operator1 > Operator2) ? 1 : -1; } else { i = 1; } } else if (Member2IsOperator) { i = -1; } } if (i == 0) { i = SortSymbolsByLocation(arg1, arg2); } return i; }
bool CLSComplianceChecker::ContainerIsPartOfRootNamespace(BCSYM_Container * Container) { if (!Container->IsNamespace()) { return false; } SourceFile *ContainingSourceFile = Container->GetSourceFile(); VSASSERT( ContainingSourceFile, "Non source container unexpected!!!"); // RootNamespace can be NULL for non-existent files specified in project files // BCSYM_Namespace *RootNamespace = ContainingSourceFile->GetRootNamespace() ? ContainingSourceFile->GetRootNamespace() : ContainingSourceFile->GetUnnamedNamespace(); VSASSERT( RootNamespace, "NULL rootnamespace unexpected!!!"); for(BCSYM_Container *NextContaineraboveRootNamespace = RootNamespace; NextContaineraboveRootNamespace; NextContaineraboveRootNamespace = NextContaineraboveRootNamespace->GetContainer()) { if (NextContaineraboveRootNamespace == Container) { return true; } VSASSERT( !NextContaineraboveRootNamespace->IsSameContainer(Container), "How can there be multiple instances per file for namespaces above the rootnamespace ?"); } return false; }
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)); } } } }
//============================================================================ // Update the tracked locations //============================================================================ void LineMarkerTable::PostNotifyOfEdit( VBTextBuffer * pVBTextBuffer, EditInfoLists * pEditLists, EditCache SingleEdit, bool LastEdit) { VSASSERT(SingleEdit.oAdjust != 0, L"oAdjust should never be 0 inside LineMarkerTable::PostNotifyOfEdit()"); CompilerIdeLock lock(m_lock); // We need to refresh the task list if an error location changes if (m_pSourceFile->GetProject() && m_pSourceFile->GetProject()->GetCompilerTaskProvider() && GetCompilerPackage()) { bool fUpdatedErrors = UpdateTrackedOffsetsAndLocations<ErrorLocation>(m_errorLocations, pVBTextBuffer, pEditLists, SingleEdit, LastEdit); bool fUpdatedOutOfProcBuildErrors = UpdateTrackedOffsetsAndLocations<ErrorLocation>(m_outOfProcBuildErrorLocations, pVBTextBuffer, pEditLists, SingleEdit, LastEdit); if (fUpdatedOutOfProcBuildErrors) { m_pSourceFile->SignalOutOfProcBuildErrorLocationsUpdated(); } if (fUpdatedErrors || fUpdatedOutOfProcBuildErrors) { m_pSourceFile->GetProject()->GetCompilerTaskProvider()->TaskListNeedsRefresh(); GetCompilerSharedState()->RefreshTaskList(); } } // Stop tracking errors we no longer care about (IsInvalid or the force remove flag is set) if (LastEdit) { RemoveInvalidErrorLocations(); } UpdateTrackedOffsetsAndLocations<TrackedLocation>(m_declLocations, pVBTextBuffer, pEditLists, SingleEdit, LastEdit); UpdateTrackedOffsetsAndLocations<TrackedLocation>(m_trackedCodeBlockLocations, pVBTextBuffer, pEditLists, SingleEdit, LastEdit); m_fPreNotified = false; }
CSingleList<Bindable::OperatorInfo> * Bindable::RelationalOperatorPool::CollateUnmatchedOperators() { VSASSERT(!IsCollated, "Collating the pool after it has already been collated!"); #if DEBUG IsCollated = true; #endif CSingleList<OperatorInfo> *Result = new(m_Allocator) CSingleList<OperatorInfo>; Result->Splice(&m_IsTrue); Result->Splice(&m_IsFalse); Result->Splice(&m_Equal); Result->Splice(&m_NotEqual); Result->Splice(&m_Less); Result->Splice(&m_LessEqual); Result->Splice(&m_GreaterEqual); Result->Splice(&m_Greater); return Result; }
//============================================================================ // Check wither this named root is included in this iterator. //============================================================================ bool ComClassMembersInAContainer::Filter ( BCSYM_NamedRoot *pRoot ) { if (pRoot->GetAccess() != ACCESS_Public) return false; // must be Public if (!pRoot->IsProc()) return false; // must be a procedure if (pRoot->IsSyntheticMethod()) return false; // can't be a synthetic method if (pRoot->IsDllDeclare()) return false; // can't be a declare if (pRoot->IsEventDecl()) return false; // can't be an event BCSYM_Proc *pProc = pRoot->DigThroughAlias()->PProc(); if (pProc->IsAnyConstructor()) return false; // can't be a constructor if (pProc->IsShared()) return false; // can't be shared/static bool ComVisible; // can't be <ComVisible(False)> if (pProc->GetPWellKnownAttrVals()->GetCOMVisibleData(&ComVisible) && !ComVisible) return false; if (pProc->IsProperty()) // Can't be a synthetic property (e.g., SYNTH_WithEventsGet) { BCSYM_Proc *pProcGet = pProc->PProperty()->GetProperty(); if (pProcGet != NULL && pProcGet->IsSyntheticMethod()) { return false; } // Check the setter just for sanity. I'm not expecting ever to find a synthetic readonly property. VSASSERT(((pProcGet = pProc->PProperty()->SetProperty()) == NULL) || !pProcGet->IsSyntheticMethod(), "A synthetic readonly property slipped through on a ComClass interface."); } return true; }
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)); } }
void Bindable::RelationalOperatorPool::Add ( UserDefinedOperators Operator, BCSYM_UserDefinedOperator *Symbol ) { VSASSERT(!IsCollated, "Adding to the pool after it has already been collated!"); switch (Operator) { case OperatorIsTrue: AddMatchingOperator(m_IsTrue, m_IsFalse, Symbol); break; case OperatorIsFalse: AddMatchingOperator(m_IsFalse, m_IsTrue, Symbol); break; case OperatorEqual: AddMatchingOperator(m_Equal, m_NotEqual, Symbol); break; case OperatorNotEqual: AddMatchingOperator(m_NotEqual, m_Equal, Symbol); break; case OperatorLess: AddMatchingOperator(m_Less, m_Greater, Symbol); break; case OperatorLessEqual: AddMatchingOperator(m_LessEqual, m_GreaterEqual, Symbol); break; case OperatorGreaterEqual: AddMatchingOperator(m_GreaterEqual, m_LessEqual, Symbol); break; case OperatorGreater: AddMatchingOperator(m_Greater, m_Less, Symbol); break; #if DEBUG case OperatorUNDEF: __fallthrough; case OperatorMAXVALID: __fallthrough; case OperatorNot2: __fallthrough; case OperatorOr2: __fallthrough; case OperatorAnd2: __fallthrough; case OperatorShiftLeft2: __fallthrough; case OperatorShiftRight2: __fallthrough; case OperatorMAX: VSFAIL("unexpected operator kind"); __fallthrough; #endif default: // do nothing break; } }
//----------------------------------------------------------------- static void ScanItem (const CH * pchStart, const CH * pchEnd, HTOK * pk) { if(pchStart == NULL || pk == NULL) { VSASSERT(false,""); return; } HRESULT hr; pk->id = hi_Unknown; pk->pch = (CH*)pchStart; pk->cch = 0; pk->bEnd = false; if (pchStart >= pchEnd) { pk->id = hi_Eof; return; } const CH * pchScan = pchStart; switch (*pchScan) { // case _CH(0): // pk->id = hi_Eof; // break; // // case _CH('\n'): // case _CH('\r'): // pchScan = AdvanceLineBreak((CH*)pchScan); // pk->id = hi_Eol; // break; case _CH('<'): { const CH * pchName; int cch; pchScan++; pk->id = hi_Error; switch (*pchScan) { case _CH('!'): pk->id = hi_Error; pchScan++; while (_CH('>') != *pchScan) { const CH * pch; int cch; SKIPWHITE_RET if (IsAAlpha(*pchScan)) hr = ScanName(pchScan, pchEnd, &pch, &cch); else { switch(*pchScan) { case CH('\''): case CH('"'): hr = ScanValue(pchScan, pchEnd, &pch, &cch); break; case CH('-'): hr = ScanComment(pchScan, pchEnd, &pch, &cch); break; default: hr = S_OK; pch = pchScan; cch = 1; break; } } pchScan = pch + cch; if (FAILED(hr) || (pchScan >= pchEnd)) return; } pk->id = hi_TagSpecial; break; case _CH('%'): // ASP 'tag' pk->id = hi_TagSpecial; do { do { pchScan++; } while ((pchScan < pchEnd) && (_CH('>') != *pchScan)); } while ((pchScan < pchEnd) && (*(pchScan-1) != _CH('%'))); break; case _CH('/'): pk->bEnd = true; pchScan++; break; case _CH('?'): // pk->id = hi_TagSpecial; pchScan++; while ((pchScan < pchEnd) && (_CH('>') != *pchScan)) pchScan++; break; } if (pk->id != hi_TagSpecial) { pk->id = hi_Error; SKIPWHITE_RET if (!IsAAlpha(*pchScan)) return; pchName = pchScan; while ((pchScan < pchEnd) && IsAAlNum(*pchScan)) pchScan++; if (pchScan >= pchEnd) return; cch = (int)(pchScan - pchName); if (cch <= cchMaxTag && cch > 0) { CH * pszName = (CH*)_alloca((cch+1)*CBCH ); strcchcopy(pszName, cch+1, pchName); pk->id = LookupElement(pszName); } else return; if (!pk->bEnd) { // scan attributes and comments for(;;) { HATT hatt; HRESULT hr = ScanAttribute(pchScan, pchEnd, &hatt); if (FAILED(hr)) { pk->id = hi_Error; return; } if (S_FALSE == hr) break; pchScan = hatt.pchValue ? hatt.pchValue + hatt.cchValue : hatt.pchName + hatt.cchName; } } } // Skip over whitespace and, if this is an empty element, the closing '/' (e.g. "<foo ... />") while ((pchScan < pchEnd) && ((*pchScan <= 32) || (*pchScan == _CH('/')))) pchScan++; if ((pchScan >= pchEnd) || (_CH('>') != *pchScan)) pk->id = hi_Error; pchScan++; } break; // case _CH('&'): // pk->id = hi_Entity; // if (!ScanEntity(pchScan, &pk->ch, &pchScan)) // goto L_Text; // break; default: //L_Text: pk->id = hi_Text; for (bool f = true; f && (pchScan < pchEnd); ) { switch (*pchScan) { // case _CH(0): // case _CH('\n'): // case _CH('\r'): // case _CH('&'): case _CH('<'): f = false; break; default: pchScan++; break; } } break; }
//----------------------------------------------------------------- // FindAttribute - Find a specific attribute // // Returns: // S_OK Found Attribute // S_FALSE Attribute not found // E_FAIL Syntax error // static HRESULT FindAttribute (const CH * pchTag, const CH *pchEnd, const CH * pszAName, const CH **ppchVal, int * pcchVal) { if(pchTag == NULL || pszAName == NULL || *pszAName == NULL) { VSASSERT(false,""); return E_INVALIDARG; } HRESULT hr; const CH * pch; int cch; int cchAttIn = slen(pszAName); const CH * pchScan = pchTag; const CH * pchVal = 0; *ppchVal = 0; *pcchVal = 0; if (*pchScan == _CH('<')) pchScan++; // don't look in ! tags or end tags if (*pchScan == _CH('!') || *pchScan == _CH('/') || *pchScan == _CH('?')) return S_FALSE; SKIPWHITE_FAIL hr = ScanName(pchScan, pchEnd, &pch, &cch); if (FAILED(hr)) return E_FAIL; pchScan = pch + cch; if (pchScan >= pchEnd) return S_FALSE; // no attributes for(;;) { HATT hatt; HRESULT hr = ScanAttribute(pchScan, pchEnd, &hatt); if (FAILED(hr)) return E_FAIL; if (S_FALSE == hr) break; pchScan = hatt.pchValue ? hatt.pchValue + hatt.cchValue : hatt.pchName + hatt.cchName; if (!hatt.pchName || !hatt.cchName) continue; // comment if ((cchAttIn == hatt.cchName) && (0 == icmpn(hatt.pchName, pszAName, cchAttIn))) { /// strip quotes, if any CH ch = *hatt.pchValue; if (ch == _CH('"') || ch == _CH('\'')) { VSASSERT(ch == hatt.pchValue[hatt.cchValue-1],""); hatt.pchValue++; hatt.cchValue -= 2; } // done! *ppchVal = hatt.pchValue; *pcchVal = hatt.cchValue; return S_OK; } } return S_FALSE; }
/***************************************************************************** ;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()); } }
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; }
BCSYM_Variable* Bindable::BindWithEventsVariable ( _In_z_ STRING *WithEventVarName, bool &InAccessible, bool &WithEventsVarFoundInBase ) { InAccessible = false; WithEventsVarFoundInBase = false; VSASSERT( CurrentContainer()->IsClass(), "How can a non-class have handles clauses ?"); BCSYM_Class *Class = CurrentContainer()->PClass(); bool IsShadowed = false; BCSYM_NamedRoot *Member; for(Member = Class->SimpleBind(NULL, WithEventVarName); Member; Member = Member->GetNextOfSameName()) { if (Member->IsVariable() && Member->PVariable()->GetVarkind() == VAR_WithEvents) { return Member->PVariable(); } // Ignore synthesized properties in checking for shadowing. if (!Member->CreatedByWithEventsDecl() || !Member->IsProperty()) { IsShadowed = true; } } for(BCSYM_Class *Base = Class->GetCompilerBaseClass(); !IsShadowed && Base; Base = Base->GetCompilerBaseClass()) { for(Member = Base->SimpleBind(NULL, WithEventVarName); Member; Member = Member->GetNextOfSameName()) { if (Member->IsVariable() && Member->PVariable()->GetVarkind() == VAR_WithEvents) { if (IsAccessible(Member)) { WithEventsVarFoundInBase = true; return Member->PVariable(); } InAccessible = true; } else { if (IsAccessible(Member) && // Ignore synthesized properties in checking for shadowing. (!Member->CreatedByWithEventsDecl() || !Member->IsProperty())) { IsShadowed = true; } } } } return NULL; }
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); } } } }
bool Bindable::CheckForAccessibleEventsWorker ( BCSYM *TypePossiblyContainingEvents, BCSYM *TypeOfWithEventsVar, MembersHashTable *ShadowingMembers, bool ConsiderEventSourcePropertiesToo, bool &AnyEventDefined ) { VSASSERT( TypePossiblyContainingEvents->IsContainer(), "Looking for events in non-container unexpected!!!"); // // ---- attributes on all symbols in the EventDecl container. This is needed // in order to verify if a property is an EventSource which is determined by // an attribute on the property. // if (ConsiderEventSourcePropertiesToo) { ----AttributesOnAllSymbolsInContainer(TypePossiblyContainingEvents->PContainer(), m_CompilationCaches); } BCITER_CHILD ContainerIterator; ContainerIterator.Init(TypePossiblyContainingEvents->PContainer()); for(BCSYM_NamedRoot *EventDecl = ContainerIterator.GetNext(); EventDecl != NULL; EventDecl = ContainerIterator.GetNext()) { // Was the event decl we just found shadowed out by somebody on a nearer base class/interface? // if (IsMemberShadowed(EventDecl, ShadowingMembers)) continue; bool IsMemberAccessible = IsAccessible( EventDecl, TypePossiblyContainingEvents->IsGenericBinding() ? TypePossiblyContainingEvents->PGenericBinding() : NULL, CurrentContainer(), TypeOfWithEventsVar); // Keep track of who is shadowing in this container - we'll need the info if the event we find is on a derived container if (IsMemberAccessible && EventDecl->IsShadowing()) { ShadowingMembers->Add(EventDecl); } if (ConsiderEventSourcePropertiesToo && EventDecl->IsProperty() && ValidEventSourceProperty(EventDecl->PProperty())) { IsMemberAccessible = IsMemberAccessible && IsAccessible( EventDecl->PProperty()->GetProperty(), TypePossiblyContainingEvents->IsGenericBinding() ? TypePossiblyContainingEvents->PGenericBinding() : NULL, CurrentContainer(), TypeOfWithEventsVar); BCSYM *PropertyReturnType = EventDecl->PProperty()->GetType(); // // We only care about properties returning classes or interfaces // because only classes and interfaces can be specified in a // handles clause. // VSASSERT(IsClassOrInterface(PropertyReturnType), "Invalid event source property found. Should have been disallowed earlier!!!"); // We've come across a Property that returns an Event source. Dig through it. // if (CheckForAccessibleEvents( PropertyReturnType, // Property return type false, // i.e. don't consider EventSource properties, because // we only allow at most 3 names i.e. x.y.z in the // handles clause and and only y is allowed to be the // referring event source property. AnyEventDefined)) { // there are events on this WithEvents variable - and they are accessible } else { continue; } } else if (EventDecl->IsEventDecl()) { // there are events on this WithEvents variable - whether they are accessible is another matter // AnyEventDefined = true; } else { // Screen out everthing that isn't an Event declaration or possible Event Source // continue; } // This assert will guard against any bad changes to the conditions checks above VSASSERT( AnyEventDefined, "How can we get here when we have not found any event or event source ?"); // Determine if the event is accessible // It must be visible to the WithEvents container that references the event // if (IsMemberAccessible) { return true; } } // trawl container members looking for events/properties that may return events // Look recursively in bases too BasesIter Bases(TypePossiblyContainingEvents->PContainer()); BCSYM_GenericTypeBinding *BaseGenericBinding; while (BCSYM_Container *Base = Bases.GetNextBase(&BaseGenericBinding)) { if (Base->IsBad()) continue; if (CheckForAccessibleEventsWorker( BaseGenericBinding ? (BCSYM *)BaseGenericBinding : Base, TypeOfWithEventsVar, ShadowingMembers, false, // Don't consider event source properties in based as available // because we don't allow binding to them in the handles clause // (for no other better reason than leaving this implementation // as it was without complicating things, since this is not a // user feature anyway.) AnyEventDefined)) { return true; } } return false; // no visible events found }
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; }