@@ -395,6 +395,7 @@ class ClassDefImpl : public DefinitionMixin<ClassDefMutable>
395395 void addTypeConstraint (const QCString &typeConstraint,const QCString &type);
396396 void writeTemplateSpec (OutputList &ol,const Definition *d,
397397 const QCString &type,SrcLangExt lang) const ;
398+ void mergeMembersFromBaseClasses (bool mergeVirtualBaseClass);
398399
399400 // PIMPL idiom
400401 class IMPL ;
@@ -1201,7 +1202,7 @@ void ClassDefImpl::internalInsertMember(MemberDef *md,
12011202 // printf("=======> adding member %s to class %s\n",qPrint(md->name()),qPrint(name()));
12021203
12031204 MemberNameInfo *mni = m_impl->allMemberNameInfoLinkedMap .add (md->name ());
1204- mni->push_back (std::make_unique<MemberInfo>(md,prot,md->virtualness (),FALSE ));
1205+ mni->push_back (std::make_unique<MemberInfo>(md,prot,md->virtualness (),false , false ));
12051206 }
12061207}
12071208
@@ -3518,47 +3519,34 @@ static bool isStandardFunc(const MemberDef *md)
35183519 md->isDestructor (); // destructor
35193520}
35203521
3521- /* !
3522- * recursively merges the 'all members' lists of a class base
3523- * with that of this class. Must only be called for classes without
3524- * subclasses!
3525- */
3526- void ClassDefImpl::mergeMembers ()
3522+ void ClassDefImpl::mergeMembersFromBaseClasses (bool mergeVirtualBaseClass)
35273523{
3528- if (m_impl->membersMerged ) return ;
3529-
3530- // bool optimizeOutputForJava = Config_getBool(OPTIMIZE_OUTPUT_JAVA);
3531- // bool vhdlOpt = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
35323524 SrcLangExt lang = getLanguage ();
35333525 QCString sep=getLanguageSpecificSeparator (lang,TRUE );
35343526 size_t sepLen = sep.length ();
3535-
3536- m_impl->membersMerged =TRUE ;
3537- // printf(" mergeMembers for %s\n",qPrint(name()));
35383527 bool inlineInheritedMembers = Config_getBool (INLINE_INHERITED_MEMB);
35393528 bool extractPrivate = Config_getBool (EXTRACT_PRIVATE);
3529+
3530+ // printf(" mergeMembers for %s mergeVirtualBaseClass=%d\n",qPrint(name()),mergeVirtualBaseClass);
3531+ // the merge the base members with this class' members
35403532 for (const auto &bcd : baseClasses ())
35413533 {
35423534 ClassDefMutable *bClass=toClassDefMutable (bcd.classDef );
35433535 if (bClass)
35443536 {
3545- // merge the members in the base class of this inheritance branch first
3546- bClass->mergeMembers ();
3547- if (bClass->getLanguage ()==SrcLangExt::Python) continue ; // python does not have member overloading, see issue 8480
3548-
35493537 const MemberNameInfoLinkedMap &srcMnd = bClass->memberNameInfoLinkedMap ();
35503538 MemberNameInfoLinkedMap &dstMnd = m_impl->allMemberNameInfoLinkedMap ;
35513539
35523540 for (auto &srcMni : srcMnd)
35533541 {
3554- // printf(" Base member name %s\n",srcMni->memberName());
35553542 MemberNameInfo *dstMni;
35563543 if ((dstMni=dstMnd.find (srcMni->memberName ())))
35573544 // a member with that name is already in the class.
35583545 // the member may hide or reimplement the one in the sub class
35593546 // or there may be another path to the base class that is already
35603547 // visited via another branch in the class hierarchy.
35613548 {
3549+ // printf(" %s hides member name %s\n",qPrint(bClass->name()),qPrint(srcMni->memberName()));
35623550 for (auto &srcMi : *srcMni)
35633551 {
35643552 MemberDef *srcMd = srcMi->memberDef ();
@@ -3583,19 +3571,19 @@ void ClassDefImpl::mergeMembers()
35833571 dstMd->getOuterScope (),dstMd->getFileDef (),&dstAl,
35843572 TRUE ,getLanguage ()
35853573 );
3586- // printf(" Yes, matching (%s<->%s): %d\n",
3574+ // printf(" Yes, matching (%s<->%s): %d\n",
35873575 // qPrint(argListToString(srcMd->argumentList())),
35883576 // qPrint(argListToString(dstMd->argumentList())),
35893577 // found);
35903578 hidden = hidden || !found;
35913579 }
35923580 else // member is in a non base class => multiple inheritance
3593- // using the same base class.
3581+ // using the same base class.
35943582 {
3595- // printf("$$ Existing member %s %s add scope %s\n",
3596- // qPrint(dstMi->ambiguityResolutionScope),
3583+ // printf(" $$ Existing member %s %s add scope %s\n",
3584+ // qPrint(dstMi->ambiguityResolutionScope() ),
35973585 // qPrint(dstMd->name()),
3598- // qPrint(dstMi->scopePath.left(dstMi->scopePath.find("::")+2));
3586+ // qPrint(dstMi->scopePath() .left(dstMi->scopePath() .find("::")+2) ));
35993587
36003588 QCString scope=dstMi->scopePath ().left (dstMi->scopePath ().find (sep)+sepLen);
36013589 if (scope!=dstMi->ambiguityResolutionScope ().left (scope.length ()))
@@ -3610,7 +3598,7 @@ void ClassDefImpl::mergeMembers()
36103598 // do not add if base class is virtual or
36113599 // if scope paths are equal or
36123600 // if base class is an interface (and thus implicitly virtual).
3613- // printf("same member found srcMi->virt=%d dstMi->virt=%d\n",srcMi->virt,dstMi->virt);
3601+ // printf(" same member found srcMi->virt=%d dstMi->virt=%d\n",srcMi->virt() ,dstMi->virt() );
36143602 if ((srcMi->virt ()!=Specifier::Normal && dstMi->virt ()!=Specifier::Normal) ||
36153603 bClass->name ()+sep+srcMi->scopePath () == dstMi->scopePath () ||
36163604 dstMd->getClassDef ()->compoundType ()==Interface
@@ -3619,12 +3607,12 @@ void ClassDefImpl::mergeMembers()
36193607 found=TRUE ;
36203608 }
36213609 else // member can be reached via multiple paths in the
3622- // inheritance tree
3610+ // inheritance tree
36233611 {
3624- // printf("$$ Existing member %s %s add scope %s\n",
3625- // qPrint(dstMi->ambiguityResolutionScope),
3612+ // printf(" $$ Existing member %s %s add scope %s\n",
3613+ // qPrint(dstMi->ambiguityResolutionScope() ),
36263614 // qPrint(dstMd->name()),
3627- // qPrint(dstMi->scopePath.left(dstMi->scopePath.find("::")+2));
3615+ // qPrint(dstMi->scopePath() .left(dstMi->scopePath() .find("::")+2) ));
36283616
36293617 QCString scope=dstMi->scopePath ().left (dstMi->scopePath ().find (sep)+sepLen);
36303618 if (scope!=dstMi->ambiguityResolutionScope ().left (scope.length ()))
@@ -3636,8 +3624,9 @@ void ClassDefImpl::mergeMembers()
36363624 }
36373625 if (found) break ;
36383626 }
3639- // printf("member %s::%s hidden %d ambiguous %d srcMi->ambigClass=%p\n",
3640- // qPrint(srcCd->name()),qPrint(srcMd->name()),hidden,ambiguous,srcMi->ambigClass);
3627+ // printf(" member %s::%s hidden %d ambiguous %d srcMi->ambigClass=%p found=%d\n",
3628+ // qPrint(srcCd->name()),qPrint(srcMd->name()),hidden,ambiguous,
3629+ // (void*)srcMi->ambigClass(),found);
36413630
36423631 // TODO: fix the case where a member is hidden by inheritance
36433632 // of a member with the same name but with another prototype,
@@ -3646,7 +3635,7 @@ void ClassDefImpl::mergeMembers()
36463635 // it seems that the member is not reachable by prefixing a
36473636 // scope name either (according to my compiler). Currently,
36483637 // this case is shown anyway.
3649- if (!found && srcMd->protection ()!=Protection::Private && !srcMd->isFriend ())
3638+ if (!found && srcMd->protection ()!=Protection::Private && !srcMd->isFriend () && srcMi-> virtualBaseClass ()==mergeVirtualBaseClass )
36503639 {
36513640 Protection prot = srcMd->protection ();
36523641 if (bcd.prot ==Protection::Protected && prot==Protection::Public)
@@ -3662,15 +3651,16 @@ void ClassDefImpl::mergeMembers()
36623651 {
36633652 if (!isStandardFunc (srcMd))
36643653 {
3665- // printf(" insertMember '%s' \n",qPrint(srcMd->name()));
3654+ // printf(" %s::insertMember(%s) \n",qPrint(name()) ,qPrint(srcMd->name()));
36663655 internalInsertMember (srcMd,prot,FALSE );
36673656 }
36683657 }
36693658
36703659 Specifier virt=srcMi->virt ();
36713660 if (virt==Specifier::Normal && bcd.virt !=Specifier::Normal) virt=bcd.virt ;
3661+ bool virtualBaseClass = bcd.virt !=Specifier::Normal;
36723662
3673- std::unique_ptr<MemberInfo> newMi = std::make_unique<MemberInfo>(srcMd,prot,virt,TRUE );
3663+ std::unique_ptr<MemberInfo> newMi = std::make_unique<MemberInfo>(srcMd,prot,virt,TRUE ,virtualBaseClass );
36743664 newMi->setScopePath (bClass->name ()+sep+srcMi->scopePath ());
36753665 if (ambiguous)
36763666 {
@@ -3704,14 +3694,15 @@ void ClassDefImpl::mergeMembers()
37043694 }
37053695 else // base class has a member that is not in the sub class => copy
37063696 {
3697+ // printf(" %s adds member name %s\n",qPrint(bClass->name()),qPrint(srcMni->memberName()));
37073698 // create a deep copy of the list (only the MemberInfo's will be
37083699 // copied, not the actual MemberDef's)
37093700 MemberNameInfo *newMni = dstMnd.add (srcMni->memberName ());
37103701
37113702 // copy the member(s) from the base to the sub class
37123703 for (auto &mi : *srcMni)
37133704 {
3714- if (!mi->memberDef ()->isFriend ()) // don't inherit friends
3705+ if (mi-> virtualBaseClass ()==mergeVirtualBaseClass && !mi->memberDef ()->isFriend ()) // don't inherit friends
37153706 {
37163707 Protection prot = mi->prot ();
37173708 if (bcd.prot ==Protection::Protected)
@@ -3722,25 +3713,29 @@ void ClassDefImpl::mergeMembers()
37223713 {
37233714 prot=Protection::Private;
37243715 }
3725- // printf("%s::%s: prot=%d bcd.prot=%d result=%d\n",
3726- // qPrint(name()),qPrint(mi->memberDef->name()),mi->prot,
3727- // bcd.prot,prot);
3716+ Specifier virt=mi->virt ();
3717+ bool virtualBaseClass = bcd.virt !=Specifier::Normal || mi->virtualBaseClass ();
3718+ if (virt==Specifier::Normal && bcd.virt !=Specifier::Normal) virt=bcd.virt ;
3719+ // printf(" %s::%s: [mi.prot=%d, bcd.prot=%d => prot=%d], [mi.virt=%d, bcd.virt=%d => virt=%d] virtualBase=%d\n",
3720+ // qPrint(name()),qPrint(mi->memberDef()->name()),
3721+ // mi->prot(),bcd.prot,prot,
3722+ // mi->virt(),bcd.virt,virt,
3723+ // virtualBaseClass
3724+ // );
37283725
37293726 if (prot!=Protection::Private || extractPrivate)
37303727 {
3731- Specifier virt=mi->virt ();
3732- if (virt==Specifier::Normal && bcd.virt !=Specifier::Normal) virt=bcd.virt ;
37333728
37343729 if (inlineInheritedMembers)
37353730 {
37363731 if (!isStandardFunc (mi->memberDef ()))
37373732 {
3738- // printf(" insertMember '%s'\n",qPrint(mi->memberDef->name()));
3733+ // printf(" %s:: insertMember '%s'\n",qPrint(name()),qPrint( mi->memberDef() ->name()));
37393734 internalInsertMember (mi->memberDef (),prot,FALSE );
37403735 }
37413736 }
37423737 // printf("Adding!\n");
3743- std::unique_ptr<MemberInfo> newMi = std::make_unique<MemberInfo>(mi->memberDef (),prot,virt,TRUE );
3738+ std::unique_ptr<MemberInfo> newMi = std::make_unique<MemberInfo>(mi->memberDef (),prot,virt,TRUE ,virtualBaseClass );
37443739 newMi->setScopePath (bClass->name ()+sep+mi->scopePath ());
37453740 newMi->setAmbigClass (mi->ambigClass ());
37463741 newMi->setAmbiguityResolutionScope (mi->ambiguityResolutionScope ());
@@ -3752,7 +3747,41 @@ void ClassDefImpl::mergeMembers()
37523747 }
37533748 }
37543749 }
3755- // printf(" end mergeMembers\n");
3750+ }
3751+
3752+ /* !
3753+ * recursively merges the 'all members' lists of a class base
3754+ * with that of this class. Must only be called for classes without
3755+ * subclasses!
3756+ */
3757+ void ClassDefImpl::mergeMembers ()
3758+ {
3759+ if (m_impl->membersMerged ) return ;
3760+ if (getLanguage ()==SrcLangExt::Python) return ; // python does not have member overloading, see issue 8480
3761+
3762+ // printf("> %s::mergeMembers()\n",qPrint(name()));
3763+
3764+ m_impl->membersMerged =TRUE ;
3765+
3766+ // first merge the members of the base class recursively
3767+ for (const auto &bcd : baseClasses ())
3768+ {
3769+ ClassDefMutable *bClass=toClassDefMutable (bcd.classDef );
3770+ if (bClass)
3771+ {
3772+ // merge the members in the base class of this inheritance branch first
3773+ bClass->mergeMembers ();
3774+ }
3775+ }
3776+
3777+ // first merge the member that are not inherited via a virtual base class
3778+ // (as this can end up reimplemented via multiple paths, see #10717 for examples)
3779+ mergeMembersFromBaseClasses (false );
3780+ // then process the member that are inherited via a virtual base class to add the
3781+ // ones that are not reimplemented via any path
3782+ mergeMembersFromBaseClasses (true );
3783+
3784+ // printf("< %s::mergeMembers()\n",qPrint(name()));
37563785}
37573786
37583787// ----------------------------------------------------------------------------
@@ -3839,7 +3868,7 @@ void ClassDefImpl::mergeCategory(ClassDef *cat)
38393868 // printf("Copying member %s\n",qPrint(mi->memberDef->name()));
38403869 mmd->moveTo (this );
38413870
3842- auto newMi=std::make_unique<MemberInfo>(newMd.get (),prot,mi->virt (),mi->inherited ());
3871+ auto newMi=std::make_unique<MemberInfo>(newMd.get (),prot,mi->virt (),mi->inherited (),mi-> virtualBaseClass () );
38433872 newMi->setScopePath (mi->scopePath ());
38443873 newMi->setAmbigClass (mi->ambigClass ());
38453874 newMi->setAmbiguityResolutionScope (mi->ambiguityResolutionScope ());
@@ -4042,7 +4071,7 @@ ClassDef *ClassDefImpl::insertTemplateInstance(const QCString &fileName,
40424071 }
40434072 if (templateClass==nullptr )
40444073 {
4045- QCString tcname = removeRedundantWhiteSpace (localName ()+templSpec);
4074+ QCString tcname = removeRedundantWhiteSpace (name ()+templSpec);
40464075 AUTO_TRACE (" New template instance class name='{}' templSpec='{}' inside '{}' hidden={}" ,
40474076 name (),templSpec,name (),isHidden ());
40484077
0 commit comments