1 /******************************************************************************
2  *
3  *
4  *
5  * Copyright (C) 1997-2015 by Dimitri van Heesch.
6  *
7  * Permission to use, copy, modify, and distribute this software and its
8  * documentation under the terms of the GNU General Public License is hereby
9  * granted. No representations are made about the suitability of this software
10  * for any purpose. It is provided "as is" without express or implied warranty.
11  * See the GNU General Public License for more details.
12  *
13  * Documents produced by Doxygen are derivative works derived from the
14  * input used in their production; they are not affected by this license.
15  *
16  */
17 
18 #include "memberlist.h"
19 #include "classdef.h"
20 #include "message.h"
21 #include "util.h"
22 #include "language.h"
23 #include "doxygen.h"
24 #include "outputlist.h"
25 #include "groupdef.h"
26 #include "vhdldocgen.h"
27 #include "namespacedef.h"
28 #include "filedef.h"
29 #include "membergroup.h"
30 #include "config.h"
31 #include "docparser.h"
32 
MemberList(MemberListType lt,MemberListContainer con)33 MemberList::MemberList(MemberListType lt,MemberListContainer con) : m_container(con), m_listType(lt)
34 {
35   //printf("%p: MemberList::MemberList(%d)\n",this,lt);
36   m_numDecMembers=-1; // special value indicating that value needs to be computed
37   m_numDecEnumValues=0;
38   m_numDocMembers=-1; // special value indicating that value needs to be computed
39   m_numDocEnumValues=0;
40   m_needsSorting=FALSE;
41 }
42 
~MemberList()43 MemberList::~MemberList()
44 {
45 }
46 
genericCompareMembers(const MemberDef * c1,const MemberDef * c2)47 int genericCompareMembers(const MemberDef *c1,const MemberDef *c2)
48 {
49   bool sortConstructorsFirst = Config_getBool(SORT_MEMBERS_CTORS_1ST);
50   if (sortConstructorsFirst)
51   {
52     int ord1 = c1->isConstructor() ? 2 : (c1->isDestructor() ? 1 : 0);
53     int ord2 = c2->isConstructor() ? 2 : (c2->isDestructor() ? 1 : 0);
54     if (ord1 > ord2)
55       return -1;
56     else if (ord2 > ord1)
57       return 1;
58   }
59   // sort on name
60   int cmp = qstricmp(c1->name(),c2->name());
61   // then on argument list
62   if (cmp==0 && !c1->argsString().isEmpty() && !c2->argsString().isEmpty())
63   {
64     cmp = qstricmp(c1->argsString(),c2->argsString());
65   }
66   // then on file in which the item is defined
67   if (cmp==0)
68   {
69     cmp = qstricmp(c1->getDefFileName(),c2->getDefFileName());
70   }
71   // then on line number at which the member is defined
72   if (cmp==0)
73   {
74     cmp = c1->getDefLine()-c2->getDefLine();
75   }
76   return cmp;
77 }
78 
countInheritableMembers(const ClassDef * inheritedFrom) const79 int MemberList::countInheritableMembers(const ClassDef *inheritedFrom) const
80 {
81   int count=0;
82   for (const auto &md : m_members)
83   {
84     if (md->isBriefSectionVisible())
85     {
86       if (md->memberType()!=MemberType_Friend &&
87           md->memberType()!=MemberType_EnumValue)
88       {
89         //printf("member %s: isReimplementedBy(%s)=%d\n",qPrint(md->name()),
90         //    qPrint(inheritedFrom->name()),
91         //    md->isReimplementedBy(inheritedFrom));
92         if (md->memberType()==MemberType_Function)
93         {
94           if (!md->isReimplementedBy(inheritedFrom)) count++;
95         }
96         else
97         {
98           count++;
99         }
100       }
101     }
102   }
103   for (const auto &mg : m_memberGroupRefList)
104   {
105     count+=mg->countInheritableMembers(inheritedFrom);
106   }
107   //printf("%s::countInheritableMembers(%s)=%d\n",
108   //    qPrint(listTypeAsString()),
109   //    qPrint(inheritedFrom->name()),count);
110   return count;
111 }
112 
113 /*! Count the number of members in this list that are visible in
114  *  the declaration part of a compound's documentation page.
115  */
countDecMembers()116 void MemberList::countDecMembers()
117 {
118   if (m_numDecMembers!=-1) return;
119 
120   //printf("----- countDecMembers count=%d ----\n",count());
121   /*
122   m_varCnt=m_funcCnt=m_enumCnt=m_enumValCnt=0;
123   m_typeCnt=m_seqCnt=m_dictCnt=m_protoCnt=m_defCnt=m_friendCnt=0;
124   */
125   m_numDecMembers=0;
126   for (const auto &md : m_members)
127   {
128     //printf("MemberList::countDecMembers(md=%s,%d)\n",qPrint(md->name()),md->isBriefSectionVisible());
129     if (md->isBriefSectionVisible())
130     {
131       switch(md->memberType())
132       {
133         case MemberType_Variable:    // fall through
134         case MemberType_Event:       // fall through
135         case MemberType_Property:    /*m_varCnt++,*/
136                                      m_numDecMembers++;
137                                      break;
138 // apparently necessary to get this to show up in declarations section?
139         case MemberType_Interface:   // fall through
140         case MemberType_Service:     // fall through
141         case MemberType_Function:    // fall through
142         case MemberType_Signal:      // fall through
143         case MemberType_DCOP:        // fall through
144         case MemberType_Slot:        if (!md->isRelated() || md->getClassDef())
145                                        /*m_funcCnt++,*/
146                                        m_numDecMembers++;
147                                      break;
148         case MemberType_Enumeration: /*m_enumCnt++,*/
149                                      m_numDecMembers++;
150                                      break;
151         case MemberType_EnumValue:   m_numDecEnumValues++;
152                                      m_numDecMembers++;
153                                      break;
154         case MemberType_Typedef:     /*m_typeCnt++,*/
155                                      m_numDecMembers++;
156                                      break;
157         case MemberType_Sequence:    /*m_seqCnt++,*/
158                                      m_numDecMembers++;
159                                      break;
160         case MemberType_Dictionary:  /*m_dictCnt++,*/
161                                      m_numDecMembers++;
162                                      break;
163         //case MemberType_Prototype:   m_protoCnt++,m_numDecMembers++; break;
164         case MemberType_Define:      if (Config_getBool(EXTRACT_ALL) ||
165                                          !md->argsString().isEmpty() ||
166                                          !md->initializer().isEmpty() ||
167                                          md->hasDocumentation()
168                                         ) /*m_defCnt++,*/ m_numDecMembers++;
169                                      break;
170         case MemberType_Friend:      /*m_friendCnt++,*/
171                                      m_numDecMembers++;
172                                      break;
173         default:
174           err("Unknown member type found for member '%s'\n!",qPrint(md->name()));
175       }
176     }
177   }
178   for (const auto &mg : m_memberGroupRefList)
179   {
180     mg->countDecMembers();
181     /*
182     m_varCnt+=mg->varCount();
183     m_funcCnt+=mg->funcCount();
184     m_enumCnt+=mg->enumCount();
185     m_enumValCnt+=mg->enumValueCount();
186     m_typeCnt+=mg->typedefCount();
187     m_seqCnt+=mg->sequenceCount();
188     m_dictCnt+=mg->dictionaryCount();
189     m_protoCnt+=mg->protoCount();
190     m_defCnt+=mg->defineCount();
191     m_friendCnt+=mg->friendCount();
192     */
193     m_numDecMembers+=mg->numDecMembers();
194     m_numDecEnumValues+=mg->numDecEnumValues();
195   }
196   //printf("----- end countDecMembers ----\n");
197 
198   //printf("MemberList::countDecMembers()=%d\n",m_numDecMembers);
199 }
200 
countDocMembers()201 void MemberList::countDocMembers()
202 {
203   if (m_numDocMembers!=-1) return; // used cached value
204   m_numDocMembers=0;
205   for (const auto &md : m_members)
206   {
207     if (md->isDetailedSectionVisible(m_container) && !md->isAlias())
208     {
209       // do not count enum values, since they do not produce entries of their own
210       if (md->memberType()==MemberType_EnumValue)
211       {
212         m_numDocEnumValues++;
213       }
214       m_numDocMembers++;
215     }
216   }
217   for (const auto &mg : m_memberGroupRefList)
218   {
219     mg->countDocMembers();
220     m_numDocMembers+=mg->numDocMembers();
221     m_numDocEnumValues+=mg->numDocEnumValues();
222   }
223   //printf("MemberList::countDocMembers()=%d memberGroupList=%p\n",m_numDocMembers,memberGroupList);
224 }
225 
setAnonymousEnumType()226 void MemberList::setAnonymousEnumType()
227 {
228   //printf("MemberList(%p)::setAnonymousEnumType()\n",this);
229   for (const auto &md : m_members)
230   {
231     if (md->isBriefSectionVisible())
232     {
233       QCString name(md->name());
234       int i=name.findRev("::");
235       if (i!=-1) name=name.right(name.length()-i-2);
236       if (md->memberType()==MemberType_Enumeration && name[0]=='@')
237       {
238         for (const auto &vmd : md->enumFieldList())
239         {
240           MemberDefMutable *vmdm = toMemberDefMutable(vmd);
241           if (vmdm)
242           {
243             QCString vtype=vmd->typeString();
244             if ((vtype.find(name))!=-1)
245             {
246               vmdm->setAnonymousEnumType(md);
247             }
248           }
249         }
250       }
251     }
252   }
253   for (const auto &mg : m_memberGroupRefList)
254   {
255     mg->setAnonymousEnumType();
256   }
257 }
258 
countEnumValues(const MemberDef * md) const259 int MemberList::countEnumValues(const MemberDef *md) const
260 {
261   int numEnumValues=0;
262   QCString name(md->name());
263   int i=name.findRev("::");
264   if (i!=-1) name=name.right(name.length()-i-2);
265   if (name[0]=='@')
266   {
267     for (const auto &vmd : m_members)
268     {
269       QCString vtype=vmd->typeString();
270       if ((vtype.find(name))!=-1)
271       {
272         numEnumValues++;
273       }
274     }
275   }
276   return numEnumValues;
277 }
278 
declVisible() const279 bool MemberList::declVisible() const
280 {
281   for (const auto &md : m_members)
282   {
283     if (md->isBriefSectionVisible())
284     {
285       switch (md->memberType())
286       {
287         case MemberType_Define:     // fall through
288         case MemberType_Typedef:    // fall through
289         case MemberType_Variable:   // fall through
290         case MemberType_Function:   // fall through
291         case MemberType_Signal:     // fall through
292         case MemberType_Slot:       // fall through
293         case MemberType_DCOP:       // fall through
294         case MemberType_Property:   // fall through
295         case MemberType_Interface:  // fall through
296         case MemberType_Service:    // fall through
297         case MemberType_Sequence:   // fall through
298         case MemberType_Dictionary: // fall through
299         case MemberType_Event:
300           return TRUE;
301         case MemberType_Enumeration:
302           {
303             // if this is an anonymous enum and there are variables of this
304             // enum type (i.e. enumVars>0), then we do not show the enum here.
305             if (countEnumValues(md)==0) // show enum here
306             {
307               return TRUE;
308             }
309           }
310           break;
311         case MemberType_Friend:
312           return TRUE;
313         case MemberType_EnumValue:
314           {
315             if (m_container==MemberListContainer::Group)
316             {
317               return TRUE;
318             }
319           }
320           break;
321       }
322     }
323   }
324   return FALSE;
325 }
326 
writePlainDeclarations(OutputList & ol,bool inGroup,const ClassDef * cd,const NamespaceDef * nd,const FileDef * fd,const GroupDef * gd,int indentLevel,const ClassDef * inheritedFrom,const QCString & inheritId) const327 void MemberList::writePlainDeclarations(OutputList &ol, bool inGroup,
328                        const ClassDef *cd,const NamespaceDef *nd,const FileDef *fd, const GroupDef *gd,
329                        int indentLevel, const ClassDef *inheritedFrom,const QCString &inheritId
330                       ) const
331 {
332   //printf("----- writePlainDeclaration() ----\n");
333   if (numDecMembers()==-1)
334   {
335     err("MemberList::numDecMembers()==-1, so the members of this list have not been counted. Please report as a bug.\n");
336     abort();
337   }
338   if (numDecMembers()<=numDecEnumValues())
339   {
340     //printf("  --> no members!\n");
341     return; // no members in this list
342   }
343   //printf("  --> writePlainDeclaration() numDecMembers()=%d\n",
344   //    numDecMembers());
345 
346   ol.pushGeneratorState();
347 
348   bool first=TRUE;
349   for (const auto &md : m_members)
350   {
351     //printf(">>> Member '%s' type=%d visible=%d\n",
352     //    qPrint(md->name()),md->memberType(),md->isBriefSectionVisible());
353     if ((inheritedFrom==0 || !md->isReimplementedBy(inheritedFrom)) &&
354         md->isBriefSectionVisible())
355     {
356       //printf(">>> rendering\n");
357       switch(md->memberType())
358       {
359         case MemberType_Define:      // fall through
360         //case MemberType_Prototype: // fall through
361         case MemberType_Typedef:     // fall through
362         case MemberType_Variable:    // fall through
363         case MemberType_Function:    // fall through
364         case MemberType_Signal:      // fall through
365         case MemberType_Slot:        // fall through
366         case MemberType_DCOP:        // fall through
367         case MemberType_Property:    // fall through
368         case MemberType_Interface:   // fall through
369         case MemberType_Service:     // fall through
370         case MemberType_Sequence:    // fall through
371         case MemberType_Dictionary:  // fall through
372         case MemberType_Event:
373           {
374             if (first) ol.startMemberList(),first=FALSE;
375             md->writeDeclaration(ol,cd,nd,fd,gd,inGroup,indentLevel,inheritedFrom,inheritId);
376             break;
377           }
378         case MemberType_Enumeration:
379           {
380             // if this is an anonymous enum and there are variables of this
381             // enum type (i.e. enumVars>0), then we do not show the enum here.
382             if (countEnumValues(md)==0) // show enum here
383             {
384               //printf("Enum!!\n");
385               if (first)
386               {
387                 ol.startMemberList();
388                 first=FALSE;
389               }
390               ol.startMemberDeclaration();
391               ol.startMemberItem(md->anchor(),0,inheritId);
392               bool detailsLinkable = md->hasDetailedDescription();
393               if (!detailsLinkable)
394               {
395                 ol.startDoxyAnchor(md->getOutputFileBase(),QCString(),md->anchor(),md->name(),QCString());
396               }
397               if (md->isSliceLocal())
398               {
399                 ol.writeString("local ");
400               }
401               ol.writeString("enum ");
402               if (md->getLanguage()==SrcLangExt_Cpp && md->isStrong())
403               {
404                 if (md->isEnumStruct())
405                 {
406                   ol.writeString("struct ");
407                 }
408                 else
409                 {
410                   ol.writeString("class ");
411                 }
412               }
413               ol.insertMemberAlign();
414               md->writeEnumDeclaration(ol,cd,nd,fd,gd);
415               if (!detailsLinkable)
416               {
417                 ol.endDoxyAnchor(md->getOutputFileBase(),md->anchor());
418               }
419               ol.endMemberItem();
420               if (!md->briefDescription().isEmpty() && Config_getBool(BRIEF_MEMBER_DESC))
421               {
422                 std::unique_ptr<IDocParser> parser { createDocParser() };
423                 std::unique_ptr<DocRoot>  rootNode { validatingParseDoc(*parser.get(),
424                                                      md->briefFile(),md->briefLine(),
425                                                      cd,md,
426                                                      md->briefDescription(),
427                                                      TRUE,FALSE,
428                                                      QCString(),TRUE,FALSE,
429                                                      Config_getBool(MARKDOWN_SUPPORT)) };
430                 if (rootNode && !rootNode->isEmpty())
431                 {
432                   ol.startMemberDescription(md->anchor());
433                   ol.writeDoc(rootNode.get(),cd,md);
434                   if (md->hasDetailedDescription())
435                   {
436                     ol.disableAllBut(OutputGenerator::Html);
437                     ol.docify(" ");
438                     ol.startTextLink(md->getOutputFileBase(),
439                         md->anchor());
440                     ol.parseText(theTranslator->trMore());
441                     ol.endTextLink();
442                     ol.enableAll();
443                   }
444                   ol.endMemberDescription();
445                 }
446               }
447               ol.endMemberDeclaration(md->anchor(),inheritId);
448             }
449             md->warnIfUndocumented();
450             break;
451           }
452         case MemberType_Friend:
453           if (inheritedFrom==0)
454           {
455             if (first)
456             {
457               ol.startMemberList();
458               first=FALSE;
459             }
460             md->writeDeclaration(ol,cd,nd,fd,gd,inGroup,indentLevel,inheritedFrom,inheritId);
461             break;
462           }
463         case MemberType_EnumValue:
464           {
465             if (inGroup)
466             {
467               //printf("EnumValue!\n");
468               if (first) ol.startMemberList(),first=FALSE;
469               md->writeDeclaration(ol,cd,nd,fd,gd,true,indentLevel,inheritedFrom,inheritId);
470             }
471           }
472           break;
473       }
474     }
475   }
476 
477   // handle members that are inside anonymous compounds and for which
478   // no variables of the anonymous compound type exist.
479   if (cd)
480   {
481     for (const auto &md : m_members)
482     {
483       if (md->fromAnonymousScope() && !md->anonymousDeclShown())
484       {
485         MemberDefMutable *mdm = toMemberDefMutable(md);
486         if (mdm) mdm->setFromAnonymousScope(FALSE);
487         //printf("anonymous compound members\n");
488         if (md->isBriefSectionVisible())
489         {
490           if (first)
491           {
492             ol.startMemberList();
493             first=FALSE;
494           }
495           md->writeDeclaration(ol,cd,nd,fd,gd,inGroup,indentLevel);
496         }
497         if (mdm) mdm->setFromAnonymousScope(TRUE);
498       }
499     }
500   }
501 
502   if (!first)
503   {
504     ol.endMemberList();
505   }
506 
507   ol.popGeneratorState();
508   //printf("----- end writePlainDeclaration() ----\n");
509 }
510 
511 /** Writes the list of members to the output.
512  *  @param ol Output list to write to
513  *  @param cd non-null if this list is part of class documentation.
514  *  @param nd non-null if this list is part of namespace documentation.
515  *  @param fd non-null if this list is part of file documentation.
516  *  @param gd non-null if this list is part of group documentation.
517  *  @param title Title to use for the member list.
518  *  @param subtitle Sub title to use for the member list.
519  *  @param showEnumValues Obsolete, always set to FALSE.
520  *  @param showInline if set to TRUE if title is rendered differently
521  *  @param inheritedFrom if not 0, the list is shown inside the
522  *         given class as inherited members, parameter cd points to the
523  *         class containing the members.
524  *  @param lt Type of list that is inherited from.
525  */
writeDeclarations(OutputList & ol,const ClassDef * cd,const NamespaceDef * nd,const FileDef * fd,const GroupDef * gd,const QCString & title,const QCString & subtitle,bool showEnumValues,bool showInline,const ClassDef * inheritedFrom,MemberListType lt) const526 void MemberList::writeDeclarations(OutputList &ol,
527              const ClassDef *cd,const NamespaceDef *nd,const FileDef *fd,const GroupDef *gd,
528              const QCString &title,const QCString &subtitle, bool showEnumValues,
529              bool showInline,const ClassDef *inheritedFrom,MemberListType lt) const
530 {
531   (void)showEnumValues; // unused
532 
533   //printf("----- writeDeclaration() this=%p ---- inheritedFrom=%p\n",this,inheritedFrom);
534   static bool optimizeVhdl = Config_getBool(OPTIMIZE_OUTPUT_VHDL);
535   QCString inheritId;
536 
537   const Definition *ctx = cd;
538   if (ctx==0 && nd) ctx = nd;
539   if (ctx==0 && gd) ctx = gd;
540   if (ctx==0 && fd) ctx = fd;
541 
542   //printf("%p: MemberList::writeDeclaration(title='%s',subtitle='%s')=%d inheritedFrom=%p\n",
543   //       this,title,subtitle,numDecMembers(),inheritedFrom);
544 
545   int num = numDecMembers();
546   int numEnumValues = numDecEnumValues();
547   if (inheritedFrom)
548   {
549     //if ( cd && !optimizeVhdl && countInheritableMembers(inheritedFrom)>0 )
550     if ( cd && !optimizeVhdl && cd->countMembersIncludingGrouped(
551                                       m_listType,inheritedFrom,TRUE)>0 )
552     {
553       ol.pushGeneratorState();
554       ol.disableAllBut(OutputGenerator::Html);
555       inheritId = substitute(listTypeAsString(lt),"-","_")+"_"+
556                   stripPath(cd->getOutputFileBase());
557       if (!title.isEmpty())
558       {
559         ol.writeInheritedSectionTitle(inheritId,cd->getReference(),
560                                       cd->getOutputFileBase(),
561                                       cd->anchor(),title,cd->displayName());
562       }
563       ol.popGeneratorState();
564     }
565   }
566   else if (num>numEnumValues)
567   {
568     if (!title.isEmpty())
569     {
570       if (showInline)
571       {
572         ol.startInlineHeader();
573       }
574       else
575       {
576         ol.startMemberHeader(listTypeAsString(m_listType));
577       }
578       ol.parseText(title);
579       if (showInline)
580       {
581         ol.endInlineHeader();
582       }
583       else
584       {
585         ol.endMemberHeader();
586       }
587     }
588     if (!subtitle.stripWhiteSpace().isEmpty())
589     {
590       ol.startMemberSubtitle();
591       ol.generateDoc("[generated]",-1,ctx,0,subtitle,FALSE,FALSE,
592                      QCString(),FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
593       ol.endMemberSubtitle();
594     }
595   }
596   if (num>numEnumValues)
597   {
598      bool inGroup = m_container==MemberListContainer::Group;
599     // TODO: Two things need to be worked out for proper VHDL output:
600     // 1. Signals and types under the group need to be
601     //    formatted to associate them with the group somehow
602     //    indentation, or at the very least, extra space after
603     //    the group is done
604     // 2. This might need to be repeated below for memberGroupLists
605     if (optimizeVhdl) // use specific declarations function
606     {
607       VhdlDocGen::writeVhdlDeclarations(this,ol,0,cd,0,0);
608     }
609     else
610     {
611       writePlainDeclarations(ol,inGroup,cd,nd,fd,gd,0,0,inheritId);
612     }
613 
614     //printf("memberGroupList=%p\n",memberGroupList);
615     for (const auto &mg : m_memberGroupRefList)
616     {
617       bool hasHeader=!mg->header().isEmpty() && mg->header()!="[NOHEADER]";
618       if (inheritId.isEmpty())
619       {
620         //printf("mg->header=%s hasHeader=%d\n",qPrint(mg->header()),hasHeader);
621         ol.startMemberGroupHeader(hasHeader);
622         if (hasHeader)
623         {
624           ol.parseText(mg->header());
625         }
626         ol.endMemberGroupHeader();
627         if (!mg->documentation().isEmpty())
628         {
629           //printf("Member group has docs!\n");
630           ol.startMemberGroupDocs();
631           ol.generateDoc(mg->docFile(),mg->docLine(),ctx,0,mg->documentation()+"\n",FALSE,FALSE,
632               QCString(),FALSE,FALSE,Config_getBool(MARKDOWN_SUPPORT));
633           ol.endMemberGroupDocs();
634         }
635         ol.startMemberGroup();
636       }
637       //printf("--- mg->writePlainDeclarations ---\n");
638       mg->writePlainDeclarations(ol,inGroup,cd,nd,fd,gd,0,inheritedFrom,inheritId);
639       if (inheritId.isEmpty())
640       {
641         ol.endMemberGroup(hasHeader);
642       }
643     }
644   }
645   if (inheritedFrom && cd)
646   {
647     const ClassDefMutable *cdm = toClassDefMutable(cd);
648     if (cdm)
649     {
650       // also add members that of this list type, that are grouped together
651       // in a separate list in class 'inheritedFrom'
652       cdm->addGroupedInheritedMembers(ol,m_listType,inheritedFrom,inheritId);
653     }
654   }
655   //printf("----- end writeDeclaration() ----\n");
656 }
657 
writeDocumentation(OutputList & ol,const QCString & scopeName,const Definition * container,const QCString & title,bool showEnumValues,bool showInline) const658 void MemberList::writeDocumentation(OutputList &ol,
659                      const QCString &scopeName, const Definition *container,
660                      const QCString &title,bool showEnumValues,bool showInline) const
661 {
662   if (numDocMembers()==-1)
663   {
664     err("MemberList::numDocMembers()==-1, so the members of this list have not been counted. Please report as a bug.\n");
665     abort();
666   }
667 
668   if (numDocMembers()==0) return;
669   if (!showEnumValues && numDocMembers()<=numDocEnumValues()) return;
670 
671   if (!title.isEmpty())
672   {
673     ol.pushGeneratorState();
674       ol.disable(OutputGenerator::Html);
675       ol.writeRuler();
676     ol.popGeneratorState();
677     ol.startGroupHeader(showInline ? 2 : 0);
678     ol.parseText(title);
679     ol.endGroupHeader(showInline ? 2 : 0);
680   }
681   ol.startMemberDocList();
682 
683   struct OverloadInfo
684   {
685     uint count = 1;
686     uint total = 0;
687   };
688   std::unordered_map<std::string,OverloadInfo> overloadInfo;
689   // count the number of overloaded members
690   for (const auto &md : m_members)
691   {
692     if (md->isDetailedSectionVisible(m_container) &&
693         !(md->isEnumValue() && !showInline))
694     {
695       auto it = overloadInfo.insert(std::make_pair(md->name().str(),OverloadInfo())).first;
696       it->second.total++;
697     }
698   }
699 
700   for (const auto &md : m_members)
701   {
702     if (md->isDetailedSectionVisible(m_container) &&
703         !(md->isEnumValue() && !showInline))
704     {
705       auto it = overloadInfo.find(md->name().str());
706       uint overloadCount = it->second.total;
707       uint &count = it->second.count;
708       MemberDefMutable *mdm = toMemberDefMutable(md);
709       if (mdm)
710       {
711         mdm->writeDocumentation(this,count++,overloadCount,ol,scopeName,container,
712             m_container==MemberListContainer::Group,showEnumValues,showInline);
713       }
714     }
715   }
716   //printf("MemberList::writeDocumentation()  --  member groups %d\n",memberGroupList->count());
717   for (const auto &mg : m_memberGroupRefList)
718   {
719     mg->writeDocumentation(ol,scopeName,container,showEnumValues,showInline);
720   }
721   ol.endMemberDocList();
722 }
723 
724 // members in a table
writeSimpleDocumentation(OutputList & ol,const Definition * container) const725 void MemberList::writeSimpleDocumentation(OutputList &ol,
726                      const Definition *container) const
727 {
728   //printf("MemberList count=%d enumValues=%d\n",numDocMembers(),numDocEnumValues());
729   if (numDocMembers()<=numDocEnumValues()) return; // only enum values and they should be excluded
730 
731   const ClassDef *cd = 0;
732   if (container && container->definitionType()==Definition::TypeClass)
733   {
734     cd = toClassDef(container);
735   }
736   ol.startMemberDocSimple(cd && cd->isJavaEnum());
737   for (const auto &md : m_members)
738   {
739     MemberDefMutable *mdm = toMemberDefMutable(md);
740     if (mdm)
741     {
742       mdm->writeMemberDocSimple(ol,container);
743     }
744   }
745   ol.endMemberDocSimple(cd && cd->isJavaEnum());
746 }
747 
748 // separate member pages
writeDocumentationPage(OutputList & ol,const QCString & scopeName,const DefinitionMutable * container) const749 void MemberList::writeDocumentationPage(OutputList &ol,
750                      const QCString &scopeName, const DefinitionMutable *container) const
751 {
752   static bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
753 
754   struct OverloadInfo
755   {
756     uint count = 1;
757     uint total = 0;
758   };
759   std::unordered_map<std::string,OverloadInfo> overloadInfo;
760 
761   // count the number of overloaded members
762   for (const auto &imd : m_members)
763   {
764     MemberDefMutable *md = toMemberDefMutable(imd);
765 
766     if (md && md->hasDetailedDescription())
767     {
768       auto it = overloadInfo.insert(std::make_pair(md->name().str(),OverloadInfo())).first;
769       it->second.total++;
770     }
771   }
772 
773   for (const auto &imd : m_members)
774   {
775     Definition *container_d = toDefinition(const_cast<DefinitionMutable*>(container));
776     MemberDefMutable *md = toMemberDefMutable(imd);
777     if (md && md->hasDetailedDescription())
778     {
779       auto it = overloadInfo.find(md->name().str());
780       uint overloadCount = it->second.total;
781       uint &count = it->second.count;
782       QCString diskName=md->getOutputFileBase();
783       QCString title=md->qualifiedName();
784       startFile(ol,diskName,md->name(),title,HLI_None,!generateTreeView,diskName);
785       if (!generateTreeView)
786       {
787         container->writeNavigationPath(ol);
788         ol.endQuickIndices();
789       }
790       ol.startContents();
791 
792       if (generateTreeView)
793       {
794         md->writeDocumentation(this,count++,overloadCount,ol,scopeName,container_d,m_container==MemberListContainer::Group);
795 
796         ol.endContents();
797         endFileWithNavPath(container_d,ol);
798       }
799       else
800       {
801         ol.writeString("<table cellspacing=\"0\" cellpadding=\"0\" border=\"0\">\n"
802             "  <tr>\n"
803             "   <td valign=\"top\">\n");
804 
805         container->writeQuickMemberLinks(ol,md);
806 
807         ol.writeString("   </td>\n");
808         ol.writeString("   <td valign=\"top\" class=\"mempage\">\n");
809 
810         md->writeDocumentation(this,count++,overloadCount,ol,scopeName,container_d,m_container==MemberListContainer::Group);
811 
812         ol.writeString("    </td>\n");
813         ol.writeString("  </tr>\n");
814         ol.writeString("</table>\n");
815 
816         endFile(ol);
817       }
818     }
819   }
820   for (const auto &mg : m_memberGroupRefList)
821   {
822     mg->writeDocumentationPage(ol,scopeName,container);
823   }
824 }
825 
addMemberGroup(MemberGroup * mg)826 void MemberList::addMemberGroup(MemberGroup *mg)
827 {
828   m_memberGroupRefList.push_back(mg);
829 }
830 
addListReferences(Definition * def)831 void MemberList::addListReferences(Definition *def)
832 {
833   for (const auto &imd : m_members)
834   {
835     MemberDefMutable *md = toMemberDefMutable(imd);
836     if (md && !md->isAlias() && (md->getGroupDef()==0 || def->definitionType()==Definition::TypeGroup))
837     {
838       md->addListReference(def);
839       const MemberVector &enumFields = md->enumFieldList();
840       if (md->memberType()==MemberType_Enumeration && !enumFields.empty())
841       {
842         //printf("  Adding enum values!\n");
843         for (const auto &vmd : enumFields)
844         {
845           MemberDefMutable *vmdm = toMemberDefMutable(vmd);
846           if (vmdm)
847           {
848             //printf("   adding %s\n",qPrint(vmd->name()));
849             vmdm->addListReference(def);
850           }
851         }
852       }
853     }
854   }
855   for (const auto &mg : m_memberGroupRefList)
856   {
857     mg->addListReferences(def);
858   }
859 }
860 
findSectionsInDocumentation(const Definition * d)861 void MemberList::findSectionsInDocumentation(const Definition *d)
862 {
863   for (const auto &imd : m_members)
864   {
865     MemberDefMutable *md = toMemberDefMutable(imd);
866     if (md)
867     {
868       md->findSectionsInDocumentation();
869     }
870   }
871   for (const auto &mg : m_memberGroupRefList)
872   {
873     mg->findSectionsInDocumentation(d);
874   }
875 }
876 
setNeedsSorting(bool b)877 void MemberList::setNeedsSorting(bool b)
878 {
879   m_needsSorting = b;
880 }
881 
listTypeAsString(MemberListType type)882 QCString MemberList::listTypeAsString(MemberListType type)
883 {
884   switch(type)
885   {
886     case MemberListType_pubMethods: return "pub-methods";
887     case MemberListType_proMethods: return "pro-methods";
888     case MemberListType_pacMethods: return "pac-methods";
889     case MemberListType_priMethods: return "pri-methods";
890     case MemberListType_pubStaticMethods: return "pub-static-methods";
891     case MemberListType_proStaticMethods: return "pro-static-methods";
892     case MemberListType_pacStaticMethods: return "pac-static-methods";
893     case MemberListType_priStaticMethods: return "pri-static-methods";
894     case MemberListType_pubSlots: return "pub-slots";
895     case MemberListType_proSlots: return "pro-slots";
896     case MemberListType_priSlots: return "pri-slots";
897     case MemberListType_pubAttribs: return "pub-attribs";
898     case MemberListType_proAttribs: return "pro-attribs";
899     case MemberListType_pacAttribs: return "pac-attribs";
900     case MemberListType_priAttribs: return "pri-attribs";
901     case MemberListType_pubStaticAttribs: return "pub-static-attribs";
902     case MemberListType_proStaticAttribs: return "pro-static-attribs";
903     case MemberListType_pacStaticAttribs: return "pac-static-attribs";
904     case MemberListType_priStaticAttribs: return "pri-static-attribs";
905     case MemberListType_pubTypes: return "pub-types";
906     case MemberListType_proTypes: return "pro-types";
907     case MemberListType_pacTypes: return "pac-types";
908     case MemberListType_priTypes: return "pri-types";
909     case MemberListType_related: return "related";
910     case MemberListType_signals: return "signals";
911     case MemberListType_friends: return "friends";
912     case MemberListType_dcopMethods: return "dcop-methods";
913     case MemberListType_properties: return "properties";
914     case MemberListType_events: return "events";
915     case MemberListType_interfaces: return "interfaces";
916     case MemberListType_services: return "services";
917     case MemberListType_decDefineMembers: return "define-members";
918     case MemberListType_decProtoMembers: return "proto-members";
919     case MemberListType_decTypedefMembers: return "typedef-members";
920     case MemberListType_decSequenceMembers: return "sequence-members";
921     case MemberListType_decDictionaryMembers: return "dictionary-members";
922     case MemberListType_decEnumMembers: return "enum-members";
923     case MemberListType_decFuncMembers: return "func-members";
924     case MemberListType_decVarMembers: return "var-members";
925     case MemberListType_decEnumValMembers: return "enumval-members";
926     case MemberListType_decPubSlotMembers: return "pub-slot-members";
927     case MemberListType_decProSlotMembers: return "pro-slot-members";
928     case MemberListType_decPriSlotMembers: return "pri-slot-members";
929     case MemberListType_decSignalMembers: return "signal-members";
930     case MemberListType_decEventMembers: return "event-members";
931     case MemberListType_decFriendMembers: return "friend-members";
932     case MemberListType_decPropMembers: return "prop-members";
933     case MemberListType_enumFields: return "enum-fields";
934     case MemberListType_memberGroup: break;
935     default: break;
936   }
937   return "";
938 }
939 
writeTagFile(TextStream & tagFile)940 void MemberList::writeTagFile(TextStream &tagFile)
941 {
942   for (const auto &imd : m_members)
943   {
944     MemberDefMutable *md = toMemberDefMutable(imd);
945     if (md)
946     {
947       if (md->getLanguage()!=SrcLangExt_VHDL)
948       {
949         md->writeTagFile(tagFile);
950         if (md->memberType()==MemberType_Enumeration && !md->isStrong())
951         {
952           for (const auto &ivmd : md->enumFieldList())
953           {
954             MemberDefMutable *vmd = toMemberDefMutable(ivmd);
955             if (vmd)
956             {
957               vmd->writeTagFile(tagFile);
958             }
959           }
960         }
961       }
962       else
963       {
964         VhdlDocGen::writeTagFile(md,tagFile);
965       }
966     }
967   }
968   for (const auto &mg : m_memberGroupRefList)
969   {
970     mg->writeTagFile(tagFile);
971   }
972 }
973 
974 // compute the HTML anchors for a list of members
setAnchors()975 void MemberList::setAnchors()
976 {
977   //int count=0;
978   for (const auto &md : m_members)
979   {
980     MemberDefMutable *mdm = toMemberDefMutable(md);
981     if (mdm && !md->isReference())
982     {
983       mdm->setAnchor();
984     }
985   }
986 }
987 
988