Skip to content

Commit

Permalink
issue #8192: Excluded inline namespace broken after a5792da
Browse files Browse the repository at this point in the history
- Further fixes to make classes inside inline namespaces appear in the
  parent scope again.
- Also added a test case to check for regression
  • Loading branch information
doxygen committed Nov 21, 2020
1 parent b2d0095 commit 61f8521
Show file tree
Hide file tree
Showing 6 changed files with 175 additions and 57 deletions.
16 changes: 8 additions & 8 deletions src/classlist.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -102,17 +102,15 @@ void ClassSDict::writeDeclaration(OutputList &ol,const ClassDef::CompoundType *f
bool found=FALSE;
for (sdi.toFirst();(cd=sdi.current());++sdi)
{
ClassDefMutable *cdm = toClassDefMutable(cd);
//printf(" ClassSDict::writeDeclaration for %s\n",cd->name().data());
if (cdm &&
!cd->isAnonymous() &&
if (!cd->isAnonymous() &&
!cd->isExtension() &&
(cd->protection()!=Private || extractPrivate) &&
(filter==0 || *filter==cd->compoundType())
)
{
//printf("writeDeclarationLink()\n");
cdm->writeDeclarationLink(ol,found,header,localNames);
cd->writeDeclarationLink(ol,found,header,localNames);
}
}
if (found) ol.endMemberList();
Expand All @@ -139,9 +137,7 @@ void ClassSDict::writeDocumentation(OutputList &ol,const Definition * container)
// cd->name().data(),cd->getOuterScope(),cd->isLinkableInProject(),cd->isEmbeddedInOuterScope(),
// container,cd->partOfGroups() ? cd->partOfGroups()->count() : 0);

ClassDefMutable *cdm = toClassDefMutable(cd);
if (cdm &&
!cd->isAnonymous() &&
if (!cd->isAnonymous() &&
cd->isLinkableInProject() &&
cd->isEmbeddedInOuterScope() &&
!cd->isAlias() &&
Expand All @@ -158,7 +154,11 @@ void ClassSDict::writeDocumentation(OutputList &ol,const Definition * container)
ol.endGroupHeader();
found=TRUE;
}
cdm->writeInlineDocumentation(ol);
ClassDefMutable *cdm = toClassDefMutable(cd);
if (cdm)
{
cdm->writeInlineDocumentation(ol);
}
}
}
}
Expand Down
126 changes: 77 additions & 49 deletions src/doxygen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -307,7 +307,7 @@ static bool findClassRelation(

//----------------------------------------------------------------------------

static DefinitionMutable *findScopeFromQualifiedName(NamespaceDefMutable *startScope,const QCString &n,
static Definition *findScopeFromQualifiedName(NamespaceDefMutable *startScope,const QCString &n,
FileDef *fileScope,const TagInfo *tagInfo);

static void addPageToContext(PageDef *pd,Entry *root)
Expand All @@ -321,10 +321,10 @@ static void addPageToContext(PageDef *pd,Entry *root)
}
scope = stripAnonymousNamespaceScope(scope);
scope+="::"+pd->name();
DefinitionMutable *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,root->tagInfo());
Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,root->tagInfo());
if (d)
{
pd->setPageScope(toDefinition(d));
pd->setPageScope(d);
}
}
}
Expand Down Expand Up @@ -453,7 +453,7 @@ static void findGroupScope(const Entry *root)
}
scope = stripAnonymousNamespaceScope(scope);
scope+="::"+gd->name();
Definition *d = toDefinition(findScopeFromQualifiedName(Doxygen::globalScope,scope,0,root->tagInfo()));
Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,root->tagInfo());
if (d)
{
gd->setGroupScope(d);
Expand Down Expand Up @@ -716,13 +716,13 @@ static Definition *findScope(Entry *root,int level=0)
* full qualified name \a name. Creates an artificial scope if the scope is
* not found and set the parent/child scope relation if the scope is found.
*/
static DefinitionMutable *buildScopeFromQualifiedName(const QCString name,
static Definition *buildScopeFromQualifiedName(const QCString name,
int level,SrcLangExt lang,const TagInfo *tagInfo)
{
//printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
int i=0;
int p=0,l;
DefinitionMutable *prevScope=Doxygen::globalScope;
Definition *prevScope=Doxygen::globalScope;
QCString fullScope;
while (i<level)
{
Expand All @@ -732,54 +732,58 @@ static DefinitionMutable *buildScopeFromQualifiedName(const QCString name,
if (nsName.isEmpty()) return prevScope;
if (!fullScope.isEmpty()) fullScope+="::";
fullScope+=nsName;
NamespaceDefMutable *nd=toNamespaceDefMutable(Doxygen::namespaceSDict->find(fullScope));
DefinitionMutable *innerScope = nd;
ClassDefMutable *cd=0;
if (nd==0) cd = getClassMutable(fullScope);
NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
DefinitionMutable *innerScope = toDefinitionMutable(nd);
ClassDef *cd=0;
if (nd==0) cd = getClass(fullScope);
if (nd==0 && cd) // scope is a class
{
innerScope = cd;
innerScope = toDefinitionMutable(cd);
}
else if (nd==0 && cd==0 && fullScope.find('<')==-1) // scope is not known and could be a namespace!
{
// introduce bogus namespace
//printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
nd=createNamespaceDef(
NamespaceDefMutable *newNd=createNamespaceDef(
"[generated]",1,1,fullScope,
tagInfo?tagInfo->tagName:QCString(),
tagInfo?tagInfo->fileName:QCString());
nd->setLanguage(lang);
newNd->setLanguage(lang);

// add namespace to the list
Doxygen::namespaceSDict->inSort(fullScope,nd);
innerScope = nd;
Doxygen::namespaceSDict->inSort(fullScope,newNd);
innerScope = newNd;
}
else // scope is a namespace
{
}
if (innerScope)
{
// make the parent/child scope relation
prevScope->addInnerCompound(toDefinition(innerScope));
innerScope->setOuterScope(toDefinition(prevScope));
DefinitionMutable *prevScopeMutable = toDefinitionMutable(prevScope);
if (prevScopeMutable)
{
prevScopeMutable->addInnerCompound(toDefinition(innerScope));
}
innerScope->setOuterScope(prevScope);
}
else // current scope is a class, so return only the namespace part...
{
return prevScope;
}
// proceed to the next scope fragment
p=idx+l+2;
prevScope=innerScope;
prevScope=toDefinition(innerScope);
i++;
}
return prevScope;
}

static DefinitionMutable *findScopeFromQualifiedName(NamespaceDefMutable *startScope,const QCString &n,
static Definition *findScopeFromQualifiedName(NamespaceDefMutable *startScope,const QCString &n,
FileDef *fileScope,const TagInfo *tagInfo)
{
//printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
DefinitionMutable *resultScope=startScope;
Definition *resultScope=toDefinition(startScope);
if (resultScope==0) resultScope=Doxygen::globalScope;
QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
int l1=0,i1;
Expand All @@ -793,9 +797,9 @@ static DefinitionMutable *findScopeFromQualifiedName(NamespaceDefMutable *startS
while ((i2=getScopeFragment(scope,p,&l2))!=-1)
{
QCString nestedNameSpecifier = scope.mid(i1,l1);
Definition *orgScope = toDefinition(resultScope);
Definition *orgScope = resultScope;
//printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
resultScope = toDefinitionMutable(toDefinition(resultScope)->findInnerCompound(nestedNameSpecifier));
resultScope = const_cast<Definition*>(resultScope->findInnerCompound(nestedNameSpecifier));
//printf(" resultScope=%p\n",resultScope);
if (resultScope==0)
{
Expand All @@ -813,7 +817,7 @@ static DefinitionMutable *findScopeFromQualifiedName(NamespaceDefMutable *startS
// N::A::I while looking for A, so we should compare
// resultScope->name() against scope.left(i2+l2)
//printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
if (rightScopeMatch(toDefinition(resultScope)->name(),scope.left(i2+l2)))
if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
{
break;
}
Expand Down Expand Up @@ -1166,29 +1170,37 @@ static void resolveClassNestingRelations()
QCString name = stripAnonymousNamespaceScope(icd->name());
//printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
// also add class to the correct structural context
DefinitionMutable *d = findScopeFromQualifiedName(Doxygen::globalScope,
Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
name,icd->getFileDef(),0);
if (d)
{
//printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
d->addInnerCompound(cd);
cd->setOuterScope(toDefinition(d));
DefinitionMutable *dm = toDefinitionMutable(d);
if (dm)
{
dm->addInnerCompound(cd);
}
cd->setOuterScope(d);

// for inline namespace add an alias of the class to the outer scope
while (toDefinition(d)->definitionType()==Definition::TypeNamespace)
while (d->definitionType()==Definition::TypeNamespace)
{
NamespaceDef *nd = toNamespaceDef(d);
//printf("d->isInline()=%d\n",nd->isInline());
//printf("nd->isInline()=%d\n",nd->isInline());
if (nd && nd->isInline())
{
d = toDefinitionMutable(toDefinition(d)->getOuterScope());
d = d->getOuterScope();
if (d)
{
ClassDef *aliasCd = createClassDefAlias(toDefinition(d),cd);
d->addInnerCompound(aliasCd);
QCString aliasFullName = toDefinition(d)->qualifiedName()+"::"+aliasCd->localName();
Doxygen::classSDict->append(aliasFullName,aliasCd);
//printf("adding %s to %s as %s\n",qPrint(aliasCd->name()),qPrint(d->name()),qPrint(aliasFullName));
dm = toDefinitionMutable(d);
if (dm)
{
ClassDef *aliasCd = createClassDefAlias(d,cd);
dm->addInnerCompound(aliasCd);
QCString aliasFullName = d->qualifiedName()+"::"+aliasCd->localName();
Doxygen::classSDict->append(aliasFullName,aliasCd);
//printf("adding %s to %s as %s\n",qPrint(aliasCd->name()),qPrint(d->name()),qPrint(aliasFullName));
}
}
}
else
Expand All @@ -1213,20 +1225,24 @@ static void resolveClassNestingRelations()
for (cli.toFirst();(icd=cli.current());++cli)
{
ClassDefMutable *cd = toClassDefMutable(icd);
if (cd && visitedClasses.find(icd)!=visitedClasses.end())
if (cd && visitedClasses.find(icd)==visitedClasses.end())
{
QCString name = stripAnonymousNamespaceScope(cd->name());
//printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
/// create the scope artificially
// anyway, so we can at least relate scopes properly.
DefinitionMutable *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
if (d && d!=cd && !cd->getDefFileName().isEmpty())
// avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
// for this case doxygen assumes the existence of a namespace N::N in which C is to be found!
// also avoid warning for stuff imported via a tagfile.
{
d->addInnerCompound(cd);
cd->setOuterScope(toDefinition(d));
DefinitionMutable *dm = toDefinitionMutable(d);
if (dm)
{
dm->addInnerCompound(cd);
}
cd->setOuterScope(d);
warn(cd->getDefFileName(),cd->getDefLine(),
"Internal inconsistency: scope for class %s not "
"found!",name.data()
Expand Down Expand Up @@ -1553,33 +1569,45 @@ static void buildNamespaceList(const Entry *root)
Doxygen::namespaceSDict->inSort(fullName,nd);

// also add namespace to the correct structural context
DefinitionMutable *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName,0,tagInfo);
Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName,0,tagInfo);
//printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
if (d==0) // we didn't find anything, create the scope artificially
// anyway, so we can at least relate scopes properly.
{
d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
d->addInnerCompound(nd);
nd->setOuterScope(toDefinition(d));
DefinitionMutable *dm = toDefinitionMutable(d);
if (dm)
{
dm->addInnerCompound(nd);
}
nd->setOuterScope(d);
// TODO: Due to the order in which the tag file is written
// a nested class can be found before its parent!
}
else
{
d->addInnerCompound(nd);
nd->setOuterScope(toDefinition(d));
DefinitionMutable *dm = toDefinitionMutable(d);
if (dm)
{
dm->addInnerCompound(nd);
}
nd->setOuterScope(d);
// in case of d is an inline namespace, alias insert nd in the part scope of d.
while (toDefinition(d)->definitionType()==Definition::TypeNamespace)
while (d->definitionType()==Definition::TypeNamespace)
{
NamespaceDef *pnd = toNamespaceDef(d);
if (pnd && pnd->isInline())
{
d = toDefinitionMutable(toDefinition(d)->getOuterScope());
d = d->getOuterScope();
if (d)
{
NamespaceDef *aliasNd = createNamespaceDefAlias(toDefinition(d),nd);
//printf("adding %s to %s\n",qPrint(aliasNd->name()),qPrint(d->name()));
d->addInnerCompound(aliasNd);
dm = toDefinitionMutable(d);
if (dm)
{
NamespaceDef *aliasNd = createNamespaceDefAlias(d,nd);
//printf("adding %s to %s\n",qPrint(aliasNd->name()),qPrint(d->name()));
dm->addInnerCompound(aliasNd);
}
}
}
else
Expand Down Expand Up @@ -4471,7 +4499,7 @@ static bool findClassRelation(
si = baseClassName.findRev("::");
if (si!=-1) // class is nested
{
Definition *sd = toDefinition(findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,root->tagInfo()));
Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,root->tagInfo());
if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
{
baseClass->setArtificial(TRUE); // see bug678139
Expand Down
30 changes: 30 additions & 0 deletions testing/057/namespacelibrary.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="" xml:lang="en-US">
<compounddef id="namespacelibrary" kind="namespace" language="C++">
<compoundname>library</compoundname>
<innerclass refid="classlibrary_1_1v2_1_1foo" prot="public">library::v2::foo</innerclass>
<innernamespace refid="namespacelibrary_1_1v1">library::v1</innernamespace>
<innernamespace refid="namespacelibrary_1_1v2" inline="yes">library::v2</innernamespace>
<innernamespace refid="namespacelibrary_1_1v2_1_1_n_s">library::v2::NS</innernamespace>
<sectiondef kind="func">
<memberdef kind="function" id="057__inlinenamespace_8cpp_1aba9375172f5b36e1f4fda9b1dec39d90" prot="public" static="no" const="no" explicit="no" inline="no" virt="non-virtual">
<type>void</type>
<definition>void library::v2::func</definition>
<argsstring>()</argsstring>
<name>func</name>
<briefdescription>
</briefdescription>
<detaileddescription>
</detaileddescription>
<inbodydescription>
</inbodydescription>
<location file="057_inlinenamespace.cpp" line="16" column="14" declfile="057_inlinenamespace.cpp" declline="16" declcolumn="14"/>
</memberdef>
</sectiondef>
<briefdescription>
</briefdescription>
<detaileddescription>
</detaileddescription>
<location file="057_inlinenamespace.cpp" line="5" column="1"/>
</compounddef>
</doxygen>
28 changes: 28 additions & 0 deletions testing/057/namespacelibrary_1_1v1.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<doxygen xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="compound.xsd" version="" xml:lang="en-US">
<compounddef id="namespacelibrary_1_1v1" kind="namespace" language="C++">
<compoundname>library::v1</compoundname>
<innerclass refid="classlibrary_1_1v1_1_1foo" prot="public">library::v1::foo</innerclass>
<innernamespace refid="namespacelibrary_1_1v1_1_1_n_s">library::v1::NS</innernamespace>
<sectiondef kind="func">
<memberdef kind="function" id="057__inlinenamespace_8cpp_1a2257981298fec15f79c54c28880ac15c" prot="public" static="no" const="no" explicit="no" inline="no" virt="non-virtual">
<type>void</type>
<definition>void library::v1::func</definition>
<argsstring>()</argsstring>
<name>func</name>
<briefdescription>
</briefdescription>
<detaileddescription>
</detaileddescription>
<inbodydescription>
</inbodydescription>
<location file="057_inlinenamespace.cpp" line="10" column="14" declfile="057_inlinenamespace.cpp" declline="10" declcolumn="14"/>
</memberdef>
</sectiondef>
<briefdescription>
</briefdescription>
<detaileddescription>
</detaileddescription>
<location file="057_inlinenamespace.cpp" line="7" column="5"/>
</compounddef>
</doxygen>
Loading

0 comments on commit 61f8521

Please sign in to comment.