@@ -1002,6 +1002,16 @@ class TagFileParser
10021002 };
10031003 private:
10041004
1005+ struct ClassNode
1006+ {
1007+ ClassNode (const std::string &n) : name(n) {}
1008+ std::string name;
1009+ const TagClassInfo *tci = nullptr ;
1010+ std::unordered_map<std::string,std::unique_ptr<ClassNode>> children;
1011+ };
1012+
1013+ void buildClassEntry (const std::shared_ptr<Entry> &root, const TagClassInfo *tci);
1014+ void buildClassTree (const std::shared_ptr<Entry> &root, const ClassNode &node);
10051015 // ------------------------------------
10061016
10071017 std::vector< TagCompoundVariant > m_tagFileCompounds;
@@ -1485,70 +1495,109 @@ void TagFileParser::buildMemberList(const std::shared_ptr<Entry> &ce,const std::
14851495 }
14861496}
14871497
1498+ void TagFileParser::buildClassEntry (const std::shared_ptr<Entry> &root, const TagClassInfo *tci)
1499+ {
1500+ std::shared_ptr<Entry> ce = std::make_shared<Entry>();
1501+ ce->section = EntryType::makeClass ();
1502+ switch (tci->kind )
1503+ {
1504+ case TagClassInfo::Kind::Class: break ;
1505+ case TagClassInfo::Kind::Struct: ce->spec = TypeSpecifier ().setStruct (true ); break ;
1506+ case TagClassInfo::Kind::Union: ce->spec = TypeSpecifier ().setUnion (true ); break ;
1507+ case TagClassInfo::Kind::Interface: ce->spec = TypeSpecifier ().setInterface (true ); break ;
1508+ case TagClassInfo::Kind::Enum: ce->spec = TypeSpecifier ().setEnum (true ); break ;
1509+ case TagClassInfo::Kind::Exception: ce->spec = TypeSpecifier ().setException (true ); break ;
1510+ case TagClassInfo::Kind::Protocol: ce->spec = TypeSpecifier ().setProtocol (true ); break ;
1511+ case TagClassInfo::Kind::Category: ce->spec = TypeSpecifier ().setCategory (true ); break ;
1512+ case TagClassInfo::Kind::Service: ce->spec = TypeSpecifier ().setService (true ); break ;
1513+ case TagClassInfo::Kind::Singleton: ce->spec = TypeSpecifier ().setSingleton (true ); break ;
1514+ case TagClassInfo::Kind::None: // should never happen, means not properly initialized
1515+ assert (tci->kind != TagClassInfo::Kind::None);
1516+ break ;
1517+ }
1518+ ce->name = tci->name ;
1519+ if (tci->kind ==TagClassInfo::Kind::Protocol)
1520+ {
1521+ ce->name +=" -p" ;
1522+ }
1523+ addDocAnchors (ce,tci->docAnchors );
1524+ ce->tagInfoData .tagName = m_tagName;
1525+ ce->tagInfoData .anchor = tci->anchor ;
1526+ ce->tagInfoData .fileName = tci->filename ;
1527+ ce->startLine = tci->lineNr ;
1528+ ce->fileName = m_tagName;
1529+ ce->hasTagInfo = TRUE ;
1530+ ce->id = tci->clangId ;
1531+ ce->lang = tci->isObjC ? SrcLangExt::ObjC : SrcLangExt::Unknown;
1532+ // transfer base class list
1533+ ce->extends = tci->bases ;
1534+ if (!tci->templateArguments .empty ())
1535+ {
1536+ ArgumentList al;
1537+ for (const auto &argName : tci->templateArguments )
1538+ {
1539+ Argument a;
1540+ a.type = " class" ;
1541+ a.name = argName.c_str ();
1542+ al.push_back (a);
1543+ }
1544+ ce->tArgLists .push_back (al);
1545+ }
1546+
1547+ buildMemberList (ce,tci->members );
1548+ root->moveToSubEntryAndKeep (ce);
1549+ }
1550+
1551+ void TagFileParser::buildClassTree (const std::shared_ptr<Entry> &root,const ClassNode &node)
1552+ {
1553+ if (node.tci )
1554+ {
1555+ buildClassEntry (root,node.tci );
1556+ }
1557+ for (const auto &child : node.children )
1558+ {
1559+ buildClassTree (root,*child.second );
1560+ }
1561+ }
1562+
14881563/* ! Injects the info gathered by the XML parser into the Entry tree.
14891564 * This tree contains the information extracted from the input in a
14901565 * "unrelated" form.
14911566 */
14921567void TagFileParser::buildLists (const std::shared_ptr<Entry> &root)
14931568{
1494- // build class list
1569+ // First reorganize the entries in m_tagFileCompounds such that
1570+ // outer scope is processed before the nested class scope.
1571+ // To solve issue #11569, where a class nested in a specialization is
1572+ // processed first, which later causes the wrong class to be used
1573+ ClassNode classRoot (" " );
14951574 for (const auto &comp : m_tagFileCompounds)
14961575 {
14971576 const TagClassInfo *tci = comp.getClassInfo ();
14981577 if (tci)
14991578 {
1500- std::shared_ptr<Entry> ce = std::make_shared<Entry>();
1501- ce->section = EntryType::makeClass ();
1502- switch (tci->kind )
1503- {
1504- case TagClassInfo::Kind::Class: break ;
1505- case TagClassInfo::Kind::Struct: ce->spec = TypeSpecifier ().setStruct (true ); break ;
1506- case TagClassInfo::Kind::Union: ce->spec = TypeSpecifier ().setUnion (true ); break ;
1507- case TagClassInfo::Kind::Interface: ce->spec = TypeSpecifier ().setInterface (true ); break ;
1508- case TagClassInfo::Kind::Enum: ce->spec = TypeSpecifier ().setEnum (true ); break ;
1509- case TagClassInfo::Kind::Exception: ce->spec = TypeSpecifier ().setException (true ); break ;
1510- case TagClassInfo::Kind::Protocol: ce->spec = TypeSpecifier ().setProtocol (true ); break ;
1511- case TagClassInfo::Kind::Category: ce->spec = TypeSpecifier ().setCategory (true ); break ;
1512- case TagClassInfo::Kind::Service: ce->spec = TypeSpecifier ().setService (true ); break ;
1513- case TagClassInfo::Kind::Singleton: ce->spec = TypeSpecifier ().setSingleton (true ); break ;
1514- case TagClassInfo::Kind::None: // should never happen, means not properly initialized
1515- assert (tci->kind != TagClassInfo::Kind::None);
1516- break ;
1517- }
1518- ce->name = tci->name ;
1519- if (tci->kind ==TagClassInfo::Kind::Protocol)
1579+ ClassNode *current = &classRoot;
1580+ auto parts = split (tci->name .str ()," ::" );
1581+ for (size_t i=0 ; i<parts.size (); ++i)
15201582 {
1521- ce->name +=" -p" ;
1522- }
1523- addDocAnchors (ce,tci->docAnchors );
1524- ce->tagInfoData .tagName = m_tagName;
1525- ce->tagInfoData .anchor = tci->anchor ;
1526- ce->tagInfoData .fileName = tci->filename ;
1527- ce->startLine = tci->lineNr ;
1528- ce->fileName = m_tagName;
1529- ce->hasTagInfo = TRUE ;
1530- ce->id = tci->clangId ;
1531- ce->lang = tci->isObjC ? SrcLangExt::ObjC : SrcLangExt::Unknown;
1532- // transfer base class list
1533- ce->extends = tci->bases ;
1534- if (!tci->templateArguments .empty ())
1535- {
1536- ArgumentList al;
1537- for (const auto &argName : tci->templateArguments )
1583+ const auto &part = parts[i];
1584+ if (current->children .find (part)==current->children .end ()) // new child node
1585+ {
1586+ current->children [part] = std::make_unique<ClassNode>(part);
1587+ }
1588+ current = current->children [part].get ();
1589+ if (i==parts.size ()-1 )
15381590 {
1539- Argument a;
1540- a.type = " class" ;
1541- a.name = argName.c_str ();
1542- al.push_back (a);
1591+ current->tci = tci;
15431592 }
1544- ce->tArgLists .push_back (al);
15451593 }
1546-
1547- buildMemberList (ce,tci->members );
1548- root->moveToSubEntryAndKeep (ce);
15491594 }
15501595 }
15511596
1597+ // now process the classes following the tree structure
1598+ buildClassTree (root,classRoot);
1599+
1600+
15521601 // build file list
15531602 for (const auto &comp : m_tagFileCompounds)
15541603 {
0 commit comments