Doxygen
doxygen.cpp
浏览该文件的文档.
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2015 by Dimitri van Heesch.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation under the terms of the GNU General Public License is hereby
7  * granted. No representations are made about the suitability of this software
8  * for any purpose. It is provided "as is" without express or implied warranty.
9  * See the GNU General Public License for more details.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15 
16 #include <stdio.h>
17 #include <stdlib.h>
18 #include <sys/stat.h>
19 #include <errno.h>
20 
21 #include <algorithm>
22 #include <unordered_map>
23 #include <memory>
24 #include <cinttypes>
25 #include <chrono>
26 #include <clocale>
27 #include <locale>
28 
29 #include "version.h"
30 #include "doxygen.h"
31 #include "scanner.h"
32 #include "entry.h"
33 #include "index.h"
34 #include "message.h"
35 #include "config.h"
36 #include "util.h"
37 #include "pre.h"
38 #include "tagreader.h"
39 #include "dot.h"
40 #include "msc.h"
41 #include "docparser.h"
42 #include "dirdef.h"
43 #include "outputlist.h"
44 #include "declinfo.h"
45 #include "htmlgen.h"
46 #include "latexgen.h"
47 #include "mangen.h"
48 #include "language.h"
49 #include "debug.h"
50 #include "htmlhelp.h"
51 #include "qhp.h"
52 #include "ftvhelp.h"
53 #include "defargs.h"
54 #include "rtfgen.h"
55 #include "sqlite3gen.h"
56 #include "xmlgen.h"
57 #include "docbookgen.h"
58 #include "defgen.h"
59 #include "perlmodgen.h"
60 #include "reflist.h"
61 #include "pagedef.h"
62 #include "bufstr.h"
63 #include "commentcnv.h"
64 #include "cmdmapper.h"
65 #include "searchindex.h"
66 #include "parserintf.h"
67 #include "htags.h"
68 #include "pycode.h"
69 #include "pyscanner.h"
70 #include "fortrancode.h"
71 #include "fortranscanner.h"
72 #include "xmlcode.h"
73 #include "sqlcode.h"
74 #include "lexcode.h"
75 #include "lexscanner.h"
76 #include "code.h"
77 #include "portable.h"
78 #include "vhdljjparser.h"
79 #include "vhdldocgen.h"
80 #include "vhdlcode.h"
81 #include "eclipsehelp.h"
82 #include "cite.h"
83 #include "markdown.h"
84 #include "arguments.h"
85 #include "memberlist.h"
86 #include "layout.h"
87 #include "groupdef.h"
88 #include "classlist.h"
89 #include "namespacedef.h"
90 #include "filename.h"
91 #include "membername.h"
92 #include "membergroup.h"
93 #include "docsets.h"
94 #include "formula.h"
95 #include "settings.h"
96 #include "context.h"
97 #include "fileparser.h"
98 #include "emoji.h"
99 #include "plantuml.h"
100 #include "stlsupport.h"
101 #include "threadpool.h"
102 #include "clangparser.h"
103 #include "symbolresolver.h"
104 #include "regex.h"
105 #include "fileinfo.h"
106 #include "dir.h"
107 #include "conceptdef.h"
108 
109 #if USE_SQLITE3
110 #include <sqlite3.h>
111 #endif
112 
113 #if USE_LIBCLANG
114 #include <clang/Basic/Version.h>
115 #endif
116 
117 // provided by the generated file resources.cpp
118 extern void initResources();
119 
120 #if !defined(_WIN32) || defined(__CYGWIN__)
121 #include <signal.h>
122 #define HAS_SIGNALS
123 #endif
124 
125 // globally accessible variables
136 StringMap Doxygen::aliasMap; // aliases
144 StringUnorderedMap Doxygen::namespaceAliasMap; // all namespace aliases
145 StringMap Doxygen::tagDestinationMap; // all tag locations
146 StringUnorderedSet Doxygen::expandAsDefinedSet; // all macros that should be expanded
147 MemberGroupInfoMap Doxygen::memberGroupInfoMap; // dictionary of the member groups heading
148 std::unique_ptr<PageDef> Doxygen::mainPage;
149 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
168 
169 // locally accessible globals
170 static std::multimap< std::string, const Entry* > g_classEntries;
172 static StringSet g_compoundKeywords; // keywords recognised as compounds
173 static OutputList *g_outputList = 0; // list of output generating objects
174 static StringSet g_usingDeclarations; // used classes
175 static bool g_successfulRun = FALSE;
176 static bool g_dumpSymbolMap = FALSE;
178 
179 void clearAll()
180 {
181  g_inputFiles.clear();
182  //g_excludeNameDict.clear();
183  //delete g_outputList; g_outputList=0;
184 
201  Doxygen::mainPage.reset();
203 }
204 
206 {
207  public:
209  void begin(const char *name)
210  {
211  msg("%s", name);
212  stats.emplace_back(name,0);
213  startTime = std::chrono::steady_clock::now();
214  }
215  void end()
216  {
217  std::chrono::steady_clock::time_point endTime = std::chrono::steady_clock::now();
218  stats.back().elapsed = std::chrono::duration_cast<
219  std::chrono::microseconds>(endTime - startTime).count()/1000000.0;
220  }
221  void print()
222  {
223  bool restore=FALSE;
225  {
226  Debug::clearFlag("time");
227  restore=TRUE;
228  }
229  msg("----------------------\n");
230  for (const auto &s : stats)
231  {
232  msg("Spent %.6f seconds in %s",s.elapsed,s.name);
233  }
234  if (restore) Debug::setFlag("time");
235  }
236  private:
237  struct stat
238  {
239  const char *name;
240  double elapsed;
241  //stat() : name(NULL),elapsed(0) {}
242  stat(const char *n, double el) : name(n),elapsed(el) {}
243  };
244  std::vector<stat> stats;
245  std::chrono::steady_clock::time_point startTime;
246 } g_s;
247 
248 
249 static void addMemberDocs(const Entry *root,MemberDefMutable *md, const QCString &funcDecl,
250  const ArgumentList *al,bool over_load,uint64 spec);
251 static void findMember(const Entry *root,
252  const QCString &relates,
253  const QCString &type,
254  const QCString &args,
255  QCString funcDecl,
256  bool overloaded,
257  bool isFunc
258  );
259 
261 {
265 };
266 
267 
268 static bool findClassRelation(
269  const Entry *root,
270  Definition *context,
271  ClassDefMutable *cd,
272  const BaseInfo *bi,
273  const TemplateNameMap &templateNames,
274  /*bool insertUndocumented*/
276  bool isArtificial
277  );
278 
279 //----------------------------------------------------------------------------
280 
282  FileDef *fileScope,const TagInfo *tagInfo);
283 
284 static void addPageToContext(PageDef *pd,Entry *root)
285 {
286  if (root->parent()) // add the page to it's scope
287  {
288  QCString scope = root->parent()->name;
289  if (root->parent()->section==Entry::PACKAGEDOC_SEC)
290  {
291  scope=substitute(scope,".","::");
292  }
293  scope = stripAnonymousNamespaceScope(scope);
294  scope+="::"+pd->name();
296  if (d)
297  {
298  pd->setPageScope(d);
299  }
300  }
301 }
302 
303 static void addRelatedPage(Entry *root)
304 {
305  GroupDef *gd=0;
306  for (const Grouping &g : root->groups)
307  {
308  if (!g.groupname.isEmpty() && (gd=Doxygen::groupLinkedMap->find(g.groupname))) break;
309  }
310  //printf("---> addRelatedPage() %s gd=%p\n",qPrint(root->name),gd);
311  QCString doc;
312  if (root->brief.isEmpty())
313  {
314  doc=root->doc+root->inbodyDocs;
315  }
316  else
317  {
318  doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
319  }
320 
321  PageDef *pd = addRelatedPage(root->name,root->args,doc,
322  root->docFile,
323  root->docLine,
324  root->startLine,
325  root->sli,
326  gd,root->tagInfo(),
327  FALSE,
328  root->lang
329  );
330  if (pd)
331  {
332  pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
333  pd->addSectionsToDefinition(root->anchors);
334  pd->setLocalToc(root->localToc);
335  addPageToContext(pd,root);
336  }
337 }
338 
339 static void buildGroupListFiltered(const Entry *root,bool additional, bool includeExternal)
340 {
341  if (root->section==Entry::GROUPDOC_SEC && !root->name.isEmpty() &&
342  ((!includeExternal && root->tagInfo()==0) ||
343  ( includeExternal && root->tagInfo()!=0))
344  )
345  {
346  if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
347  (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
348  {
350  //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
351  // qPrint(root->type),qPrint(root->name),additional,includeExternal,gd);
352 
353  if (gd)
354  {
355  if ( !gd->hasGroupTitle() )
356  {
357  gd->setGroupTitle( root->type );
358  }
359  else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
360  {
361  warn( root->fileName,root->startLine,
362  "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
363  qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
364  }
365  gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
366  gd->setDocumentation( root->doc, root->docFile, root->docLine );
367  gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
368  gd->addSectionsToDefinition(root->anchors);
369  gd->setRefItems(root->sli);
370  gd->setLanguage(root->lang);
371  }
372  else
373  {
374  if (root->tagInfo())
375  {
376  gd = Doxygen::groupLinkedMap->add(root->name,
377  std::unique_ptr<GroupDef>(
378  createGroupDef(root->fileName,root->startLine,root->name,root->type,root->tagInfo()->fileName)));
379  gd->setReference(root->tagInfo()->tagName);
380  }
381  else
382  {
383  gd = Doxygen::groupLinkedMap->add(root->name,
384  std::unique_ptr<GroupDef>(
385  createGroupDef(root->fileName,root->startLine,root->name,root->type)));
386  }
387  gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
388  // allow empty docs for group
389  gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
390  gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
391  gd->addSectionsToDefinition(root->anchors);
392  gd->setRefItems(root->sli);
393  gd->setLanguage(root->lang);
394  }
395  }
396  }
397  for (const auto &e : root->children()) buildGroupListFiltered(e.get(),additional,includeExternal);
398 }
399 
400 static void buildGroupList(const Entry *root)
401 {
402  // --- first process only local groups
403  // first process the @defgroups blocks
405  // then process the @addtogroup, @weakgroup blocks
407 
408  // --- then also process external groups
409  // first process the @defgroups blocks
411  // then process the @addtogroup, @weakgroup blocks
413 }
414 
415 static void findGroupScope(const Entry *root)
416 {
417  if (root->section==Entry::GROUPDOC_SEC && !root->name.isEmpty() &&
418  root->parent() && !root->parent()->name.isEmpty())
419  {
420  GroupDef *gd;
421  if ((gd=Doxygen::groupLinkedMap->find(root->name)))
422  {
423  QCString scope = root->parent()->name;
424  if (root->parent()->section==Entry::PACKAGEDOC_SEC)
425  {
426  scope=substitute(scope,".","::");
427  }
428  scope = stripAnonymousNamespaceScope(scope);
429  scope+="::"+gd->name();
431  if (d)
432  {
433  gd->setGroupScope(d);
434  }
435  }
436  }
437  for (const auto &e : root->children()) findGroupScope(e.get());
438 }
439 
440 static void organizeSubGroupsFiltered(const Entry *root,bool additional)
441 {
442  if (root->section==Entry::GROUPDOC_SEC && !root->name.isEmpty())
443  {
444  if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
445  (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
446  {
447  GroupDef *gd;
448  if ((gd=Doxygen::groupLinkedMap->find(root->name)))
449  {
450  //printf("adding %s to group %s\n",qPrint(root->name),qPrint(gd->name()));
451  addGroupToGroups(root,gd);
452  }
453  }
454  }
455  for (const auto &e : root->children()) organizeSubGroupsFiltered(e.get(),additional);
456 }
457 
458 static void organizeSubGroups(const Entry *root)
459 {
460  //printf("Defining groups\n");
461  // first process the @defgroups blocks
463  //printf("Additional groups\n");
464  // then process the @addtogroup, @weakgroup blocks
466 }
467 
468 //----------------------------------------------------------------------
469 
470 static void buildFileList(const Entry *root)
471 {
472  if (((root->section==Entry::FILEDOC_SEC) ||
473  ((root->section & Entry::FILE_MASK) && Config_getBool(EXTRACT_ALL))) &&
474  !root->name.isEmpty() && !root->tagInfo() // skip any file coming from tag files
475  )
476  {
477  bool ambig;
479  if (!fd || ambig)
480  {
481  int save_ambig = ambig;
482  // use the directory of the file to see if the described file is in the same
483  // directory as the describing file.
484  QCString fn = root->fileName;
485  int newIndex=fn.findRev('/');
486  if (newIndex<0)
487  {
488  fn = root->name;
489  }
490  else
491  {
492  fn = fn.left(newIndex)+"/"+root->name;
493  }
495  if (!fd) ambig = save_ambig;
496  }
497  //printf("**************** root->name=%s fd=%p\n",qPrint(root->name),fd);
498  if (fd && !ambig)
499  {
500  //printf("Adding documentation!\n");
501  // using FALSE in setDocumentation is small hack to make sure a file
502  // is documented even if a \file command is used without further
503  // documentation
504  fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
505  fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
506  fd->addSectionsToDefinition(root->anchors);
507  fd->setRefItems(root->sli);
508  for (const Grouping &g : root->groups)
509  {
510  GroupDef *gd=0;
512  {
513  gd->addFile(fd);
514  fd->makePartOfGroup(gd);
515  //printf("File %s: in group %s\n",qPrint(fd->name()),qPrint(gd->name()));
516  }
517  }
518  }
519  else
520  {
521  QCString text(4096);
522  text.sprintf("the name '%s' supplied as "
523  "the argument in the \\file statement ",
524  qPrint(root->name));
525  if (ambig) // name is ambiguous
526  {
527  text+="matches the following input files:\n";
529  text+="Please use a more specific name by "
530  "including a (larger) part of the path!";
531  }
532  else // name is not an input file
533  {
534  text+="is not an input file";
535  }
536  warn(root->fileName,root->startLine,"%s", qPrint(text));
537  }
538  }
539  for (const auto &e : root->children()) buildFileList(e.get());
540 }
541 
542 template<class DefMutable>
543 static void addIncludeFile(DefMutable *cd,FileDef *ifd,const Entry *root)
544 {
545  if (
546  (!root->doc.stripWhiteSpace().isEmpty() ||
547  !root->brief.stripWhiteSpace().isEmpty() ||
548  Config_getBool(EXTRACT_ALL)
549  ) && root->protection!=Private
550  )
551  {
552  //printf(">>>>>> includeFile=%s\n",qPrint(root->includeFile));
553 
554  bool local=Config_getBool(FORCE_LOCAL_INCLUDES);
555  QCString includeFile = root->includeFile;
556  if (!includeFile.isEmpty() && includeFile.at(0)=='"')
557  {
558  local = TRUE;
559  includeFile=includeFile.mid(1,includeFile.length()-2);
560  }
561  else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
562  {
563  local = FALSE;
564  includeFile=includeFile.mid(1,includeFile.length()-2);
565  }
566 
567  bool ambig;
568  FileDef *fd=0;
569  // see if we need to include a verbatim copy of the header file
570  //printf("root->includeFile=%s\n",qPrint(root->includeFile));
571  if (!includeFile.isEmpty() &&
572  (fd=findFileDef(Doxygen::inputNameLinkedMap,includeFile,ambig))==0
573  )
574  { // explicit request
575  QCString text;
576  text.sprintf("the name '%s' supplied as "
577  "the argument of the \\class, \\struct, \\union, or \\include command ",
578  qPrint(includeFile)
579  );
580  if (ambig) // name is ambiguous
581  {
582  text+="matches the following input files:\n";
584  text+="Please use a more specific name by "
585  "including a (larger) part of the path!";
586  }
587  else // name is not an input file
588  {
589  text+="is not an input file";
590  }
591  warn(root->fileName,root->startLine, "%s", qPrint(text));
592  }
593  else if (includeFile.isEmpty() && ifd &&
594  // see if the file extension makes sense
596  { // implicit assumption
597  fd=ifd;
598  }
599 
600  // if a file is found, we mark it as a source file.
601  if (fd)
602  {
603  QCString iName = !root->includeName.isEmpty() ?
604  root->includeName : includeFile;
605  if (!iName.isEmpty()) // user specified include file
606  {
607  if (iName.at(0)=='<') local=FALSE; // explicit override
608  else if (iName.at(0)=='"') local=TRUE;
609  if (iName.at(0)=='"' || iName.at(0)=='<')
610  {
611  iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
612  }
613  if (iName.isEmpty())
614  {
615  iName=fd->name();
616  }
617  }
618  else if (!Config_getList(STRIP_FROM_INC_PATH).empty())
619  {
620  iName=stripFromIncludePath(fd->absFilePath());
621  }
622  else // use name of the file containing the class definition
623  {
624  iName=fd->name();
625  }
626  if (fd->generateSourceFile()) // generate code for header
627  {
628  cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
629  }
630  else // put #include in the class documentation without link
631  {
632  cd->setIncludeFile(0,iName,local,TRUE);
633  }
634  }
635  }
636 }
637 
638 #if 0
639 static bool addNamespace(Entry *root,ClassDef *cd)
640 {
641  // see if this class is defined inside a namespace
642  if (root->section & Entry::COMPOUND_MASK)
643  {
644  Entry *e = root->parent;
645  while (e)
646  {
648  {
649  NamespaceDef *nd=0;
651  //printf("addNameSpace() trying: %s\n",qPrint(nsName));
652  if (!nsName.isEmpty() && nsName.at(0)!='@' &&
653  (nd=getResolvedNamespace(nsName))
654  )
655  {
656  cd->setNamespace(nd);
657  cd->setOuterScope(nd);
658  nd->insertClass(cd);
659  return TRUE;
660  }
661  }
662  e=e->parent;
663  }
664  }
665  return FALSE;
666 }
667 #endif
668 
669 #if 0
670 static Definition *findScope(Entry *root,int level=0)
671 {
672  if (root==0) return 0;
673  //printf("start findScope name=%s\n",qPrint(root->name));
674  Definition *result=0;
675  if (root->section&Entry::SCOPE_MASK)
676  {
677  result = findScope(root->parent,level+1); // traverse to the root of the tree
678  if (result)
679  {
680  //printf("Found %s inside %s at level %d\n",qPrint(root->name),qPrint(result->name()),level);
681  // TODO: look at template arguments
682  result = result->findInnerCompound(root->name);
683  }
684  else // reached the global scope
685  {
686  // TODO: look at template arguments
688  //printf("Found in globalScope %s at level %d\n",qPrint(result->name()),level);
689  }
690  }
691  //printf("end findScope(%s,%d)=%s\n",qPrint(root->name),
692  // level,result==0 ? "<none>" : qPrint(result->name()));
693  return result;
694 }
695 #endif
696 
698 {
699  int l = s.length();
700  int count=0;
701  int round=0;
702  QCString result;
703  for (int i=0;i<l;i++)
704  {
705  char c=s.at(i);
706  if (c=='(') round++;
707  else if (c==')' && round>0) round--;
708  else if (c=='<' && round==0) count++;
709  if (count==0)
710  {
711  result+=c;
712  }
713  if (c=='>' && round==0 && count>0) count--;
714  }
715  //printf("stripTemplateSpecifiers(%s)=%s\n",qPrint(s),qPrint(result));
716  return result;
717 }
718 
719 /*! returns the Definition object belonging to the first \a level levels of
720  * full qualified name \a name. Creates an artificial scope if the scope is
721  * not found and set the parent/child scope relation if the scope is found.
722  */
723 static Definition *buildScopeFromQualifiedName(const QCString &name_,SrcLangExt lang,const TagInfo *tagInfo)
724 {
725  QCString name = stripTemplateSpecifiers(name_);
726  int level = name.contains("::");
727  //printf("buildScopeFromQualifiedName(%s) level=%d\n",qPrint(name),level);
728  int i=0;
729  int p=0,l;
730  Definition *prevScope=Doxygen::globalScope;
731  QCString fullScope;
732  while (i<level)
733  {
734  int idx=getScopeFragment(name,p,&l);
735  if (idx==-1) return prevScope;
736  QCString nsName = name.mid(idx,l);
737  if (nsName.isEmpty()) return prevScope;
738  if (!fullScope.isEmpty()) fullScope+="::";
739  fullScope+=nsName;
741  DefinitionMutable *innerScope = toDefinitionMutable(nd);
742  ClassDef *cd=0;
743  if (nd==0) cd = getClass(fullScope);
744  if (nd==0 && cd) // scope is a class
745  {
746  innerScope = toDefinitionMutable(cd);
747  }
748  else if (nd==0 && cd==0 && fullScope.find('<')==-1) // scope is not known and could be a namespace!
749  {
750  // introduce bogus namespace
751  //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",qPrint(nsName),qPrint(prevScope->name()),(void*)tagInfo);
752  NamespaceDefMutable *newNd=
754  Doxygen::namespaceLinkedMap->add(fullScope,
755  std::unique_ptr<NamespaceDef>(
757  "[generated]",1,1,fullScope,
758  tagInfo?tagInfo->tagName:QCString(),
759  tagInfo?tagInfo->fileName:QCString()))));
760  if (newNd)
761  {
762  newNd->setLanguage(lang);
763  newNd->setArtificial(TRUE);
764  // add namespace to the list
765  innerScope = newNd;
766  }
767  }
768  else // scope is a namespace
769  {
770  }
771  if (innerScope)
772  {
773  // make the parent/child scope relation
774  DefinitionMutable *prevScopeMutable = toDefinitionMutable(prevScope);
775  if (prevScopeMutable)
776  {
777  prevScopeMutable->addInnerCompound(toDefinition(innerScope));
778  }
779  innerScope->setOuterScope(prevScope);
780  }
781  else // current scope is a class, so return only the namespace part...
782  {
783  return prevScope;
784  }
785  // proceed to the next scope fragment
786  p=idx+l+2;
787  prevScope=toDefinition(innerScope);
788  i++;
789  }
790  return prevScope;
791 }
792 
794  FileDef *fileScope,const TagInfo *tagInfo)
795 {
796  //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? qPrint(startScope->name()) : 0, qPrint(n));
797  Definition *resultScope=toDefinition(startScope);
798  if (resultScope==0) resultScope=Doxygen::globalScope;
800  int l1=0,i1;
801  i1=getScopeFragment(scope,0,&l1);
802  if (i1==-1)
803  {
804  //printf(">no fragments!\n");
805  return resultScope;
806  }
807  int p=i1+l1,l2=0,i2;
808  while ((i2=getScopeFragment(scope,p,&l2))!=-1)
809  {
810  QCString nestedNameSpecifier = scope.mid(i1,l1);
811  Definition *orgScope = resultScope;
812  //printf(" nestedNameSpecifier=%s\n",qPrint(nestedNameSpecifier));
813  resultScope = const_cast<Definition*>(resultScope->findInnerCompound(nestedNameSpecifier));
814  //printf(" resultScope=%p\n",resultScope);
815  if (resultScope==0)
816  {
817  if (orgScope==Doxygen::globalScope && fileScope && !fileScope->getUsedNamespaces().empty())
818  // also search for used namespaces
819  {
820  for (const auto &nd : fileScope->getUsedNamespaces())
821  {
822  resultScope = findScopeFromQualifiedName(toNamespaceDefMutable(nd),n,fileScope,tagInfo);
823  if (resultScope!=0) break;
824  }
825  if (resultScope)
826  {
827  // for a nested class A::I in used namespace N, we get
828  // N::A::I while looking for A, so we should compare
829  // resultScope->name() against scope.left(i2+l2)
830  //printf(" -> result=%s scope=%s\n",qPrint(resultScope->name()),qPrint(scope));
831  if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
832  {
833  break;
834  }
835  goto nextFragment;
836  }
837  }
838 
839  // also search for used classes. Complication: we haven't been able
840  // to put them in the right scope yet, because we are still resolving
841  // the scope relations!
842  // Therefore loop through all used classes and see if there is a right
843  // scope match between the used class and nestedNameSpecifier.
844  for (const auto &usedName : g_usingDeclarations)
845  {
846  //printf("Checking using class %s\n",ui.currentKey());
847  if (rightScopeMatch(usedName.c_str(),nestedNameSpecifier))
848  {
849  // ui.currentKey() is the fully qualified name of nestedNameSpecifier
850  // so use this instead.
851  QCString fqn = QCString(usedName) + scope.right(scope.length()-p);
852  resultScope = buildScopeFromQualifiedName(fqn,startScope->getLanguage(),0);
853  //printf("Creating scope from fqn=%s result %p\n",qPrint(fqn),resultScope);
854  if (resultScope)
855  {
856  //printf("> Match! resultScope=%s\n",qPrint(resultScope->name()));
857  return resultScope;
858  }
859  }
860  }
861 
862  //printf("> name %s not found in scope %s\n",qPrint(nestedNameSpecifier),qPrint(orgScope->name()));
863  return 0;
864  }
865  nextFragment:
866  i1=i2;
867  l1=l2;
868  p=i2+l2;
869  }
870  //printf(">findScopeFromQualifiedName scope %s\n",qPrint(resultScope->name()));
871  return resultScope;
872 }
873 
874 std::unique_ptr<ArgumentList> getTemplateArgumentsFromName(
875  const QCString &name,
876  const ArgumentLists &tArgLists)
877 {
878  // for each scope fragment, check if it is a template and advance through
879  // the list if so.
880  int i,p=0;
881  auto alIt = tArgLists.begin();
882  while ((i=name.find("::",p))!=-1 && alIt!=tArgLists.end())
883  {
885  if (nd==0)
886  {
887  ClassDef *cd = getClass(name.left(i));
888  if (cd)
889  {
890  if (!cd->templateArguments().empty())
891  {
892  ++alIt;
893  }
894  }
895  }
896  p=i+2;
897  }
898  return alIt!=tArgLists.end() ?
899  std::make_unique<ArgumentList>(*alIt) :
900  std::unique_ptr<ArgumentList>();
901 }
902 
903 static
905 {
907  if (specifier&Entry::Struct)
908  sec=ClassDef::Struct;
909  else if (specifier&Entry::Union)
910  sec=ClassDef::Union;
911  else if (specifier&Entry::Category)
912  sec=ClassDef::Category;
913  else if (specifier&Entry::Interface)
915  else if (specifier&Entry::Protocol)
916  sec=ClassDef::Protocol;
917  else if (specifier&Entry::Exception)
919  else if (specifier&Entry::Service)
920  sec=ClassDef::Service;
921  else if (specifier&Entry::Singleton)
923 
924  switch(section)
925  {
926  //case Entry::UNION_SEC:
927  case Entry::UNIONDOC_SEC:
928  sec=ClassDef::Union;
929  break;
930  //case Entry::STRUCT_SEC:
932  sec=ClassDef::Struct;
933  break;
934  //case Entry::INTERFACE_SEC:
937  break;
938  //case Entry::PROTOCOL_SEC:
940  sec=ClassDef::Protocol;
941  break;
942  //case Entry::CATEGORY_SEC:
944  sec=ClassDef::Category;
945  break;
946  //case Entry::EXCEPTION_SEC:
949  break;
951  sec=ClassDef::Service;
952  break;
955  break;
956  }
957  return sec;
958 }
959 
960 
961 static void addClassToContext(const Entry *root)
962 {
963  FileDef *fd = root->fileDef();
964 
965  QCString scName;
966  if (root->parent()->section&Entry::SCOPE_MASK)
967  {
968  scName=root->parent()->name;
969  }
970  // name without parent's scope
971  QCString fullName = root->name;
972 
973  // strip off any template parameters (but not those for specializations)
974  fullName=stripTemplateSpecifiersFromScope(fullName);
975 
976  // name with scope (if not present already)
977  QCString qualifiedName = fullName;
978  if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
979  {
980  qualifiedName.prepend(scName+"::");
981  }
982 
983  // see if we already found the class before
984  ClassDefMutable *cd = getClassMutable(qualifiedName);
985 
986  Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",
987  cd ? qPrint(cd->name()) : qPrint(root->name), qPrint(qualifiedName),cd);
988 
989  if (cd)
990  {
991  fullName=cd->name();
992  Debug::print(Debug::Classes,0," Existing class %s!\n",qPrint(cd->name()));
993  //if (cd->templateArguments()==0)
994  //{
995  // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,qPrint(root->scopeSpec));
996  // cd->setTemplateArguments(tArgList);
997  //}
998 
999  cd->setDocumentation(root->doc,root->docFile,root->docLine);
1000  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1001 
1002  if ((root->spec&Entry::ForwardDecl)==0 && cd->isForwardDeclared())
1003  {
1004  cd->setDefFile(root->fileName,root->startLine,root->startColumn);
1005  if (root->bodyLine!=-1)
1006  {
1007  cd->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
1008  cd->setBodyDef(fd);
1009  }
1010  }
1011 
1012  if (cd->templateArguments().empty() || (cd->isForwardDeclared() && (root->spec&Entry::ForwardDecl)==0))
1013  {
1014  // this happens if a template class declared with @class is found
1015  // before the actual definition or if a forward declaration has different template
1016  // parameter names.
1017  std::unique_ptr<ArgumentList> tArgList = getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1018  if (tArgList)
1019  {
1020  cd->setTemplateArguments(*tArgList);
1021  }
1022  }
1023  if (cd->requiresClause().isEmpty() && !root->req.isEmpty())
1024  {
1025  cd->setRequiresClause(root->req);
1026  }
1027 
1029 
1030  cd->setMetaData(root->metaData);
1031  }
1032  else // new class
1033  {
1035 
1036  QCString className;
1037  QCString namespaceName;
1038  extractNamespaceName(fullName,className,namespaceName);
1039 
1040  //printf("New class: fullname %s namespace '%s' name='%s' brief='%s' docs='%s'\n",
1041  // qPrint(fullName),qPrint(namespaceName),qPrint(className),qPrint(root->brief),qPrint(root->doc));
1042 
1043  QCString tagName;
1044  QCString refFileName;
1045  const TagInfo *tagInfo = root->tagInfo();
1046  int i;
1047  if (tagInfo)
1048  {
1049  tagName = tagInfo->tagName;
1050  refFileName = tagInfo->fileName;
1051  if (fullName.find("::")!=-1)
1052  // symbols imported via tag files may come without the parent scope,
1053  // so we artificially create it here
1054  {
1055  buildScopeFromQualifiedName(fullName,root->lang,tagInfo);
1056  }
1057  }
1058  std::unique_ptr<ArgumentList> tArgList;
1059  if ((root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java) && (i=fullName.findRev('<'))!=-1)
1060  {
1061  // a Java/C# generic class looks like a C++ specialization, so we need to split the
1062  // name and template arguments here
1063  tArgList = stringToArgumentList(root->lang,fullName.mid(i));
1064  fullName=fullName.left(i);
1065  }
1066  else
1067  {
1068  tArgList = getTemplateArgumentsFromName(fullName,root->tArgLists);
1069  }
1070  // add class to the list
1071  //printf("ClassDict.insert(%s)\n",qPrint(fullName));
1072  cd = toClassDefMutable(
1073  Doxygen::classLinkedMap->add(fullName,
1074  std::unique_ptr<ClassDef>(
1075  createClassDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn,
1076  fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum) )));
1077  if (cd)
1078  {
1079  Debug::print(Debug::Classes,0," New class '%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p hidden=%d artificial=%d\n",
1080  qPrint(fullName),sec,root->tArgLists.size(), tagInfo,root->hidden,root->artificial);
1081  cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1082  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1083  cd->setLanguage(root->lang);
1084  cd->setId(root->id);
1085  cd->setHidden(root->hidden);
1086  cd->setArtificial(root->artificial);
1087  cd->setClassSpecifier(root->spec);
1088  cd->setTypeConstraints(root->typeConstr);
1089  //printf("new ClassDef %s tempArgList=%p specScope=%s\n",qPrint(fullName),root->tArgList,qPrint(root->scopeSpec));
1090 
1091  //printf("class %s template args=%s\n",qPrint(fullName),
1092  // tArgList ? tempArgListToString(tArgList,qPrint(root->lang)) : "<none>");
1093  if (tArgList)
1094  {
1095  cd->setTemplateArguments(*tArgList);
1096  }
1097  cd->setRequiresClause(root->req);
1098  cd->setProtection(root->protection);
1099  cd->setIsStatic(root->stat);
1100 
1101  // file definition containing the class cd
1102  cd->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
1103  cd->setBodyDef(fd);
1104 
1105  cd->setMetaData(root->metaData);
1106 
1107  // see if the class is found inside a namespace
1108  //bool found=addNamespace(root,cd);
1109 
1110  cd->insertUsedFile(fd);
1111  }
1112  else
1113  {
1114  Debug::print(Debug::Classes,0," Not added class '%s', already exists as alias\n", qPrint(fullName));
1115  }
1116  }
1117 
1118  if (cd)
1119  {
1120  cd->addSectionsToDefinition(root->anchors);
1121  if (!root->subGrouping) cd->setSubGrouping(FALSE);
1122  if ((root->spec&Entry::ForwardDecl)==0)
1123  {
1124  if (cd->hasDocumentation())
1125  {
1126  addIncludeFile(cd,fd,root);
1127  }
1128  if (fd && (root->section & Entry::COMPOUND_MASK))
1129  {
1130  //printf(">> Inserting class '%s' in file '%s' (root->fileName='%s')\n",
1131  // qPrint(cd->name()),
1132  // qPrint(fd->name()),
1133  // qPrint(root->fileName)
1134  // );
1135  cd->setFileDef(fd);
1136  fd->insertClass(cd);
1137  }
1138  }
1139  addClassToGroups(root,cd);
1140  cd->setRefItems(root->sli);
1141  }
1142 }
1143 
1144 //----------------------------------------------------------------------
1145 // build a list of all classes mentioned in the documentation
1146 // and all classes that have a documentation block before their definition.
1147 static void buildClassList(const Entry *root)
1148 {
1149  if (
1150  ((root->section & Entry::COMPOUND_MASK) ||
1151  root->section==Entry::OBJCIMPL_SEC) && !root->name.isEmpty()
1152  )
1153  {
1154  addClassToContext(root);
1155  }
1156  for (const auto &e : root->children()) buildClassList(e.get());
1157 }
1158 
1159 static void buildClassDocList(const Entry *root)
1160 {
1161  if (
1162  (root->section & Entry::COMPOUNDDOC_MASK) && !root->name.isEmpty()
1163  )
1164  {
1165  addClassToContext(root);
1166  }
1167  for (const auto &e : root->children()) buildClassDocList(e.get());
1168 }
1169 
1170 //----------------------------------------------------------------------
1171 // build a list of all classes mentioned in the documentation
1172 // and all classes that have a documentation block before their definition.
1173 
1174 static void addConceptToContext(const Entry *root)
1175 {
1176  FileDef *fd = root->fileDef();
1177 
1178  QCString scName;
1179  if (root->parent()->section&Entry::SCOPE_MASK)
1180  {
1181  scName=root->parent()->name;
1182  }
1183 
1184  // name with scope (if not present already)
1185  QCString qualifiedName = root->name;
1186  if (!scName.isEmpty() && !leftScopeMatch(qualifiedName,scName))
1187  {
1188  qualifiedName.prepend(scName+"::");
1189  }
1190 
1191  // see if we already found the concept before
1192  ConceptDefMutable *cd = getConceptMutable(qualifiedName);
1193 
1194  Debug::print(Debug::Classes,0, " Found concept with name %s (qualifiedName=%s -> cd=%p)\n",
1195  cd ? qPrint(cd->name()) : qPrint(root->name), qPrint(qualifiedName),cd);
1196 
1197  if (cd)
1198  {
1199  qualifiedName=cd->name();
1200  Debug::print(Debug::Classes,0," Existing concept %s!\n",qPrint(cd->name()));
1201 
1202  cd->setDocumentation(root->doc,root->docFile,root->docLine);
1203  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1204 
1205  addIncludeFile(cd,fd,root);
1206  }
1207  else // new concept
1208  {
1209  QCString className;
1210  QCString namespaceName;
1211  extractNamespaceName(qualifiedName,className,namespaceName);
1212 
1213  //printf("New concept: fullname %s namespace '%s' name='%s' brief='%s' docs='%s'\n",
1214  // qPrint(qualifiedName),qPrint(namespaceName),qPrint(className),qPrint(root->brief),qPrint(root->doc));
1215 
1216  QCString tagName;
1217  QCString refFileName;
1218  const TagInfo *tagInfo = root->tagInfo();
1219  if (tagInfo)
1220  {
1221  tagName = tagInfo->tagName;
1222  refFileName = tagInfo->fileName;
1223  if (qualifiedName.find("::")!=-1)
1224  // symbols imported via tag files may come without the parent scope,
1225  // so we artificially create it here
1226  {
1227  buildScopeFromQualifiedName(qualifiedName,root->lang,tagInfo);
1228  }
1229  }
1230  std::unique_ptr<ArgumentList> tArgList = getTemplateArgumentsFromName(qualifiedName,root->tArgLists);
1231  // add concept to the list
1232  //printf("ClassDict.insert(%s)\n",qPrint(fullName));
1233  cd = toConceptDefMutable(
1234  Doxygen::conceptLinkedMap->add(qualifiedName,
1235  std::unique_ptr<ConceptDef>(
1236  createConceptDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn,
1237  qualifiedName,tagName,refFileName))));
1238  if (cd)
1239  {
1240  Debug::print(Debug::Classes,0," New concept '%s' #tArgLists=%d tagInfo=%p\n",
1241  qPrint(qualifiedName),root->tArgLists.size(),tagInfo);
1242  cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1243  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1244  cd->setLanguage(root->lang);
1245  cd->setId(root->id);
1246  cd->setHidden(root->hidden);
1247  if (tArgList)
1248  {
1249  cd->setTemplateArguments(*tArgList);
1250  }
1251  cd->setInitializer(root->initializer.str().c_str());
1252  // file definition containing the class cd
1253  cd->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
1254  cd->setBodyDef(fd);
1255  addIncludeFile(cd,fd,root);
1256 
1257  // also add namespace to the correct structural context
1258  Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,qualifiedName,0,tagInfo);
1260  {
1262  if (dm)
1263  {
1264  dm->addInnerCompound(cd);
1265  }
1266  cd->setOuterScope(d);
1267  }
1268  }
1269  else
1270  {
1271  Debug::print(Debug::Classes,0," Not added concept '%s', already exists (as alias)\n", qPrint(qualifiedName));
1272  }
1273  }
1274 
1275  if (cd)
1276  {
1277  cd->addSectionsToDefinition(root->anchors);
1278  if (fd)
1279  {
1280  //printf(">> Inserting concept '%s' in file '%s' (root->fileName='%s')\n",
1281  // qPrint(cd->name()),
1282  // qPrint(fd->name()),
1283  // qPrint(root->fileName)
1284  // );
1285  cd->setFileDef(fd);
1286  fd->insertConcept(cd);
1287  }
1288  addConceptToGroups(root,cd);
1289  cd->setRefItems(root->sli);
1290  }
1291 }
1292 static void buildConceptList(const Entry *root)
1293 {
1294  if (root->section & Entry::CONCEPT_SEC)
1295  {
1296  addConceptToContext(root);
1297  }
1298  for (const auto &e : root->children()) buildConceptList(e.get());
1299 }
1300 
1301 static void buildConceptDocList(const Entry *root)
1302 {
1303  if (root->section & Entry::CONCEPTDOC_SEC)
1304  {
1305  addConceptToContext(root);
1306  }
1307  for (const auto &e : root->children()) buildConceptDocList(e.get());
1308 }
1309 
1310 //----------------------------------------------------------------------
1311 
1313 {
1314  ClassDefSet visitedClasses;
1315 
1316  bool done=FALSE;
1317  int iteration=0;
1318  while (!done)
1319  {
1320  done=TRUE;
1321  ++iteration;
1322  struct ClassAlias
1323  {
1324  ClassAlias(const QCString &name,std::unique_ptr<ClassDef> cd,DefinitionMutable *ctx) :
1325  aliasFullName(name),aliasCd(std::move(cd)), aliasContext(ctx) {}
1326  QCString aliasFullName;
1327  std::unique_ptr<ClassDef> aliasCd;
1328  DefinitionMutable *aliasContext;
1329  };
1330  std::vector<ClassAlias> aliases;
1331  for (const auto &icd : *Doxygen::classLinkedMap)
1332  {
1333  ClassDefMutable *cd = toClassDefMutable(icd.get());
1334  if (cd && visitedClasses.find(icd.get())==visitedClasses.end())
1335  {
1336  QCString name = stripAnonymousNamespaceScope(icd->name());
1337  //printf("processing=%s, iteration=%d\n",qPrint(cd->name()),iteration);
1338  // also add class to the correct structural context
1340  name,icd->getFileDef(),0);
1341  if (d)
1342  {
1343  //printf("****** adding %s to scope %s in iteration %d\n",qPrint(cd->name()),qPrint(d->name()),iteration);
1345  if (dm)
1346  {
1347  dm->addInnerCompound(cd);
1348  }
1349  cd->setOuterScope(d);
1350 
1351  // for inline namespace add an alias of the class to the outer scope
1353  {
1354  NamespaceDef *nd = toNamespaceDef(d);
1355  //printf("nd->isInline()=%d\n",nd->isInline());
1356  if (nd && nd->isInline())
1357  {
1358  d = d->getOuterScope();
1359  if (d)
1360  {
1361  dm = toDefinitionMutable(d);
1362  if (dm)
1363  {
1364  std::unique_ptr<ClassDef> aliasCd { createClassDefAlias(d,cd) };
1365  QCString aliasFullName = d->qualifiedName()+"::"+aliasCd->localName();
1366  aliases.push_back(ClassAlias(aliasFullName,std::move(aliasCd),dm));
1367  //printf("adding %s to %s as %s\n",qPrint(aliasCd->name()),qPrint(d->name()),qPrint(aliasFullName));
1368  }
1369  }
1370  }
1371  else
1372  {
1373  break;
1374  }
1375  }
1376 
1377  visitedClasses.insert(icd.get());
1378  done=FALSE;
1379  }
1380  //else
1381  //{
1382  // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",qPrint(cd->name()),iteration);
1383  //}
1384  }
1385  }
1386  // add aliases
1387  for (auto &alias : aliases)
1388  {
1389  ClassDef *aliasCd = Doxygen::classLinkedMap->add(alias.aliasFullName,std::move(alias.aliasCd));
1390  if (aliasCd)
1391  {
1392  alias.aliasContext->addInnerCompound(aliasCd);
1393  }
1394  }
1395  }
1396 
1397  //give warnings for unresolved compounds
1398  for (const auto &icd : *Doxygen::classLinkedMap)
1399  {
1400  ClassDefMutable *cd = toClassDefMutable(icd.get());
1401  if (cd && visitedClasses.find(icd.get())==visitedClasses.end())
1402  {
1404  //printf("processing unresolved=%s, iteration=%d\n",qPrint(cd->name()),iteration);
1405  /// create the scope artificially
1406  // anyway, so we can at least relate scopes properly.
1408  if (d && d!=cd && !cd->getDefFileName().isEmpty())
1409  // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1410  // for this case doxygen assumes the existence of a namespace N::N in which C is to be found!
1411  // also avoid warning for stuff imported via a tagfile.
1412  {
1414  if (dm)
1415  {
1416  dm->addInnerCompound(cd);
1417  }
1418  cd->setOuterScope(d);
1419  warn(cd->getDefFileName(),cd->getDefLine(),
1420  "Internal inconsistency: scope for class %s not "
1421  "found!",qPrint(name)
1422  );
1423  }
1424  }
1425  }
1426 }
1427 
1429 {
1430  //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
1431  //if (!inlineGroupedClasses) return;
1432  //printf("** distributeClassGroupRelations()\n");
1433 
1434  ClassDefSet visitedClasses;
1435  for (const auto &cd : *Doxygen::classLinkedMap)
1436  {
1437  //printf("Checking %s\n",qPrint(cd->name()));
1438  // distribute the group to nested classes as well
1439  if (visitedClasses.find(cd.get())==visitedClasses.end() && !cd->partOfGroups().empty())
1440  {
1441  //printf(" Candidate for merging\n");
1442  const GroupDef *gd = cd->partOfGroups().front();
1443  for (const auto &ncd : cd->getClasses())
1444  {
1445  ClassDefMutable *ncdm = toClassDefMutable(ncd);
1446  if (ncdm && ncdm->partOfGroups().empty())
1447  {
1448  //printf(" Adding %s to group '%s'\n",qPrint(ncd->name()),
1449  // gd->groupTitle());
1450  ncdm->makePartOfGroup(gd);
1451  const_cast<GroupDef*>(gd)->addClass(ncdm);
1452  }
1453  }
1454  visitedClasses.insert(cd.get()); // only visit every class once
1455  }
1456  }
1457 }
1458 
1459 //----------------------------
1460 
1461 static ClassDefMutable *createTagLessInstance(const ClassDef *rootCd,const ClassDef *templ,const QCString &fieldName)
1462 {
1463  QCString fullName = removeAnonymousScopes(templ->name());
1464  if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1465  fullName+="."+fieldName;
1466 
1467  //printf("** adding class %s based on %s\n",qPrint(fullName),qPrint(templ->name()));
1469  Doxygen::classLinkedMap->add(fullName,
1470  std::unique_ptr<ClassDef>(
1471  createClassDef(templ->getDefFileName(),
1472  templ->getDefLine(),
1473  templ->getDefColumn(),
1474  fullName,
1475  templ->compoundType()))));
1476  if (cd)
1477  {
1478  cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1479  cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1480  cd->setLanguage(templ->getLanguage());
1481  cd->setBodySegment(templ->getDefLine(),templ->getStartBodyLine(),templ->getEndBodyLine());
1482  cd->setBodyDef(templ->getBodyDef());
1483 
1484  cd->setOuterScope(rootCd->getOuterScope());
1485  if (rootCd->getOuterScope()!=Doxygen::globalScope)
1486  {
1487  DefinitionMutable *outerScope = toDefinitionMutable(rootCd->getOuterScope());
1488  if (outerScope)
1489  {
1490  outerScope->addInnerCompound(cd);
1491  }
1492  }
1493 
1494  FileDef *fd = templ->getFileDef();
1495  if (fd)
1496  {
1497  cd->setFileDef(fd);
1498  fd->insertClass(cd);
1499  }
1500  for (const auto &gd : rootCd->partOfGroups())
1501  {
1502  cd->makePartOfGroup(gd);
1503  const_cast<GroupDef*>(gd)->addClass(cd);
1504  }
1505 
1507  if (ml)
1508  {
1509  for (const auto &md : *ml)
1510  {
1511  //printf(" Member %s type=%s\n",qPrint(md->name()),md->typeString());
1512  MemberDefMutable *imd = createMemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1513  md->typeString(),md->name(),md->argsString(),md->excpString(),
1514  md->protection(),md->virtualness(),md->isStatic(),Member,
1515  md->memberType(),
1516  ArgumentList(),ArgumentList(),"");
1517  imd->setMemberClass(cd);
1518  imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1519  imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1520  imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1521  imd->setMemberSpecifiers(md->getMemberSpecifiers());
1522  imd->setMemberGroupId(md->getMemberGroupId());
1523  imd->setInitializer(md->initializer());
1524  imd->setRequiresClause(md->requiresClause());
1525  imd->setMaxInitLines(md->initializerLines());
1526  imd->setBitfields(md->bitfieldString());
1527  imd->setLanguage(md->getLanguage());
1528  cd->insertMember(imd);
1529  }
1530  }
1531  }
1532  return cd;
1533 }
1534 
1535 /** Look through the members of class \a cd and its public members.
1536  * If there is a member m of a tag less struct/union,
1537  * then we create a duplicate of the struct/union with the name of the
1538  * member to identify it.
1539  * So if cd has name S, then the tag less struct/union will get name S.m
1540  * Since tag less structs can be nested we need to call this function
1541  * recursively. Later on we need to patch the member types so we keep
1542  * track of the hierarchy of classes we create.
1543  */
1544 static void processTagLessClasses(const ClassDef *rootCd,
1545  const ClassDef *cd,
1546  ClassDefMutable *tagParentCd,
1547  const QCString &prefix,int count)
1548 {
1549  //printf("%d: processTagLessClasses %s\n",count,qPrint(cd->name()));
1550  //printf("checking members for %s\n",qPrint(cd->name()));
1551  if (tagParentCd && !cd->getClasses().empty())
1552  {
1554  if (ml)
1555  {
1556  for (const auto &md : *ml)
1557  {
1558  QCString type = md->typeString();
1559  if (type.find("::@")!=-1) // member of tag less struct/union
1560  {
1561  for (const auto &icd : cd->getClasses())
1562  {
1563  //printf(" member %s: type='%s'\n",qPrint(md->name()),qPrint(type));
1564  //printf(" comparing '%s'<->'%s'\n",qPrint(type),qPrint(icd->name()));
1565  if (type.find(icd->name())!=-1) // matching tag less struct/union
1566  {
1567  QCString name = md->name();
1568  if (md->isAnonymous()) name = "__unnamed" + name.right(name.length()-1)+"__";
1569  if (!prefix.isEmpty()) name.prepend(prefix+".");
1570  //printf(" found %s for class %s\n",qPrint(name),qPrint(cd->name()));
1571  ClassDefMutable *ncd = createTagLessInstance(rootCd,icd,name);
1572  if (ncd)
1573  {
1574  processTagLessClasses(rootCd,icd,ncd,name,count+1);
1575  //printf(" addTagged %s to %s\n",qPrint(ncd->name()),qPrint(tagParentCd->name()));
1576  ncd->setTagLessReference(icd);
1577 
1578  // replace tag-less type for generated/original member
1579  // by newly created class name.
1580  // note the difference between changing cd and tagParentCd.
1581  // for the initial call this is the same pointer, but for
1582  // recursive calls cd is the original tag-less struct (of which
1583  // there is only one instance) and tagParentCd is the newly
1584  // generated tagged struct of which there can be multiple instances!
1585  MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1586  if (pml)
1587  {
1588  for (const auto &pmd : *pml)
1589  {
1590  MemberDefMutable *pmdm = toMemberDefMutable(pmd);
1591  if (pmdm && pmd->name()==md->name())
1592  {
1593  pmdm->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1594  //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1595  }
1596  }
1597  }
1598  }
1599  }
1600  }
1601  }
1602  }
1603  }
1604  }
1605 }
1606 
1607 static void findTagLessClasses(std::vector<ClassDefMutable*> &candidates,const ClassDef *cd)
1608 {
1609  for (const auto &icd : cd->getClasses())
1610  {
1611  if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1612  {
1613  findTagLessClasses(candidates,icd);
1614  }
1615  }
1616 
1618  if (cdm)
1619  {
1620  candidates.push_back(cdm);
1621  }
1622 }
1623 
1624 static void findTagLessClasses()
1625 {
1626  std::vector<ClassDefMutable *> candidates;
1627  for (const auto &cd : *Doxygen::classLinkedMap)
1628  {
1629  Definition *scope = cd->getOuterScope();
1630  if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1631  {
1632  findTagLessClasses(candidates,cd.get());
1633  }
1634  }
1635 
1636  // since processTagLessClasses is potentially adding classes to Doxygen::classLinkedMap
1637  // we need to call it outside of the loop above, otherwise the iterator gets invalidated!
1638  for (auto &cd : candidates)
1639  {
1640  processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes
1641  }
1642 }
1643 
1644 
1645 //----------------------------------------------------------------------
1646 // build a list of all namespaces mentioned in the documentation
1647 // and all namespaces that have a documentation block before their definition.
1648 static void buildNamespaceList(const Entry *root)
1649 {
1650  if (
1651  (root->section==Entry::NAMESPACE_SEC ||
1654  ) &&
1655  !root->name.isEmpty()
1656  )
1657  {
1658  //printf("** buildNamespaceList(%s)\n",qPrint(root->name));
1659 
1660  QCString fName = root->name;
1661  if (root->section==Entry::PACKAGEDOC_SEC)
1662  {
1663  fName=substitute(fName,".","::");
1664  }
1665 
1666  QCString fullName = stripAnonymousNamespaceScope(fName);
1667  if (!fullName.isEmpty())
1668  {
1669  //printf("Found namespace %s in %s at line %d\n",qPrint(root->name),
1670  // qPrint(root->fileName), root->startLine);
1671  NamespaceDef *ndi = Doxygen::namespaceLinkedMap->find(fullName);
1672  if (ndi) // existing namespace
1673  {
1675  if (nd) // non-inline namespace
1676  {
1677  nd->setDocumentation(root->doc,root->docFile,root->docLine);
1678  nd->setName(fullName); // change name to match docs
1679  nd->addSectionsToDefinition(root->anchors);
1680  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1681  if (nd->getLanguage()==SrcLangExt_Unknown)
1682  {
1683  nd->setLanguage(root->lang);
1684  }
1685  if (root->tagInfo()==0) // if we found the namespace in a tag file
1686  // and also in a project file, then remove
1687  // the tag file reference
1688  {
1689  nd->setReference("");
1690  nd->setFileName(fullName);
1691  }
1692  nd->setMetaData(root->metaData);
1693 
1694  // file definition containing the namespace nd
1695  FileDef *fd=root->fileDef();
1696  if (nd->isArtificial())
1697  {
1698  nd->setArtificial(FALSE); // found namespace explicitly, so cannot be artificial
1699  nd->setDefFile(root->fileName,root->startLine,root->startColumn);
1700  }
1701  // insert the namespace in the file definition
1702  if (fd) fd->insertNamespace(nd);
1703  addNamespaceToGroups(root,nd);
1704  nd->setRefItems(root->sli);
1705  }
1706  }
1707  else // fresh namespace
1708  {
1709  QCString tagName;
1710  QCString tagFileName;
1711  const TagInfo *tagInfo = root->tagInfo();
1712  if (tagInfo)
1713  {
1714  tagName = tagInfo->tagName;
1715  tagFileName = tagInfo->fileName;
1716  }
1717  //printf("++ new namespace %s lang=%s tagName=%s\n",qPrint(fullName),qPrint(langToString(root->lang)),qPrint(tagName));
1718  // add namespace to the list
1720  Doxygen::namespaceLinkedMap->add(fullName,
1721  std::unique_ptr<NamespaceDef>(
1722  createNamespaceDef(tagInfo?tagName:root->fileName,root->startLine,
1723  root->startColumn,fullName,tagName,tagFileName,
1724  root->type,root->spec&Entry::Published))));
1725  if (nd)
1726  {
1727  nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1728  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1729  nd->addSectionsToDefinition(root->anchors);
1730  nd->setHidden(root->hidden);
1731  nd->setArtificial(root->artificial);
1732  nd->setLanguage(root->lang);
1733  nd->setId(root->id);
1734  nd->setMetaData(root->metaData);
1735  nd->setInline((root->spec&Entry::Inline)!=0);
1736 
1737  //printf("Adding namespace to group\n");
1738  addNamespaceToGroups(root,nd);
1739  nd->setRefItems(root->sli);
1740 
1741  // file definition containing the namespace nd
1742  FileDef *fd=root->fileDef();
1743  // insert the namespace in the file definition
1744  if (fd) fd->insertNamespace(nd);
1745 
1746  // the empty string test is needed for extract all case
1747  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1748  nd->insertUsedFile(fd);
1749  nd->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
1750  nd->setBodyDef(fd);
1751 
1752  // also add namespace to the correct structural context
1754  //printf("adding namespace %s to context %s\n",qPrint(nd->name()),d?qPrint(d->name()):"<none>");
1755  if (d==0) // we didn't find anything, create the scope artificially
1756  // anyway, so we can at least relate scopes properly.
1757  {
1758  d = buildScopeFromQualifiedName(fullName,nd->getLanguage(),tagInfo);
1760  if (dm)
1761  {
1762  dm->addInnerCompound(nd);
1763  }
1764  nd->setOuterScope(d);
1765  // TODO: Due to the order in which the tag file is written
1766  // a nested class can be found before its parent!
1767  }
1768  else
1769  {
1771  if (dm)
1772  {
1773  dm->addInnerCompound(nd);
1774  }
1775  nd->setOuterScope(d);
1776  // in case of d is an inline namespace, alias insert nd in the part scope of d.
1778  {
1779  NamespaceDef *pnd = toNamespaceDef(d);
1780  if (pnd && pnd->isInline())
1781  {
1782  d = d->getOuterScope();
1783  if (d)
1784  {
1785  dm = toDefinitionMutable(d);
1786  if (dm)
1787  {
1788  NamespaceDef *aliasNd = createNamespaceDefAlias(d,nd);
1789  dm->addInnerCompound(aliasNd);
1790  QCString aliasName = aliasNd->name();
1791  //printf("adding alias %s (%p) to %s\n",qPrint(aliasName),aliasNd,qPrint(d->name()));
1793  aliasName,std::unique_ptr<NamespaceDef>(aliasNd));
1794  }
1795  }
1796  else
1797  {
1798  break;
1799  }
1800  }
1801  else
1802  {
1803  break;
1804  }
1805  }
1806  }
1807  }
1808  }
1809  }
1810  }
1811  for (const auto &e : root->children()) buildNamespaceList(e.get());
1812 }
1813 
1814 //----------------------------------------------------------------------
1815 
1817  const QCString &name)
1818 {
1819  const NamespaceDef *usingNd =0;
1820  for (const auto &und : unl)
1821  {
1822  QCString uScope=und->name()+"::";
1823  usingNd = getResolvedNamespace(uScope+name);
1824  if (usingNd!=0) break;
1825  }
1826  return usingNd;
1827 }
1828 
1829 static void findUsingDirectives(const Entry *root)
1830 {
1831  if (root->section==Entry::USINGDIR_SEC)
1832  {
1833  //printf("Found using directive %s at line %d of %s\n",
1834  // qPrint(root->name),root->startLine,qPrint(root->fileName));
1835  QCString name=substitute(root->name,".","::");
1836  if (name.right(2)=="::")
1837  {
1838  name=name.left(name.length()-2);
1839  }
1840  if (!name.isEmpty())
1841  {
1842  const NamespaceDef *usingNd = 0;
1843  NamespaceDefMutable *nd = 0;
1844  FileDef *fd = root->fileDef();
1845  QCString nsName;
1846 
1847  // see if the using statement was found inside a namespace or inside
1848  // the global file scope.
1849  if (root->parent() && root->parent()->section==Entry::NAMESPACE_SEC &&
1850  (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1851  )
1852  {
1853  nsName=stripAnonymousNamespaceScope(root->parent()->name);
1854  if (!nsName.isEmpty())
1855  {
1856  nd = getResolvedNamespaceMutable(nsName);
1857  }
1858  }
1859 
1860  // find the scope in which the 'using' namespace is defined by prepending
1861  // the possible scopes in which the using statement was found, starting
1862  // with the most inner scope and going to the most outer scope (i.e.
1863  // file scope).
1864  int scopeOffset = nsName.length();
1865  do
1866  {
1867  QCString scope=scopeOffset>0 ?
1868  nsName.left(scopeOffset)+"::" : QCString();
1869  usingNd = getResolvedNamespace(scope+name);
1870  //printf("Trying with scope='%s' usingNd=%p\n",(scope+qPrint(name)),usingNd);
1871  if (scopeOffset==0)
1872  {
1873  scopeOffset=-1;
1874  }
1875  else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1876  {
1877  scopeOffset=0;
1878  }
1879  } while (scopeOffset>=0 && usingNd==0);
1880 
1881  if (usingNd==0 && nd) // not found, try used namespaces in this scope
1882  // or in one of the parent namespace scopes
1883  {
1884  const NamespaceDefMutable *pnd = nd;
1885  while (pnd && usingNd==0)
1886  {
1887  // also try with one of the used namespaces found earlier
1889 
1890  // goto the parent
1891  const Definition *s = pnd->getOuterScope();
1893  {
1895  }
1896  else
1897  {
1898  pnd = 0;
1899  }
1900  }
1901  }
1902  if (usingNd==0 && fd) // still nothing, also try used namespace in the
1903  // global scope
1904  {
1905  usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1906  }
1907 
1908  //printf("%s -> %s\n",qPrint(name),usingNd?qPrint(usingNd->name()):"<none>");
1909 
1910  // add the namespace the correct scope
1911  if (usingNd)
1912  {
1913  //printf("using fd=%p nd=%p\n",fd,nd);
1914  if (nd)
1915  {
1916  //printf("Inside namespace %s\n",qPrint(nd->name()));
1917  nd->addUsingDirective(usingNd);
1918  }
1919  else if (fd)
1920  {
1921  //printf("Inside file %s\n",qPrint(fd->name()));
1922  fd->addUsingDirective(usingNd);
1923  }
1924  }
1925  else // unknown namespace, but add it anyway.
1926  {
1927  //printf("++ new unknown namespace %s lang=%s\n",qPrint(name),qPrint(langToString(root->lang)));
1928  // add namespace to the list
1929  nd = toNamespaceDefMutable(
1930  Doxygen::namespaceLinkedMap->add(name,
1931  std::unique_ptr<NamespaceDef>(
1932  createNamespaceDef(root->fileName,root->startLine,root->startColumn,name))));
1933  if (nd)
1934  {
1935  nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1936  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1937  nd->addSectionsToDefinition(root->anchors);
1938  //printf("** Adding namespace %s hidden=%d\n",qPrint(name),root->hidden);
1939  nd->setHidden(root->hidden);
1940  nd->setArtificial(TRUE);
1941  nd->setLanguage(root->lang);
1942  nd->setId(root->id);
1943  nd->setMetaData(root->metaData);
1944  nd->setInline((root->spec&Entry::Inline)!=0);
1945 
1946  for (const Grouping &g : root->groups)
1947  {
1948  GroupDef *gd=0;
1950  gd->addNamespace(nd);
1951  }
1952 
1953  // insert the namespace in the file definition
1954  if (fd)
1955  {
1956  fd->insertNamespace(nd);
1957  fd->addUsingDirective(nd);
1958  }
1959 
1960  // the empty string test is needed for extract all case
1961  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1962  nd->insertUsedFile(fd);
1963  nd->setRefItems(root->sli);
1964  }
1965  }
1966  }
1967  }
1968  for (const auto &e : root->children()) findUsingDirectives(e.get());
1969 }
1970 
1971 //----------------------------------------------------------------------
1972 
1973 static void buildListOfUsingDecls(const Entry *root)
1974 {
1975  if (root->section==Entry::USINGDECL_SEC &&
1976  !(root->parent()->section&Entry::COMPOUND_MASK) // not a class/struct member
1977  )
1978  {
1979  QCString name = substitute(root->name,".","::");
1980  g_usingDeclarations.insert(name.str());
1981  }
1982  for (const auto &e : root->children()) buildListOfUsingDecls(e.get());
1983 }
1984 
1985 
1986 static void findUsingDeclarations(const Entry *root,bool filterPythonPackages)
1987 {
1988  if (root->section==Entry::USINGDECL_SEC &&
1989  !(root->parent()->section&Entry::COMPOUND_MASK) && // not a class/struct member
1990  (!filterPythonPackages || (root->lang==SrcLangExt_Python && root->fileName.endsWith("__init__.py")))
1991  )
1992  {
1993  //printf("Found using declaration %s at line %d of %s inside section %x\n",
1994  // qPrint(root->name),root->startLine,qPrint(root->fileName),
1995  // root->parent()->section);
1996  if (!root->name.isEmpty())
1997  {
1998  ClassDefMutable *usingCd = 0;
1999  NamespaceDefMutable *nd = 0;
2000  FileDef *fd = root->fileDef();
2001  QCString scName;
2002 
2003  // see if the using statement was found inside a namespace or inside
2004  // the global file scope.
2005  if (root->parent()->section == Entry::NAMESPACE_SEC)
2006  {
2007  scName=root->parent()->name;
2008  if (!scName.isEmpty())
2009  {
2010  nd = getResolvedNamespaceMutable(scName);
2011  }
2012  }
2013 
2014  // Assume the using statement was used to import a class.
2015  // Find the scope in which the 'using' namespace is defined by prepending
2016  // the possible scopes in which the using statement was found, starting
2017  // with the most inner scope and going to the most outer scope (i.e.
2018  // file scope).
2019 
2020  QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2021  usingCd = getClassMutable(name); // try direct lookup first, this is needed to get
2022  // builtin STL classes to properly resolve, e.g.
2023  // vector -> std::vector
2024  if (usingCd==0)
2025  {
2026  SymbolResolver resolver(fd);
2027  usingCd = resolver.resolveClassMutable(nd,name); // try via resolving (see also bug757509)
2028  }
2029  if (usingCd==0)
2030  {
2031  usingCd = toClassDefMutable(Doxygen::hiddenClassLinkedMap->find(name)); // check if it is already hidden
2032  }
2033 
2034  //printf("%s -> %p\n",qPrint(root->name),(void*)usingCd);
2035  if (usingCd==0) // definition not in the input => add an artificial class
2036  {
2037  Debug::print(Debug::Classes,0," New using class '%s' (sec=0x%08x)! #tArgLists=%d\n",
2038  qPrint(name),root->section,root->tArgLists.size());
2039  usingCd = toClassDefMutable(
2041  std::unique_ptr<ClassDef>(
2042  createClassDef( "<using>",1,1, name, ClassDef::Class))));
2043  if (usingCd)
2044  {
2045  usingCd->setArtificial(TRUE);
2046  usingCd->setLanguage(root->lang);
2047  }
2048  }
2049  else
2050  {
2051  Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",
2052  qPrint(usingCd->name()),
2053  nd?qPrint(nd->name()):
2054  fd?qPrint(fd->name()):
2055  "<unknown>");
2056  }
2057 
2058  if (nd)
2059  {
2060  //printf("Inside namespace %s\n",qPrint(nd->name()));
2061  nd->addUsingDeclaration(usingCd);
2062  }
2063  else if (fd)
2064  {
2065  //printf("Inside file %s\n",qPrint(fd->name()));
2066  fd->addUsingDeclaration(usingCd);
2067  }
2068  }
2069  }
2070  for (const auto &e : root->children()) findUsingDeclarations(e.get(),filterPythonPackages);
2071 }
2072 
2073 //----------------------------------------------------------------------
2074 
2075 static void findUsingDeclImports(const Entry *root)
2076 {
2077  if (root->section==Entry::USINGDECL_SEC &&
2078  (root->parent()->section&Entry::COMPOUND_MASK) // in a class/struct member
2079  )
2080  {
2081  //printf("Found using declaration %s inside section %x\n",
2082  // qPrint(root->name), root->parent()->section);
2083  QCString fullName=removeRedundantWhiteSpace(root->parent()->name);
2084  fullName=stripAnonymousNamespaceScope(fullName);
2085  fullName=stripTemplateSpecifiersFromScope(fullName);
2086  ClassDefMutable *cd = getClassMutable(fullName);
2087  if (cd)
2088  {
2089  //printf("found class %s\n",qPrint(cd->name()));
2090  int i=root->name.find("::");
2091  if (i!=-1)
2092  {
2093  QCString scope=root->name.left(i);
2094  QCString memName=root->name.right(root->name.length()-i-2);
2095  SymbolResolver resolver;
2096  const ClassDef *bcd = resolver.resolveClass(cd,scope); // todo: file in fileScope parameter
2097  if (bcd && bcd!=cd)
2098  {
2099  //printf("found class %s memName=%s\n",qPrint(bcd->name()),qPrint(memName));
2101  const MemberNameInfo *mni = mnlm.find(memName);
2102  if (mni)
2103  {
2104  for (auto &mi : *mni)
2105  {
2106  const MemberDef *md = mi->memberDef();
2107  if (md && md->protection()!=Private)
2108  {
2109  //printf("found member %s\n",mni->memberName());
2110  QCString fileName = root->fileName;
2111  if (fileName.isEmpty() && root->tagInfo())
2112  {
2113  fileName = root->tagInfo()->tagName;
2114  }
2115  const ArgumentList &templAl = md->templateArguments();
2116  const ArgumentList &al = md->argumentList();
2117  std::unique_ptr<MemberDefMutable> newMd { createMemberDef(
2118  fileName,root->startLine,root->startColumn,
2119  md->typeString(),memName,md->argsString(),
2120  md->excpString(),root->protection,root->virt,
2121  md->isStatic(),Member,md->memberType(),
2122  templAl,al,root->metaData
2123  ) };
2124  newMd->setMemberClass(cd);
2125  cd->insertMember(newMd.get());
2126  if (!root->doc.isEmpty() || !root->brief.isEmpty())
2127  {
2128  newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2129  newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2130  newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2131  }
2132  else
2133  {
2134  newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2135  newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2136  newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2137  }
2138  newMd->setDefinition(md->definition());
2139  newMd->enableCallGraph(root->callGraph);
2140  newMd->enableCallerGraph(root->callerGraph);
2141  newMd->enableReferencedByRelation(root->referencedByRelation);
2142  newMd->enableReferencesRelation(root->referencesRelation);
2143  newMd->setBitfields(md->bitfieldString());
2144  newMd->addSectionsToDefinition(root->anchors);
2145  newMd->setBodySegment(md->getDefLine(),md->getStartBodyLine(),md->getEndBodyLine());
2146  newMd->setBodyDef(md->getBodyDef());
2147  newMd->setInitializer(md->initializer());
2148  newMd->setRequiresClause(md->requiresClause());
2149  newMd->setMaxInitLines(md->initializerLines());
2150  newMd->setMemberGroupId(root->mGrpId);
2151  newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2152  newMd->setLanguage(root->lang);
2153  newMd->setId(root->id);
2155  mn->push_back(std::move(newMd));
2156  }
2157  }
2158  }
2159  }
2160  }
2161  }
2162 
2163  }
2164  for (const auto &e : root->children()) findUsingDeclImports(e.get());
2165 }
2166 
2167 //----------------------------------------------------------------------
2168 
2170 {
2171  FileDefSet visitedFiles;
2172  // then recursively add using directives found in #include files
2173  // to files that have not been visited.
2174  for (const auto &fn : *Doxygen::inputNameLinkedMap)
2175  {
2176  for (const auto &fd : *fn)
2177  {
2178  //printf("----- adding using directives for file %s\n",qPrint(fd->name()));
2179  fd->addIncludedUsingDirectives(visitedFiles);
2180  }
2181  }
2182 }
2183 
2184 //----------------------------------------------------------------------
2185 
2187  const Entry *root,
2188  ClassDefMutable *cd,
2189  MemberType mtype,
2190  const QCString &type,
2191  const QCString &name,
2192  const QCString &args,
2193  bool fromAnnScope,
2194  MemberDef *fromAnnMemb,
2195  Protection prot,
2196  Relationship related)
2197 {
2199  QCString scopeSeparator="::";
2200  SrcLangExt lang = cd->getLanguage();
2201  if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2202  {
2203  qualScope = substitute(qualScope,"::",".");
2204  scopeSeparator=".";
2205  }
2207  " class variable:\n"
2208  " '%s' '%s'::'%s' '%s' prot=%d ann=%d init='%s'\n",
2209  qPrint(type),
2210  qPrint(qualScope),
2211  qPrint(name),
2212  qPrint(args),
2213  root->protection,
2214  fromAnnScope,
2215  qPrint(root->initializer.str())
2216  );
2217 
2218  QCString def;
2219  if (!type.isEmpty())
2220  {
2221  if (related || mtype==MemberType_Friend || Config_getBool(HIDE_SCOPE_NAMES))
2222  {
2223  if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2224  {
2225  def="using "+name+" = "+type.mid(7);
2226  }
2227  else
2228  {
2229  def=type+" "+name+args;
2230  }
2231  }
2232  else
2233  {
2234  if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2235  {
2236  def="using "+qualScope+scopeSeparator+name+" = "+type.mid(7);
2237  }
2238  else
2239  {
2240  def=type+" "+qualScope+scopeSeparator+name+args;
2241  }
2242  }
2243  }
2244  else
2245  {
2246  if (Config_getBool(HIDE_SCOPE_NAMES))
2247  {
2248  def=name+args;
2249  }
2250  else
2251  {
2252  def=qualScope+scopeSeparator+name+args;
2253  }
2254  }
2255  def.stripPrefix("static ");
2256 
2257  // see if the member is already found in the same scope
2258  // (this may be the case for a static member that is initialized
2259  // outside the class)
2261  if (mn)
2262  {
2263  for (const auto &imd : *mn)
2264  {
2265  //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2266  // md->getClassDef(),cd,qPrint(type),md->typeString());
2267  MemberDefMutable *md = toMemberDefMutable(imd.get());
2268  if (md &&
2269  md->getClassDef()==cd &&
2271  // member already in the scope
2272  {
2273 
2274  if (root->lang==SrcLangExt_ObjC &&
2275  root->mtype==Property &&
2277  { // Objective-C 2.0 property
2278  // turn variable into a property
2279  md->setProtection(root->protection);
2281  }
2282  addMemberDocs(root,md,def,0,FALSE,root->spec);
2283  //printf(" Member already found!\n");
2284  return md;
2285  }
2286  }
2287  }
2288 
2289  QCString fileName = root->fileName;
2290  if (fileName.isEmpty() && root->tagInfo())
2291  {
2292  fileName = root->tagInfo()->tagName;
2293  }
2294 
2295  // new member variable, typedef or enum value
2296  std::unique_ptr<MemberDefMutable> md { createMemberDef(
2297  fileName,root->startLine,root->startColumn,
2298  type,name,args,root->exception,
2299  prot,Normal,root->stat,related,
2300  mtype,!root->tArgLists.empty() ? root->tArgLists.back() : ArgumentList(),
2301  ArgumentList(), root->metaData) };
2302  md->setTagInfo(root->tagInfo());
2303  md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2304  md->setDocumentation(root->doc,root->docFile,root->docLine);
2305  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2306  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2307  md->setDefinition(def);
2308  md->setBitfields(root->bitfields);
2309  md->addSectionsToDefinition(root->anchors);
2310  md->setFromAnonymousScope(fromAnnScope);
2311  md->setFromAnonymousMember(fromAnnMemb);
2312  //md->setIndentDepth(indentDepth);
2313  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
2314  std::string init = root->initializer.str();
2315  md->setInitializer(init.c_str());
2316  md->setMaxInitLines(root->initLines);
2317  md->setMemberGroupId(root->mGrpId);
2318  md->setMemberSpecifiers(root->spec);
2319  md->setReadAccessor(root->read);
2320  md->setWriteAccessor(root->write);
2321  md->enableCallGraph(root->callGraph);
2322  md->enableCallerGraph(root->callerGraph);
2323  md->enableReferencedByRelation(root->referencedByRelation);
2324  md->enableReferencesRelation(root->referencesRelation);
2325  md->setHidden(root->hidden);
2326  md->setArtificial(root->artificial);
2327  md->setLanguage(root->lang);
2328  md->setId(root->id);
2329  addMemberToGroups(root,md.get());
2330  md->setBodyDef(root->fileDef());
2331 
2332  //printf(" New member adding to %s (%p)!\n",qPrint(cd->name()),cd);
2333  cd->insertMember(md.get());
2334  md->setRefItems(root->sli);
2335 
2336  //TODO: insert FileDef instead of filename strings.
2337  cd->insertUsedFile(root->fileDef());
2338  root->markAsProcessed();
2339 
2340  //printf(" Adding member=%s\n",qPrint(md->name()));
2341  // add the member to the global list
2342  MemberDef *result = md.get();
2343  mn = Doxygen::memberNameLinkedMap->add(name);
2344  mn->push_back(std::move(md));
2345 
2346  return result;
2347 }
2348 
2349 //----------------------------------------------------------------------
2350 
2352  const Entry *root,
2353  MemberType mtype,
2354  const QCString &scope,
2355  const QCString &type,
2356  const QCString &name,
2357  const QCString &args,
2358  bool fromAnnScope,
2359  /*int indentDepth,*/
2360  MemberDef *fromAnnMemb)
2361 {
2363  " global variable:\n"
2364  " file='%s' type='%s' scope='%s' name='%s' args='%s' prot=`%d mtype=%d lang=%d\n",
2365  qPrint(root->fileName),
2366  qPrint(type),
2367  qPrint(scope),
2368  qPrint(name),
2369  qPrint(args),
2370  root->protection,
2371  mtype,
2372  root->lang
2373  );
2374 
2375  FileDef *fd = root->fileDef();
2376 
2377  // see if we have a typedef that should hide a struct or union
2378  if (mtype==MemberType_Typedef && Config_getBool(TYPEDEF_HIDES_STRUCT))
2379  {
2380  QCString ttype = type;
2381  ttype.stripPrefix("typedef ");
2382  if (ttype.left(7)=="struct " || ttype.left(6)=="union ")
2383  {
2384  ttype.stripPrefix("struct ");
2385  ttype.stripPrefix("union ");
2386  static const reg::Ex re(R"(\a\w*)");
2387  reg::Match match;
2388  std::string typ = ttype.str();
2389  if (reg::search(typ,match,re))
2390  {
2391  QCString typeValue = match.str();
2392  ClassDefMutable *cd = getClassMutable(typeValue);
2393  if (cd)
2394  {
2395  // this typedef should hide compound name cd, so we
2396  // change the name that is displayed from cd.
2397  cd->setClassName(name);
2398  cd->setDocumentation(root->doc,root->docFile,root->docLine);
2399  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2400  return 0;
2401  }
2402  }
2403  }
2404  }
2405 
2406  // see if the function is inside a namespace
2407  NamespaceDefMutable *nd = 0;
2408  if (!scope.isEmpty())
2409  {
2410  if (scope.find('@')!=-1) return 0; // anonymous scope!
2411  nd = getResolvedNamespaceMutable(scope);
2412  }
2413  QCString def;
2414 
2415  // determine the definition of the global variable
2416  if (nd && !nd->isAnonymous() &&
2417  !Config_getBool(HIDE_SCOPE_NAMES)
2418  )
2419  // variable is inside a namespace, so put the scope before the name
2420  {
2421  SrcLangExt lang = nd->getLanguage();
2423 
2424  if (!type.isEmpty())
2425  {
2426  if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2427  {
2428  def="using "+nd->name()+sep+name+" = "+type;
2429  }
2430  else // normal member
2431  {
2432  def=type+" "+nd->name()+sep+name+args;
2433  }
2434  }
2435  else
2436  {
2437  def=nd->name()+sep+name+args;
2438  }
2439  }
2440  else
2441  {
2442  if (!type.isEmpty() && !root->name.isEmpty())
2443  {
2444  if (name.at(0)=='@') // dummy variable representing anonymous union
2445  {
2446  def=type;
2447  }
2448  else
2449  {
2450  if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2451  {
2452  def="using "+root->name+" = "+type.mid(7);
2453  }
2454  else // normal member
2455  {
2456  def=type+" "+name+args;
2457  }
2458  }
2459  }
2460  else
2461  {
2462  def=name+args;
2463  }
2464  }
2465  def.stripPrefix("static ");
2466 
2468  if (mn)
2469  {
2470  //QCString nscope=removeAnonymousScopes(scope);
2471  //NamespaceDef *nd=0;
2472  //if (!nscope.isEmpty())
2473  if (!scope.isEmpty())
2474  {
2475  nd = getResolvedNamespaceMutable(scope);
2476  }
2477  for (const auto &imd : *mn)
2478  {
2479  MemberDefMutable *md = toMemberDefMutable(imd.get());
2480  if (md &&
2481  ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2482  root->fileName==md->getFileDef()->absFilePath()
2483  ) // both variable names in the same file
2484  || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2485  )
2486  && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2487  && !md->isEnumerate() // in C# an enum value and enum can have the same name
2488  )
2489  // variable already in the scope
2490  {
2491  bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2492  md->argsString()!=args &&
2493  args.find('[')!=-1;
2494  bool staticsInDifferentFiles =
2495  root->stat && md->isStatic() &&
2496  root->fileName!=md->getDefFileName();
2497 
2498  if (md->getFileDef() &&
2499  !isPHPArray && // not a php array
2500  !staticsInDifferentFiles
2501  )
2502  // not a php array variable
2503  {
2505  " variable already found: scope=%s\n",qPrint(md->getOuterScope()->name()));
2506  addMemberDocs(root,md,def,0,FALSE,root->spec);
2507  md->setRefItems(root->sli);
2508  // if md is a variable forward declaration and root is the definition that
2509  // turn md into the definition
2510  if (!root->explicitExternal && md->isExternal())
2511  {
2512  md->setDeclFile(md->getDefFileName(),md->getDefLine(),md->getDefColumn());
2513  md->setExplicitExternal(FALSE,root->fileName,root->startLine,root->startColumn);
2514  }
2515  // if md is the definition and root point at a declaration, then add the
2516  // declaration info
2517  else if (root->explicitExternal && !md->isExternal())
2518  {
2519  md->setDeclFile(root->fileName,root->startLine,root->startColumn);
2520  }
2521  return md;
2522  }
2523  }
2524  }
2525  }
2526 
2527  QCString fileName = root->fileName;
2528  if (fileName.isEmpty() && root->tagInfo())
2529  {
2530  fileName = root->tagInfo()->tagName;
2531  }
2532 
2534  " new variable, nd=%s tagInfo=%p!\n",nd?qPrint(nd->name()):"<global>",root->tagInfo());
2535  // new global variable, enum value or typedef
2536  std::unique_ptr<MemberDefMutable> md { createMemberDef(
2537  fileName,root->startLine,root->startColumn,
2538  type,name,args,QCString(),
2539  root->protection, Normal,root->stat,Member,
2540  mtype,!root->tArgLists.empty() ? root->tArgLists.back() : ArgumentList(),
2541  root->argList, root->metaData) };
2542  md->setTagInfo(root->tagInfo());
2543  md->setMemberSpecifiers(root->spec);
2544  md->setDocumentation(root->doc,root->docFile,root->docLine);
2545  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2546  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2547  md->addSectionsToDefinition(root->anchors);
2548  md->setFromAnonymousScope(fromAnnScope);
2549  md->setFromAnonymousMember(fromAnnMemb);
2550  std::string init = root->initializer.str();
2551  md->setInitializer(init.c_str());
2552  md->setMaxInitLines(root->initLines);
2553  md->setMemberGroupId(root->mGrpId);
2554  md->setDefinition(def);
2555  md->setLanguage(root->lang);
2556  md->setId(root->id);
2557  md->enableCallGraph(root->callGraph);
2558  md->enableCallerGraph(root->callerGraph);
2559  md->enableReferencedByRelation(root->referencedByRelation);
2560  md->enableReferencesRelation(root->referencesRelation);
2561  md->setExplicitExternal(root->explicitExternal,fileName,root->startLine,root->startColumn);
2562  //md->setOuterScope(fd);
2563  if (!root->explicitExternal)
2564  {
2565  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
2566  md->setBodyDef(fd);
2567  }
2568  addMemberToGroups(root,md.get());
2569 
2570  md->setRefItems(root->sli);
2571  if (nd && !nd->isAnonymous())
2572  {
2573  md->setNamespace(nd);
2574  nd->insertMember(md.get());
2575  }
2576 
2577  // add member to the file (we do this even if we have already inserted
2578  // it into the namespace.
2579  if (fd)
2580  {
2581  md->setFileDef(fd);
2582  fd->insertMember(md.get());
2583  }
2584 
2585  root->markAsProcessed();
2586 
2587  // add member definition to the list of globals
2588  MemberDef *result = md.get();
2589  mn = Doxygen::functionNameLinkedMap->add(name);
2590  mn->push_back(std::move(md));
2591 
2592  return result;
2593 }
2594 
2595 /*! See if the return type string \a type is that of a function pointer
2596  * \returns -1 if this is not a function pointer variable or
2597  * the index at which the closing brace of (...*name) was found.
2598  */
2599 static int findFunctionPtr(const std::string &type,SrcLangExt lang, int *pLength=0)
2600 {
2601  if (lang == SrcLangExt_Fortran || lang == SrcLangExt_VHDL)
2602  {
2603  return -1; // Fortran and VHDL do not have function pointers
2604  }
2605 
2606  static const reg::Ex re(R"(\([^)]*[*^][^)]*\))");
2607  reg::Match match;
2608  size_t i=std::string::npos;
2609  size_t l=0;
2610  if (reg::search(type,match,re)) // contains (...*...)
2611  {
2612  i = match.position();
2613  l = match.length();
2614  }
2615  size_t bb=type.find('<');
2616  size_t be=type.rfind('>');
2617 
2618  if (!type.empty() && // return type is non-empty
2619  i!=std::string::npos && // contains (...*...)
2620  type.find("operator")==std::string::npos && // not an operator
2621  (type.find(")(")==std::string::npos || type.find("typedef ")!=std::string::npos) &&
2622  // not a function pointer return type
2623  !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2624  )
2625  {
2626  if (pLength) *pLength=(int)l;
2627  //printf("findFunctionPtr=%d\n",(int)i);
2628  return (int)i;
2629  }
2630  else
2631  {
2632  //printf("findFunctionPtr=%d\n",-1);
2633  return -1;
2634  }
2635 }
2636 
2637 
2638 /*! Returns TRUE iff \a type is a class within scope \a context.
2639  * Used to detect variable declarations that look like function prototypes.
2640  */
2641 static bool isVarWithConstructor(const Entry *root)
2642 {
2643  bool result=FALSE;
2644  bool typeIsClass = false;
2645  bool typePtrType = false;
2646  QCString type;
2647  Definition *ctx = 0;
2648  FileDef *fd = root->fileDef();
2649  int ti;
2650  SymbolResolver resolver(fd);
2651 
2652  //printf("isVarWithConstructor(%s)\n",qPrint(rootNav->name()));
2653  if (root->parent()->section & Entry::COMPOUND_MASK)
2654  { // inside a class
2655  result=FALSE;
2656  goto done;
2657  }
2658  else if ((fd != nullptr) && (fd->name().right(2)==".c" || fd->name().right(2)==".h"))
2659  { // inside a .c file
2660  result=FALSE;
2661  goto done;
2662  }
2663  if (root->type.isEmpty())
2664  {
2665  result=FALSE;
2666  goto done;
2667  }
2668  if (!root->parent()->name.isEmpty())
2669  {
2671  }
2672  type = root->type;
2673  // remove qualifiers
2674  findAndRemoveWord(type,"const");
2675  findAndRemoveWord(type,"static");
2676  findAndRemoveWord(type,"volatile");
2677  typePtrType = type.find('*')!=-1 || type.find('&')!=-1;
2678  //if (type.left(6)=="const ") type=type.right(type.length()-6);
2679  if (!typePtrType)
2680  {
2681  typeIsClass = resolver.resolveClass(ctx,type)!=0;
2682  if (!typeIsClass && (ti=type.find('<'))!=-1)
2683  {
2684  typeIsClass=resolver.resolveClass(ctx,type.left(ti))!=0;
2685  }
2686  }
2687  if (typeIsClass) // now we still have to check if the arguments are
2688  // types or values. Since we do not have complete type info
2689  // we need to rely on heuristics :-(
2690  {
2691  //printf("typeIsClass\n");
2692  if (root->argList.empty())
2693  {
2694  result=FALSE; // empty arg list -> function prototype.
2695  goto done;
2696  }
2697  for (const Argument &a : root->argList)
2698  {
2699  static const reg::Ex initChars(R"([\d"'&*!^]+)");
2700  reg::Match match;
2701  if (!a.name.isEmpty() || !a.defval.isEmpty())
2702  {
2703  std::string name = a.name.str();
2704  if (reg::search(name,match,initChars) && match.position()==0)
2705  {
2706  result=TRUE;
2707  }
2708  else
2709  {
2710  result=FALSE; // arg has (type,name) pair -> function prototype
2711  }
2712  goto done;
2713  }
2714  if (!a.type.isEmpty() &&
2715  (a.type.at(a.type.length()-1)=='*' ||
2716  a.type.at(a.type.length()-1)=='&'))
2717  // type ends with * or & => pointer or reference
2718  {
2719  result=FALSE;
2720  goto done;
2721  }
2722  if (a.type.isEmpty() || resolver.resolveClass(ctx,a.type)!=0)
2723  {
2724  result=FALSE; // arg type is a known type
2725  goto done;
2726  }
2727  if (checkIfTypedef(ctx,fd,a.type))
2728  {
2729  //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2730  result=FALSE; // argument is a typedef
2731  goto done;
2732  }
2733  std::string atype = a.type.str();
2734  if (reg::search(atype,match,initChars) && match.position()==0)
2735  {
2736  result=TRUE; // argument type starts with typical initializer char
2737  goto done;
2738  }
2739  std::string resType=resolveTypeDef(ctx,a.type).str();
2740  if (resType.empty()) resType=atype;
2741  static const reg::Ex idChars(R"(\a\w*)");
2742  if (reg::search(resType,match,idChars) && match.position()==0) // resType starts with identifier
2743  {
2744  resType=match.str();
2745  //printf("resType=%s\n",resType.data());
2746  if (resType=="int" || resType=="long" ||
2747  resType=="float" || resType=="double" ||
2748  resType=="char" || resType=="void" ||
2749  resType=="signed" || resType=="unsigned" ||
2750  resType=="const" || resType=="volatile" )
2751  {
2752  result=FALSE; // type keyword -> function prototype
2753  goto done;
2754  }
2755  }
2756  }
2757  result=TRUE;
2758  }
2759 
2760 done:
2761  //printf("isVarWithConstructor(%s,%s)=%d\n",qPrint(rootNav->parent()->name()),
2762  // qPrint(root->type),result);
2763  return result;
2764 }
2765 
2766 static void addVariable(const Entry *root,int isFuncPtr=-1)
2767 {
2768  static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE);
2769 
2771  "VARIABLE_SEC: \n"
2772  " type='%s' name='%s' args='%s' bodyLine=%d mGrpId=%d relates='%s'\n",
2773  qPrint(root->type),
2774  qPrint(root->name),
2775  qPrint(root->args),
2776  root->bodyLine,
2777  root->mGrpId,
2778  qPrint(root->relates)
2779  );
2780  //printf("root->parent->name=%s\n",qPrint(root->parent->name));
2781 
2782  QCString type = root->type;
2783  QCString name = root->name;
2784  QCString args = root->args;
2785  if (type.isEmpty() && name.find("operator")==-1 &&
2786  (name.find('*')!=-1 || name.find('&')!=-1))
2787  {
2788  // recover from parse error caused by redundant braces
2789  // like in "int *(var[10]);", which is parsed as
2790  // type="" name="int *" args="(var[10])"
2791 
2792  type=name;
2793  std::string sargs = args.str();
2794  static const reg::Ex reName(R"(\a\w*)");
2795  reg::Match match;
2796  if (reg::search(sargs,match,reName))
2797  {
2798  name = match.str(); // e.g. 'var' in '(var[10])'
2799  sargs = match.suffix().str(); // e.g. '[10]) in '(var[10])'
2800  size_t j = sargs.find(')');
2801  if (j!=std::string::npos) args=sargs.substr(0,j); // extract, e.g '[10]' from '[10])'
2802  }
2803  //printf("new: type='%s' name='%s' args='%s'\n",
2804  // qPrint(type),qPrint(name),qPrint(args));
2805  }
2806  else
2807  {
2808  int i=isFuncPtr;
2809  if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(type.str(),root->lang); // for typedefs isFuncPtr is not yet set
2810  Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no");
2811  if (i>=0) // function pointer
2812  {
2813  int ai = type.find('[',i);
2814  if (ai>i) // function pointer array
2815  {
2816  args.prepend(type.right(type.length()-ai));
2817  type=type.left(ai);
2818  }
2819  else if (type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2820  {
2821  type=type.left(type.length()-1);
2822  args.prepend(") ");
2823  //printf("type=%s args=%s\n",qPrint(type),qPrint(args));
2824  }
2825  }
2826  }
2827 
2828  QCString scope;
2829  name=removeRedundantWhiteSpace(name);
2830 
2831  // find the scope of this variable
2832  Entry *p = root->parent();
2833  while ((p->section & Entry::SCOPE_MASK))
2834  {
2835  QCString scopeName = p->name;
2836  if (!scopeName.isEmpty())
2837  {
2838  scope.prepend(scopeName);
2839  break;
2840  }
2841  p=p->parent();
2842  }
2843 
2844  MemberType mtype;
2845  type=type.stripWhiteSpace();
2846  ClassDefMutable *cd=0;
2847  bool isRelated=FALSE;
2848  bool isMemberOf=FALSE;
2849 
2850  QCString classScope=stripAnonymousNamespaceScope(scope);
2851  classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2852  QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2853 
2854  if (name.findRev("::")!=-1)
2855  {
2856  if (type=="friend class" || type=="friend struct" ||
2857  type=="friend union")
2858  {
2859  cd=getClassMutable(scope);
2860  if (cd)
2861  {
2862  addVariableToClass(root, // entry
2863  cd, // class to add member to
2864  MemberType_Friend, // type of member
2865  type, // type value as string
2866  name, // name of the member
2867  args, // arguments as string
2868  FALSE, // from Anonymous scope
2869  0, // anonymous member
2870  Public, // protection
2871  Member // related to a class
2872  );
2873  }
2874  }
2875  return; /* skip this member, because it is a
2876  * static variable definition (always?), which will be
2877  * found in a class scope as well, but then we know the
2878  * correct protection level, so only then it will be
2879  * inserted in the correct list!
2880  */
2881  }
2882 
2883  if (type=="@")
2884  mtype=MemberType_EnumValue;
2885  else if (type.left(8)=="typedef ")
2886  mtype=MemberType_Typedef;
2887  else if (type.left(7)=="friend ")
2888  mtype=MemberType_Friend;
2889  else if (root->mtype==Property)
2890  mtype=MemberType_Property;
2891  else if (root->mtype==Event)
2892  mtype=MemberType_Event;
2893  else if (type.find("sequence<") != -1)
2894  mtype=sliceOpt ? MemberType_Sequence : MemberType_Typedef;
2895  else if (type.find("dictionary<") != -1)
2896  mtype=sliceOpt ? MemberType_Dictionary : MemberType_Typedef;
2897  else
2898  mtype=MemberType_Variable;
2899 
2900  if (!root->relates.isEmpty()) // related variable
2901  {
2902  isRelated=TRUE;
2903  isMemberOf=(root->relatesType == MemberOf);
2904  if (getClass(root->relates)==0 && !scope.isEmpty())
2905  scope=mergeScopes(scope,root->relates);
2906  else
2907  scope=root->relates;
2908  }
2909 
2910  cd=getClassMutable(scope);
2911  if (cd==0 && classScope!=scope) cd=getClassMutable(classScope);
2912  if (cd)
2913  {
2914  MemberDef *md=0;
2915 
2916  // if cd is an anonymous (=tag less) scope we insert the member
2917  // into a non-anonymous parent scope as well. This is needed to
2918  // be able to refer to it using \var or \fn
2919 
2920  //int indentDepth=0;
2921  int si=scope.find('@');
2922  //int anonyScopes = 0;
2923  //bool added=FALSE;
2924 
2925  static bool inlineSimpleStructs = Config_getBool(INLINE_SIMPLE_STRUCTS);
2926  if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2927  {
2928  QCString pScope;
2929  ClassDefMutable *pcd=0;
2930  pScope = scope.left(std::max(si-2,0)); // scope without tag less parts
2931  if (!pScope.isEmpty())
2932  pScope.prepend(annScopePrefix);
2933  else if (annScopePrefix.length()>2)
2934  pScope=annScopePrefix.left(annScopePrefix.length()-2);
2935  if (name.at(0)!='@')
2936  {
2937  if (!pScope.isEmpty() && (pcd=getClassMutable(pScope)))
2938  {
2939  md=addVariableToClass(root, // entry
2940  pcd, // class to add member to
2941  mtype, // member type
2942  type, // type value as string
2943  name, // member name
2944  args, // arguments as string
2945  TRUE, // from anonymous scope
2946  0, // from anonymous member
2947  root->protection,
2948  isMemberOf ? Foreign : isRelated ? Related : Member
2949  );
2950  //added=TRUE;
2951  }
2952  else // anonymous scope inside namespace or file => put variable in the global scope
2953  {
2954  if (mtype==MemberType_Variable)
2955  {
2956  md=addVariableToFile(root,mtype,pScope,type,name,args,TRUE,0);
2957  }
2958  //added=TRUE;
2959  }
2960  }
2961  }
2962 
2963  //printf("name='%s' scope=%s scope.right=%s\n",
2964  // qPrint(name),qPrint(scope),
2965  // qPrint(scope.right(scope.length()-si)));
2966  addVariableToClass(root, // entry
2967  cd, // class to add member to
2968  mtype, // member type
2969  type, // type value as string
2970  name, // name of the member
2971  args, // arguments as string
2972  FALSE, // from anonymous scope
2973  md, // from anonymous member
2974  root->protection,
2975  isMemberOf ? Foreign : isRelated ? Related : Member);
2976  }
2977  else if (!name.isEmpty()) // global variable
2978  {
2979  //printf("Inserting member in global scope %s!\n",qPrint(scope));
2980  addVariableToFile(root,mtype,scope,type,name,args,FALSE,/*0,*/0);
2981  }
2982 
2983 }
2984 
2985 //----------------------------------------------------------------------
2986 // Searches the Entry tree for typedef documentation sections.
2987 // If found they are stored in their class or in the global list.
2988 static void buildTypedefList(const Entry *root)
2989 {
2990  //printf("buildVarList(%s)\n",qPrint(rootNav->name()));
2991  if (!root->name.isEmpty() &&
2992  root->section==Entry::VARIABLE_SEC &&
2993  root->type.find("typedef ")!=-1 // its a typedef
2994  )
2995  {
2996  addVariable(root);
2997  }
2998  for (const auto &e : root->children())
2999  if (e->section!=Entry::ENUM_SEC)
3000  buildTypedefList(e.get());
3001 }
3002 
3003 //----------------------------------------------------------------------
3004 // Searches the Entry tree for sequence documentation sections.
3005 // If found they are stored in the global list.
3006 static void buildSequenceList(const Entry *root)
3007 {
3008  if (!root->name.isEmpty() &&
3009  root->section==Entry::VARIABLE_SEC &&
3010  root->type.find("sequence<")!=-1 // it's a sequence
3011  )
3012  {
3013  addVariable(root);
3014  }
3015  for (const auto &e : root->children())
3016  if (e->section!=Entry::ENUM_SEC)
3017  buildSequenceList(e.get());
3018 }
3019 
3020 //----------------------------------------------------------------------
3021 // Searches the Entry tree for dictionary documentation sections.
3022 // If found they are stored in the global list.
3023 static void buildDictionaryList(const Entry *root)
3024 {
3025  if (!root->name.isEmpty() &&
3026  root->section==Entry::VARIABLE_SEC &&
3027  root->type.find("dictionary<")!=-1 // it's a dictionary
3028  )
3029  {
3030  addVariable(root);
3031  }
3032  for (const auto &e : root->children())
3033  if (e->section!=Entry::ENUM_SEC)
3034  buildDictionaryList(e.get());
3035 }
3036 
3037 //----------------------------------------------------------------------
3038 // Searches the Entry tree for Variable documentation sections.
3039 // If found they are stored in their class or in the global list.
3040 
3041 static void buildVarList(const Entry *root)
3042 {
3043  //printf("buildVarList(%s) section=%08x\n",qPrint(rootNav->name()),rootNav->section());
3044  int isFuncPtr=-1;
3045  if (!root->name.isEmpty() &&
3046  (root->type.isEmpty() || g_compoundKeywords.find(root->type.str())==g_compoundKeywords.end()) &&
3047  (
3048  (root->section==Entry::VARIABLE_SEC // it's a variable
3049  ) ||
3050  (root->section==Entry::FUNCTION_SEC && // or maybe a function pointer variable
3051  (isFuncPtr=findFunctionPtr(root->type.str(),root->lang))!=-1
3052  ) ||
3053  (root->section==Entry::FUNCTION_SEC && // class variable initialized by constructor
3054  isVarWithConstructor(root)
3055  )
3056  )
3057  ) // documented variable
3058  {
3059  addVariable(root,isFuncPtr);
3060  }
3061  for (const auto &e : root->children())
3062  if (e->section!=Entry::ENUM_SEC)
3063  buildVarList(e.get());
3064 }
3065 
3066 //----------------------------------------------------------------------
3067 // Searches the Entry tree for Interface sections (UNO IDL only).
3068 // If found they are stored in their service or in the global list.
3069 //
3070 
3071 static void addInterfaceOrServiceToServiceOrSingleton(
3072  const Entry *root,
3073  ClassDefMutable *cd,
3074  QCString const& rname)
3075 {
3076  FileDef *fd = root->fileDef();
3077  enum MemberType type = (root->section==Entry::EXPORTED_INTERFACE_SEC)
3080  QCString fileName = root->fileName;
3081  if (fileName.isEmpty() && root->tagInfo())
3082  {
3083  fileName = root->tagInfo()->tagName;
3084  }
3085  std::unique_ptr<MemberDefMutable> md { createMemberDef(
3086  fileName, root->startLine, root->startColumn, root->type, rname,
3087  "", "", root->protection, root->virt, root->stat, Member,
3088  type, ArgumentList(), root->argList, root->metaData) };
3089  md->setTagInfo(root->tagInfo());
3090  md->setMemberClass(cd);
3091  md->setDocumentation(root->doc,root->docFile,root->docLine);
3092  md->setDocsForDefinition(false);
3093  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3094  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3095  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
3096  md->setMemberSpecifiers(root->spec);
3097  md->setMemberGroupId(root->mGrpId);
3098  md->setTypeConstraints(root->typeConstr);
3099  md->setLanguage(root->lang);
3100  md->setBodyDef(fd);
3101  md->setFileDef(fd);
3102  md->addSectionsToDefinition(root->anchors);
3103  QCString const def = root->type + " " + rname;
3104  md->setDefinition(def);
3105  md->enableCallGraph(root->callGraph);
3106  md->enableCallerGraph(root->callerGraph);
3107  md->enableReferencedByRelation(root->referencedByRelation);
3108  md->enableReferencesRelation(root->referencesRelation);
3109 
3111  " Interface Member:\n"
3112  " '%s' '%s' proto=%d\n"
3113  " def='%s'\n",
3114  qPrint(root->type),
3115  qPrint(rname),
3116  root->proto,
3117  qPrint(def)
3118  );
3119 
3120 
3121  // add member to the class cd
3122  cd->insertMember(md.get());
3123  // also add the member as a "base" (to get nicer diagrams)
3124  // "optional" interface/service get Protected which turns into dashed line
3125  BaseInfo base(rname,
3126  (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3127  TemplateNameMap templateNames;
3128  findClassRelation(root,cd,cd,&base,templateNames,DocumentedOnly,true) ||
3129  findClassRelation(root,cd,cd,&base,templateNames,Undocumented,true);
3130  // add file to list of used files
3131  cd->insertUsedFile(fd);
3132 
3133  addMemberToGroups(root,md.get());
3134  root->markAsProcessed();
3135  md->setRefItems(root->sli);
3136 
3137  // add member to the global list of all members
3139  mn->push_back(std::move(md));
3140 }
3141 
3142 static void buildInterfaceAndServiceList(const Entry *root)
3143 {
3146  {
3148  "EXPORTED_INTERFACE_SEC:\n"
3149  " '%s' '%s'::'%s' '%s' relates='%s' relatesType='%d' file='%s' line='%d' bodyLine='%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3150  qPrint(root->type),
3151  qPrint(root->parent()->name),
3152  qPrint(root->name),
3153  qPrint(root->args),
3154  qPrint(root->relates),
3155  root->relatesType,
3156  qPrint(root->fileName),
3157  root->startLine,
3158  root->bodyLine,
3159  root->tArgLists.size(),
3160  root->mGrpId,
3161  root->spec,
3162  root->proto,
3163  qPrint(root->docFile)
3164  );
3165 
3166  QCString rname = removeRedundantWhiteSpace(root->name);
3167 
3168  if (!rname.isEmpty())
3169  {
3170  QCString scope = root->parent()->name;
3171  ClassDefMutable *cd = getClassMutable(scope);
3172  assert(cd);
3173  if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3174  (ClassDef::Service == cd->compoundType()) ||
3175  (ClassDef::Singleton == cd->compoundType())))
3176  {
3177  addInterfaceOrServiceToServiceOrSingleton(root,cd,rname);
3178  }
3179  else
3180  {
3181  assert(false); // was checked by scanner.l
3182  }
3183  }
3184  else if (rname.isEmpty())
3185  {
3186  warn(root->fileName,root->startLine,
3187  "Illegal member name found.");
3188  }
3189  }
3190  // can only have these in IDL anyway
3191  switch (root->lang)
3192  {
3193  case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3194  case SrcLangExt_IDL:
3195  for (const auto &e : root->children()) buildInterfaceAndServiceList(e.get());
3196  break;
3197  default:
3198  return; // nothing to do here
3199  }
3200 }
3201 
3202 
3203 //----------------------------------------------------------------------
3204 // Searches the Entry tree for Function sections.
3205 // If found they are stored in their class or in the global list.
3206 
3207 static void addMethodToClass(const Entry *root,ClassDefMutable *cd,
3208  const QCString &rtype,const QCString &rname,const QCString &rargs,
3209  bool isFriend,
3210  Protection protection,bool stat,Specifier virt,uint64 spec,
3211  const QCString &relates
3212  )
3213 {
3214  FileDef *fd=root->fileDef();
3215 
3216  QCString type = rtype;
3217  QCString args = rargs;
3218 
3219  QCString name=removeRedundantWhiteSpace(rname);
3220  if (name.left(2)=="::") name=name.right(name.length()-2);
3221 
3222  MemberType mtype;
3223  if (isFriend) mtype=MemberType_Friend;
3224  else if (root->mtype==Signal) mtype=MemberType_Signal;
3225  else if (root->mtype==Slot) mtype=MemberType_Slot;
3226  else if (root->mtype==DCOP) mtype=MemberType_DCOP;
3227  else mtype=MemberType_Function;
3228 
3229  // strip redundant template specifier for constructors
3230  int i = -1;
3231  int j = -1;
3232  if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3233  name.left(9)!="operator " && // not operator
3234  (i=name.find('<'))!=-1 && // containing <
3235  (j=name.find('>'))!=-1 && // or >
3236  (j!=i+2 || name.at(i+1)!='=') // but not the C++20 spaceship operator <=>
3237  )
3238  {
3239  name=name.left(i);
3240  }
3241 
3242  QCString fileName = root->fileName;
3243  if (fileName.isEmpty() && root->tagInfo())
3244  {
3245  fileName = root->tagInfo()->tagName;
3246  }
3247 
3248  //printf("root->name='%s; args='%s' root->argList='%s'\n",
3249  // qPrint(root->name),qPrint(args),qPrint(argListToString(root->argList))
3250  // );
3251 
3252  // adding class member
3253  std::unique_ptr<MemberDefMutable> md { createMemberDef(
3254  fileName,root->startLine,root->startColumn,
3255  type,name,args,root->exception,
3256  protection,virt,
3257  stat && root->relatesType != MemberOf,
3258  relates.isEmpty() ? Member :
3259  root->relatesType == MemberOf ? Foreign : Related,
3260  mtype,!root->tArgLists.empty() ? root->tArgLists.back() : ArgumentList(),
3261  root->argList, root->metaData) };
3262  md->setTagInfo(root->tagInfo());
3263  md->setMemberClass(cd);
3264  md->setDocumentation(root->doc,root->docFile,root->docLine);
3265  md->setDocsForDefinition(!root->proto);
3266  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3267  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3268  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
3269  md->setMemberSpecifiers(spec);
3270  md->setMemberGroupId(root->mGrpId);
3271  md->setTypeConstraints(root->typeConstr);
3272  md->setLanguage(root->lang);
3273  md->setRequiresClause(root->req);
3274  md->setId(root->id);
3275  md->setBodyDef(fd);
3276  md->setFileDef(fd);
3277  md->addSectionsToDefinition(root->anchors);
3278  QCString def;
3280  SrcLangExt lang = cd->getLanguage();
3281  QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3282  if (scopeSeparator!="::")
3283  {
3284  qualScope = substitute(qualScope,"::",scopeSeparator);
3285  }
3286  if (lang==SrcLangExt_PHP)
3287  {
3288  // for PHP we use Class::method and Namespace\method
3289  scopeSeparator="::";
3290  }
3291 // QCString optArgs = root->argList.empty() ? args : QCString();
3292  if (!relates.isEmpty() || isFriend || Config_getBool(HIDE_SCOPE_NAMES))
3293  {
3294  if (!type.isEmpty())
3295  {
3296  def=type+" "+name; //+optArgs;
3297  }
3298  else
3299  {
3300  def=name; //+optArgs;
3301  }
3302  }
3303  else
3304  {
3305  if (!type.isEmpty())
3306  {
3307  def=type+" "+qualScope+scopeSeparator+name; //+optArgs;
3308  }
3309  else
3310  {
3311  def=qualScope+scopeSeparator+name; //+optArgs;
3312  }
3313  }
3314  if (def.left(7)=="friend ") def=def.right(def.length()-7);
3315  md->setDefinition(def);
3316  md->enableCallGraph(root->callGraph);
3317  md->enableCallerGraph(root->callerGraph);
3318  md->enableReferencedByRelation(root->referencedByRelation);
3319  md->enableReferencesRelation(root->referencesRelation);
3320 
3322  " Func Member:\n"
3323  " '%s' '%s'::'%s' '%s' proto=%d\n"
3324  " def='%s'\n",
3325  qPrint(type),
3326  qPrint(qualScope),
3327  qPrint(rname),
3328  qPrint(args),
3329  root->proto,
3330  qPrint(def)
3331  );
3332 
3333  // add member to the class cd
3334  cd->insertMember(md.get());
3335  // add file to list of used files
3336  cd->insertUsedFile(fd);
3337 
3338  addMemberToGroups(root,md.get());
3339  root->markAsProcessed();
3340  md->setRefItems(root->sli);
3341 
3342  // add member to the global list of all members
3343  //printf("Adding member=%s class=%s\n",qPrint(md->name()),qPrint(cd->name()));
3345  mn->push_back(std::move(md));
3346 }
3347 
3348 //------------------------------------------------------------------------------------------
3349 
3350 static void addGlobalFunction(const Entry *root,const QCString &rname,const QCString &sc)
3351 {
3352  QCString scope = sc;
3353  Debug::print(Debug::Functions,0," --> new function %s found!\n",qPrint(rname));
3354  //printf("New function type='%s' name='%s' args='%s' bodyLine=%d\n",
3355  // qPrint(root->type),qPrint(rname),qPrint(root->args),root->bodyLine);
3356 
3357  // new global function
3358  QCString name=removeRedundantWhiteSpace(rname);
3359  std::unique_ptr<MemberDefMutable> md { createMemberDef(
3360  root->fileName,root->startLine,root->startColumn,
3361  root->type,name,root->args,root->exception,
3362  root->protection,root->virt,root->stat,Member,
3364  !root->tArgLists.empty() ? root->tArgLists.back() : ArgumentList(),
3365  root->argList,root->metaData) };
3366 
3367  md->setTagInfo(root->tagInfo());
3368  md->setLanguage(root->lang);
3369  md->setId(root->id);
3370  md->setDocumentation(root->doc,root->docFile,root->docLine);
3371  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3372  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3373  md->setPrototype(root->proto,root->fileName,root->startLine,root->startColumn);
3374  md->setDocsForDefinition(!root->proto);
3375  md->setTypeConstraints(root->typeConstr);
3376  //md->setBody(root->body);
3377  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
3378  FileDef *fd=root->fileDef();
3379  md->setBodyDef(fd);
3380  md->addSectionsToDefinition(root->anchors);
3381  md->setMemberSpecifiers(root->spec);
3382  md->setMemberGroupId(root->mGrpId);
3383  md->setRequiresClause(root->req);
3384 
3385  NamespaceDefMutable *nd = 0;
3386  // see if the function is inside a namespace that was not part of
3387  // the name already (in that case nd should be non-zero already)
3388  if (root->parent()->section == Entry::NAMESPACE_SEC )
3389  {
3390  //QCString nscope=removeAnonymousScopes(root->parent()->name);
3391  QCString nscope=root->parent()->name;
3392  if (!nscope.isEmpty())
3393  {
3394  nd = getResolvedNamespaceMutable(nscope);
3395  }
3396  }
3397 
3398  if (!scope.isEmpty())
3399  {
3401  if (sep!="::")
3402  {
3403  scope = substitute(scope,"::",sep);
3404  }
3405  scope+=sep;
3406  }
3407 
3408  QCString def;
3409  //QCString optArgs = root->argList.empty() ? QCString() : root->args;
3410  if (!root->type.isEmpty())
3411  {
3412  def=root->type+" "+scope+name; //+optArgs;
3413  }
3414  else
3415  {
3416  def=scope+name; //+optArgs;
3417  }
3419  " Global Function:\n"
3420  " '%s' '%s'::'%s' '%s' proto=%d\n"
3421  " def='%s'\n",
3422  qPrint(root->type),
3423  qPrint(root->parent()->name),
3424  qPrint(rname),
3425  qPrint(root->args),
3426  root->proto,
3427  qPrint(def)
3428  );
3429  md->setDefinition(def);
3430  md->enableCallGraph(root->callGraph);
3431  md->enableCallerGraph(root->callerGraph);
3432  md->enableReferencedByRelation(root->referencedByRelation);
3433  md->enableReferencesRelation(root->referencesRelation);
3434  //if (root->mGrpId!=-1)
3435  //{
3436  // md->setMemberGroup(memberGroupDict[root->mGrpId]);
3437  //}
3438 
3439  md->setRefItems(root->sli);
3440  if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3441  {
3442  // add member to namespace
3443  md->setNamespace(nd);
3444  nd->insertMember(md.get());
3445  }
3446  if (fd)
3447  {
3448  // add member to the file (we do this even if we have already
3449  // inserted it into the namespace)
3450  md->setFileDef(fd);
3451  fd->insertMember(md.get());
3452  }
3453 
3454  addMemberToGroups(root,md.get());
3455  if (root->relatesType == Simple) // if this is a relatesalso command,
3456  // allow find Member to pick it up
3457  {
3458  root->markAsProcessed(); // Otherwise we have finished with this entry.
3459  }
3460 
3461  // add member to the list of file members
3462  //printf("Adding member=%s\n",qPrint(md->name()));
3464  mn->push_back(std::move(md));
3465 }
3466 
3467 //------------------------------------------------------------------------------------------
3468 
3469 static void buildFunctionList(const Entry *root)
3470 {
3471  if (root->section==Entry::FUNCTION_SEC)
3472  {
3474  "FUNCTION_SEC:\n"
3475  " '%s' '%s'::'%s' '%s' relates='%s' relatesType='%d' file='%s' line='%d' bodyLine='%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3476  qPrint(root->type),
3477  qPrint(root->parent()->name),
3478  qPrint(root->name),
3479  qPrint(root->args),
3480  qPrint(root->relates),
3481  root->relatesType,
3482  qPrint(root->fileName),
3483  root->startLine,
3484  root->bodyLine,
3485  root->tArgLists.size(),
3486  root->mGrpId,
3487  root->spec,
3488  root->proto,
3489  qPrint(root->docFile)
3490  );
3491 
3492  bool isFriend=root->type.find("friend ")!=-1;
3493  QCString rname = removeRedundantWhiteSpace(root->name);
3494  //printf("rname=%s\n",qPrint(rname));
3495 
3496  QCString scope=root->parent()->name; //stripAnonymousNamespaceScope(root->parent->name);
3497  if (!rname.isEmpty() && scope.find('@')==-1)
3498  {
3499  ClassDefMutable *cd=0;
3500  // check if this function's parent is a class
3502 
3503  FileDef *rfd=root->fileDef();
3504 
3505  int memIndex=rname.findRev("::");
3506 
3507  cd=getClassMutable(scope);
3508  if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3509  {
3510  // strip scope from name
3511  rname=rname.right(rname.length()-root->parent()->name.length()-2);
3512  }
3513 
3514  bool isMember=FALSE;
3515  if (memIndex!=-1)
3516  {
3517  int ts=rname.find('<');
3518  int te=rname.find('>');
3519  if (memIndex>0 && (ts==-1 || te==-1))
3520  {
3521  // note: the following code was replaced by inMember=TRUE to deal with a
3522  // function rname='X::foo' of class X inside a namespace also called X...
3523  // bug id 548175
3524  //nd = Doxygen::namespaceLinkedMap->find(rname.left(memIndex));
3525  //isMember = nd==0;
3526  //if (nd)
3527  //{
3528  // // strip namespace scope from name
3529  // scope=rname.left(memIndex);
3530  // rname=rname.right(rname.length()-memIndex-2);
3531  //}
3532  isMember = TRUE;
3533  }
3534  else
3535  {
3536  isMember=memIndex<ts || memIndex>te;
3537  }
3538  }
3539 
3540  if (!root->parent()->name.isEmpty() &&
3541  (root->parent()->section & Entry::COMPOUND_MASK) &&
3542  cd
3543  )
3544  {
3545  Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
3546  qPrint(rname),qPrint(cd->name()));
3547  addMethodToClass(root,cd,root->type,rname,root->args,isFriend,
3548  root->protection,root->stat,root->virt,root->spec,root->relates);
3549  }
3550  else if (!((root->parent()->section & Entry::COMPOUND_MASK)
3551  || root->parent()->section==Entry::OBJCIMPL_SEC
3552  ) &&
3553  !isMember &&
3554  (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3555  root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3556  )
3557  // no member => unrelated function
3558  {
3559  /* check the uniqueness of the function name in the file.
3560  * A file could contain a function prototype and a function definition
3561  * or even multiple function prototypes.
3562  */
3563  bool found=FALSE;
3564  MemberName *mn;
3565  MemberDef *md_found=0;
3566  if ((mn=Doxygen::functionNameLinkedMap->find(rname)))
3567  {
3568  Debug::print(Debug::Functions,0," --> function %s already found!\n",qPrint(rname));
3569  for (const auto &imd : *mn)
3570  {
3571  MemberDefMutable *md = toMemberDefMutable(imd.get());
3572  if (md)
3573  {
3574  const NamespaceDef *mnd = md->getNamespaceDef();
3575  NamespaceDef *rnd = 0;
3576  //printf("root namespace=%s\n",qPrint(rootNav->parent()->name()));
3577  QCString fullScope = scope;
3578  QCString parentScope = root->parent()->name;
3579  if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3580  {
3581  if (!scope.isEmpty()) fullScope.prepend("::");
3582  fullScope.prepend(parentScope);
3583  }
3584  //printf("fullScope=%s\n",qPrint(fullScope));
3585  rnd = getResolvedNamespace(fullScope);
3586  const FileDef *mfd = md->getFileDef();
3587  QCString nsName,rnsName;
3588  if (mnd) nsName = mnd->name();
3589  if (rnd) rnsName = rnd->name();
3590  //printf("matching arguments for %s%s %s%s\n",
3591  // qPrint(md->name()),md->argsString(),qPrint(rname),qPrint(argListToString(root->argList)));
3592  const ArgumentList &mdAl = md->argumentList();
3593  const ArgumentList &mdTempl = md->templateArguments();
3594 
3595  // in case of template functions, we need to check if the
3596  // functions have the same number of template parameters
3597  bool sameNumTemplateArgs = TRUE;
3598  bool matchingReturnTypes = TRUE;
3599  bool sameRequiresClause = TRUE;
3600  if (!mdTempl.empty() && !root->tArgLists.empty())
3601  {
3602  if (mdTempl.size()!=root->tArgLists.back().size())
3603  {
3604  sameNumTemplateArgs = FALSE;
3605  }
3606  if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3607  {
3608  matchingReturnTypes = FALSE;
3609  }
3610  if (md->requiresClause()!=root->req)
3611  {
3612  sameRequiresClause = FALSE;
3613  }
3614  }
3615 
3616  bool staticsInDifferentFiles =
3617  root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3618 
3619  if (
3620  matchArguments2(md->getOuterScope(),mfd,&mdAl,
3621  rnd ? rnd : Doxygen::globalScope,rfd,&root->argList,
3622  FALSE) &&
3623  sameNumTemplateArgs &&
3624  matchingReturnTypes &&
3625  sameRequiresClause &&
3626  !staticsInDifferentFiles
3627  )
3628  {
3629  GroupDef *gd=0;
3630  if (!root->groups.empty() && !root->groups.front().groupname.isEmpty())
3631  {
3632  gd = Doxygen::groupLinkedMap->find(root->groups.front().groupname);
3633  }
3634  //printf("match!\n");
3635  //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,qPrint(nsName),qPrint(rnsName));
3636  // see if we need to create a new member
3637  found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace
3638  ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and
3639  mfd->absFilePath()==root->fileName // prototype in the same file
3640  )
3641  );
3642  // otherwise, allow a duplicate global member with the same argument list
3643  if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3644  {
3645  // member is already in the group, so we don't want to add it again.
3646  found=TRUE;
3647  }
3648 
3649  //printf("combining function with prototype found=%d in namespace %s\n",
3650  // found,qPrint(nsName));
3651 
3652  if (found)
3653  {
3654  // merge argument lists
3655  ArgumentList mergedArgList = root->argList;
3656  mergeArguments(const_cast<ArgumentList&>(mdAl),mergedArgList,!root->doc.isEmpty());
3657  // merge documentation
3658  if (md->documentation().isEmpty() && !root->doc.isEmpty())
3659  {
3660  if (root->proto)
3661  {
3662  //printf("setDeclArgumentList to %p\n",argList);
3664  }
3665  else
3666  {
3667  md->moveArgumentList(stringToArgumentList(root->lang,root->args));
3668  }
3669  }
3670 
3671  md->setDocumentation(root->doc,root->docFile,root->docLine);
3672  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3673  md->setDocsForDefinition(!root->proto);
3674  if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3675  {
3676  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
3677  md->setBodyDef(rfd);
3678  }
3679 
3680  if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3681  {
3682  md->setArgsString(root->args);
3683  }
3684  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3685 
3686  md->addSectionsToDefinition(root->anchors);
3687 
3688  md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3689  md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3692 
3693  // merge ingroup specifiers
3694  if (md->getGroupDef()==0 && !root->groups.empty())
3695  {
3696  addMemberToGroups(root,md);
3697  }
3698  else if (md->getGroupDef()!=0 && root->groups.empty())
3699  {
3700  //printf("existing member is grouped, new member not\n");
3701  }
3702  else if (md->getGroupDef()!=0 && !root->groups.empty())
3703  {
3704  //printf("both members are grouped\n");
3705  }
3706 
3707  // if md is a declaration and root is the corresponding
3708  // definition, then turn md into a definition.
3709  if (md->isPrototype() && !root->proto)
3710  {
3711  md->setDeclFile(md->getDefFileName(),md->getDefLine(),md->getDefColumn());
3712  md->setPrototype(FALSE,root->fileName,root->startLine,root->startColumn);
3713  }
3714  // if md is already the definition, then add the declaration info
3715  else if (!md->isPrototype() && root->proto)
3716  {
3717  md->setDeclFile(root->fileName,root->startLine,root->startColumn);
3718  }
3719  }
3720  }
3721  }
3722  if (found)
3723  {
3724  md_found = md;
3725  break;
3726  }
3727  }
3728  }
3729  if (!found) /* global function is unique with respect to the file */
3730  {
3731  addGlobalFunction(root,rname,scope);
3732  }
3733  else
3734  {
3735  FileDef *fd=root->fileDef();
3736  if (fd)
3737  {
3738  // add member to the file (we do this even if we have already
3739  // inserted it into the namespace)
3740  fd->insertMember(md_found);
3741  }
3742  }
3743 
3744  //printf("unrelated function %d '%s' '%s' '%s'\n",
3745  // root->parent->section,qPrint(root->type),qPrint(rname),qPrint(root->args));
3746  }
3747  else
3748  {
3749  Debug::print(Debug::Functions,0," --> %s not processed!\n",qPrint(rname));
3750  }
3751  }
3752  else if (rname.isEmpty())
3753  {
3754  warn(root->fileName,root->startLine,
3755  "Illegal member name found."
3756  );
3757  }
3758  }
3759  for (const auto &e : root->children()) buildFunctionList(e.get());
3760 }
3761 
3762 //----------------------------------------------------------------------
3763 
3764 static void findFriends()
3765 {
3766  //printf("findFriends()\n");
3767  for (const auto &fn : *Doxygen::functionNameLinkedMap) // for each global function name
3768  {
3769  //printf("Function name='%s'\n",fn->memberName());
3770  MemberName *mn;
3771  if ((mn=Doxygen::memberNameLinkedMap->find(fn->memberName())))
3772  { // there are members with the same name
3773  //printf("Function name is also a member name\n");
3774  // for each function with that name
3775  for (const auto &ifmd : *fn)
3776  {
3777  MemberDefMutable *fmd = toMemberDefMutable(ifmd.get());
3778  // for each member with that name
3779  for (const auto &immd : *mn)
3780  {
3781  MemberDefMutable *mmd = toMemberDefMutable(immd.get());
3782  //printf("Checking for matching arguments
3783  // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3784  // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3785  if (fmd && mmd &&
3786  (mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3787  matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), &mmd->argumentList(),
3788  fmd->getOuterScope(), fmd->getFileDef(), &fmd->argumentList(),
3789  TRUE
3790  )
3791 
3792  ) // if the member is related and the arguments match then the
3793  // function is actually a friend.
3794  {
3795  const ArgumentList &mmdAl = mmd->argumentList();
3796  const ArgumentList &fmdAl = fmd->argumentList();
3797  mergeArguments(const_cast<ArgumentList&>(mmdAl),const_cast<ArgumentList&>(fmdAl));
3798  if (!fmd->documentation().isEmpty())
3799  {
3800  mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3801  }
3802  else if (!mmd->documentation().isEmpty())
3803  {
3804  fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3805  }
3806  if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3807  {
3808  mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3809  }
3810  else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3811  {
3812  fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3813  }
3814  if (!fmd->inbodyDocumentation().isEmpty())
3815  {
3817  }
3818  else if (!mmd->inbodyDocumentation().isEmpty())
3819  {
3821  }
3822  //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3823  if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3824  {
3825  mmd->setBodySegment(fmd->getDefLine(),fmd->getStartBodyLine(),fmd->getEndBodyLine());
3826  mmd->setBodyDef(fmd->getBodyDef());
3827  //mmd->setBodyMember(fmd);
3828  }
3829  else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3830  {
3831  fmd->setBodySegment(mmd->getDefLine(),mmd->getStartBodyLine(),mmd->getEndBodyLine());
3832  fmd->setBodyDef(mmd->getBodyDef());
3833  //fmd->setBodyMember(mmd);
3834  }
3836 
3837  mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3838  mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3841 
3842  fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3843  fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3846  }
3847  }
3848  }
3849  }
3850  }
3851 }
3852 
3853 //----------------------------------------------------------------------
3854 
3856 {
3857  //printf("---- transferFunctionDocumentation()\n");
3858 
3859  // find matching function declaration and definitions.
3860  for (const auto &mn : *Doxygen::functionNameLinkedMap)
3861  {
3862  //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3863  /* find a matching function declaration and definition for this function */
3864  for (const auto &imdec : *mn)
3865  {
3866  MemberDefMutable *mdec = toMemberDefMutable(imdec.get());
3867  if (mdec &&
3868  (mdec->isPrototype() ||
3869  (mdec->isVariable() && mdec->isExternal())
3870  ))
3871  {
3872  for (const auto &imdef : *mn)
3873  {
3874  MemberDefMutable *mdef = toMemberDefMutable(imdef.get());
3875  if (mdef && mdec!=mdef &&
3876  mdec->getNamespaceDef()==mdef->getNamespaceDef())
3877  {
3879  }
3880  }
3881  }
3882  }
3883  }
3884 }
3885 
3886 //----------------------------------------------------------------------
3887 
3889 {
3890  for (const auto &mn : *Doxygen::functionNameLinkedMap)
3891  {
3892  MemberDefMutable *mdef=0,*mdec=0;
3893  /* find a matching function declaration and definition for this function */
3894  for (const auto &imd : *mn)
3895  {
3896  MemberDefMutable *md = toMemberDefMutable(imd.get());
3897  if (md)
3898  {
3899  if (md->isPrototype())
3900  mdec=md;
3901  else if (md->isVariable() && md->isExternal())
3902  mdec=md;
3903 
3904  if (md->isFunction() && !md->isStatic() && !md->isPrototype())
3905  mdef=md;
3906  else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3907  mdef=md;
3908  }
3909 
3910  if (mdef && mdec) break;
3911  }
3912  if (mdef && mdec)
3913  {
3914  const ArgumentList &mdefAl = mdef->argumentList();
3915  const ArgumentList &mdecAl = mdec->argumentList();
3916  if (
3917  matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),const_cast<ArgumentList*>(&mdefAl),
3918  mdec->getOuterScope(),mdec->getFileDef(),const_cast<ArgumentList*>(&mdecAl),
3919  TRUE
3920  )
3921  ) /* match found */
3922  {
3923  mdef->mergeReferences(mdec);
3924  mdec->mergeReferences(mdef);
3925  mdef->mergeReferencedBy(mdec);
3926  mdec->mergeReferencedBy(mdef);
3927  }
3928  }
3929  }
3930 }
3931 
3932 //----------------------------------------------------------------------
3933 
3935 {
3936  // find match between function declaration and definition for
3937  // related functions
3938  for (const auto &mn : *Doxygen::functionNameLinkedMap)
3939  {
3940  /* find a matching function declaration and definition for this function */
3941  // for each global function
3942  for (const auto &imd : *mn)
3943  {
3944  MemberDefMutable *md = toMemberDefMutable(imd.get());
3945  if (md)
3946  {
3947  //printf(" Function '%s'\n",qPrint(md->name()));
3948  MemberName *rmn;
3949  if ((rmn=Doxygen::memberNameLinkedMap->find(md->name()))) // check if there is a member with the same name
3950  {
3951  //printf(" Member name found\n");
3952  // for each member with the same name
3953  for (const auto &irmd : *rmn)
3954  {
3955  MemberDefMutable *rmd = toMemberDefMutable(irmd.get());
3956  //printf(" Member found: related='%d'\n",rmd->isRelated());
3957  if (rmd &&
3958  (rmd->isRelated() || rmd->isForeign()) && // related function
3959  matchArguments2( md->getOuterScope(), md->getFileDef(), &md->argumentList(),
3960  rmd->getOuterScope(),rmd->getFileDef(),&rmd->argumentList(),
3961  TRUE
3962  )
3963  )
3964  {
3965  //printf(" Found related member '%s'\n",qPrint(md->name()));
3966  if (rmd->relatedAlso())
3967  md->setRelatedAlso(rmd->relatedAlso());
3968  else if (rmd->isForeign())
3969  md->makeForeign();
3970  else
3971  md->makeRelated();
3972  }
3973  }
3974  }
3975  }
3976  }
3977  }
3978 }
3979 
3980 //----------------------------------------------------------------------
3981 
3982 /*! make a dictionary of all template arguments of class cd
3983  * that are part of the base class name.
3984  * Example: A template class A with template arguments <R,S,T>
3985  * that inherits from B<T,T,S> will have T and S in the dictionary.
3986  */
3987 static TemplateNameMap getTemplateArgumentsInName(const ArgumentList &templateArguments,const std::string &name)
3988 {
3989  std::map<std::string,int> templateNames;
3990  int count=0;
3991  for (const Argument &arg : templateArguments)
3992  {
3993  static const reg::Ex re(R"(\a[\w:]*)");
3994  reg::Iterator it(name,re);
3996  for (; it!=end ; ++it)
3997  {
3998  const auto &match = *it;
3999  std::string n = match.str();
4000  if (n==arg.name.str())
4001  {
4002  if (templateNames.find(n)==templateNames.end())
4003  {
4004  templateNames.insert(std::make_pair(n,count));
4005  }
4006  }
4007  }
4008  }
4009  return templateNames;
4010 }
4011 
4012 /*! Searches a class from within \a context and \a cd and returns its
4013  * definition if found (otherwise 0 is returned).
4014  */
4016 {
4017  ClassDef *result=0;
4018  if (cd==0)
4019  {
4020  return result;
4021  }
4022  FileDef *fd=cd->getFileDef();
4023  SymbolResolver resolver(fd);
4024  if (context && cd!=context)
4025  {
4026  result = const_cast<ClassDef*>(resolver.resolveClass(context,name,true,true));
4027  }
4028  //printf("1. result=%p\n",result);
4029  if (result==0)
4030  {
4031  result = const_cast<ClassDef*>(resolver.resolveClass(cd,name,true,true));
4032  }
4033  //printf("2. result=%p\n",result);
4034  if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4035  {
4036  result = getClass(name);
4037  }
4038  //printf("3. result=%p\n",result);
4039  //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4040  // qPrint(name),
4041  // context ? qPrint(context->name()) : "<none>",
4042  // cd ? qPrint(cd->name()) : "<none>",
4043  // result ? qPrint(result->name()) : "<none>",
4044  // Doxygen::classLinkedMap->find(name)
4045  // );
4046  return result;
4047 }
4048 
4049 
4050 static void findUsedClassesForClass(const Entry *root,
4051  Definition *context,
4052  ClassDefMutable *masterCd,
4053  ClassDefMutable *instanceCd,
4054  bool isArtificial,
4055  const std::unique_ptr<ArgumentList> &actualArgs = std::unique_ptr<ArgumentList>(),
4056  const TemplateNameMap &templateNames = TemplateNameMap()
4057  )
4058 {
4059  const ArgumentList &formalArgs = masterCd->templateArguments();
4060  for (auto &mni : masterCd->memberNameInfoLinkedMap())
4061  {
4062  for (auto &mi : *mni)
4063  {
4064  const MemberDef *md=mi->memberDef();
4065  if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4066  {
4067  //printf(" Found variable %s in class %s\n",qPrint(md->name()),qPrint(masterCd->name()));
4068  QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4069  QCString typedefValue = resolveTypeDef(masterCd,type);
4070  if (!typedefValue.isEmpty())
4071  {
4072  type = typedefValue;
4073  }
4074  int pos=0;
4075  QCString usedClassName;
4076  QCString templSpec;
4077  bool found=FALSE;
4078  // the type can contain template variables, replace them if present
4079  type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4080 
4081  //printf(" template substitution gives=%s\n",qPrint(type));
4082  while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,root->lang)!=-1)
4083  {
4084  // find the type (if any) that matches usedClassName
4085  SymbolResolver resolver(masterCd->getFileDef());
4086  const ClassDefMutable *typeCd = resolver.resolveClassMutable(masterCd,usedClassName,false,true);
4087  //printf("====> usedClassName=%s -> typeCd=%s\n",
4088  // qPrint(usedClassName),typeCd?qPrint(typeCd->name()):"<none>");
4089  if (typeCd)
4090  {
4091  usedClassName = typeCd->name();
4092  }
4093 
4094  int sp=usedClassName.find('<');
4095  if (sp==-1) sp=0;
4096  int si=usedClassName.findRev("::",sp);
4097  if (si!=-1)
4098  {
4099  // replace any namespace aliases
4100  replaceNamespaceAliases(usedClassName,si);
4101  }
4102  // add any template arguments to the class
4103  QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4104  //printf(" usedName=%s\n",qPrint(usedName));
4105 
4106  TemplateNameMap formTemplateNames;
4107  if (templateNames.empty())
4108  {
4109  formTemplateNames = getTemplateArgumentsInName(formalArgs,usedName.str());
4110  }
4111  BaseInfo bi(usedName,Public,Normal);
4112  findClassRelation(root,context,instanceCd,&bi,formTemplateNames,TemplateInstances,isArtificial);
4113 
4114  for (const Argument &arg : masterCd->templateArguments())
4115  {
4116  if (arg.name==usedName) // type is a template argument
4117  {
4118  Debug::print(Debug::Classes,0," New used class '%s'\n", qPrint(usedName));
4119 
4120  ClassDef *usedCd = Doxygen::hiddenClassLinkedMap->find(usedName);
4121  ClassDefMutable *usedCdm = toClassDefMutable(usedCd);
4122  if (usedCd==0)
4123  {
4124  usedCdm = toClassDefMutable(
4125  Doxygen::hiddenClassLinkedMap->add(usedName,
4126  std::unique_ptr<ClassDef>(
4128  masterCd->getDefFileName(),masterCd->getDefLine(),
4129  masterCd->getDefColumn(),
4130  usedName,
4131  ClassDef::Class))));
4132  if (usedCdm)
4133  {
4134  //printf("making %s a template argument!!!\n",qPrint(usedCd->name()));
4135  usedCdm->makeTemplateArgument();
4136  usedCdm->setUsedOnly(TRUE);
4137  usedCdm->setLanguage(masterCd->getLanguage());
4138  usedCd = usedCdm;
4139  }
4140  }
4141  if (usedCd)
4142  {
4143  found=TRUE;
4144  Debug::print(Debug::Classes,0," Adding used class '%s' (1)\n", qPrint(usedCd->name()));
4145  instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4146  if (usedCdm)
4147  {
4148  if (isArtificial) usedCdm->setArtificial(TRUE);
4149  usedCdm->addUsedByClass(instanceCd,md->name(),md->protection());
4150  }
4151  }
4152  }
4153  }
4154 
4155  if (!found)
4156  {
4157  ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4158  //printf("Looking for used class %s: result=%s master=%s\n",
4159  // qPrint(usedName),usedCd?qPrint(usedCd->name()):"<none>",masterCd?qPrint(masterCd->name()):"<none>");
4160 
4161  if (usedCd)
4162  {
4163  found=TRUE;
4164  Debug::print(Debug::Classes,0," Adding used class '%s' (2)\n", qPrint(usedCd->name()));
4165  instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
4166  ClassDefMutable *usedCdm = toClassDefMutable(usedCd);
4167  if (usedCdm)
4168  {
4169  usedCdm->addUsedByClass(instanceCd,md->name(),md->protection());
4170  }
4171  }
4172  }
4173  }
4174  if (!found && !type.isEmpty()) // used class is not documented in any scope
4175  {
4176  ClassDef *usedCd = Doxygen::hiddenClassLinkedMap->find(type);
4177  ClassDefMutable *usedCdm = toClassDefMutable(usedCd);
4178  if (usedCd==0 && !Config_getBool(HIDE_UNDOC_RELATIONS))
4179  {
4180  if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4181  {
4182  type+=md->argsString();
4183  }
4184  Debug::print(Debug::Classes,0," New undocumented used class '%s'\n", qPrint(type));
4185  usedCdm = toClassDefMutable(
4187  std::unique_ptr<ClassDef>(
4189  masterCd->getDefFileName(),masterCd->getDefLine(),
4190  masterCd->getDefColumn(),
4191  type,ClassDef::Class))));
4192  if (usedCdm)
4193  {
4194  usedCdm->setUsedOnly(TRUE);
4195  usedCdm->setLanguage(masterCd->getLanguage());
4196  usedCd = usedCdm;
4197  }
4198  }
4199  if (usedCd)
4200  {
4201  Debug::print(Debug::Classes,0," Adding used class '%s' (3)\n", qPrint(usedCd->name()));
4202  instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4203  if (usedCdm)
4204  {
4205  if (isArtificial) usedCdm->setArtificial(TRUE);
4206  usedCdm->addUsedByClass(instanceCd,md->name(),md->protection());
4207  }
4208  }
4209  }
4210  }
4211  }
4212  }
4213 }
4214 
4216  const Entry *root,
4217  Definition *context,
4218  ClassDefMutable *masterCd,
4219  ClassDefMutable *instanceCd,
4221  bool isArtificial,
4222  const std::unique_ptr<ArgumentList> &actualArgs = std::unique_ptr<ArgumentList>(),
4223  const TemplateNameMap &templateNames=TemplateNameMap()
4224  )
4225 {
4226  // The base class could ofcouse also be a non-nested class
4227  const ArgumentList &formalArgs = masterCd->templateArguments();
4228  for (const BaseInfo &bi : root->extends)
4229  {
4230  //printf("masterCd=%s bi.name='%s' #actualArgs=%d\n",
4231  // qPrint(masterCd->localName()),qPrint(bi.name),actualArgs ? (int)actualArgs->size() : -1);
4232  TemplateNameMap formTemplateNames;
4233  if (templateNames.empty())
4234  {
4235  formTemplateNames = getTemplateArgumentsInName(formalArgs,bi.name.str());
4236  }
4237  BaseInfo tbi = bi;
4238  tbi.name = substituteTemplateArgumentsInString(bi.name,formalArgs,actualArgs);
4239  //printf("bi->name=%s tbi.name=%s\n",qPrint(bi->name),qPrint(tbi.name));
4240 
4241  if (mode==DocumentedOnly)
4242  {
4243  // find a documented base class in the correct scope
4244  if (!findClassRelation(root,context,instanceCd,&tbi,formTemplateNames,DocumentedOnly,isArtificial))
4245  {
4246  // 1.8.2: decided to show inheritance relations even if not documented,
4247  // we do make them artificial, so they do not appear in the index
4248  //if (!Config_getBool(HIDE_UNDOC_RELATIONS))
4249  bool b = Config_getBool(HIDE_UNDOC_RELATIONS) ? TRUE : isArtificial;
4250  //{
4251  // no documented base class -> try to find an undocumented one
4252  findClassRelation(root,context,instanceCd,&tbi,formTemplateNames,Undocumented,b);
4253  //}
4254  }
4255  }
4256  else if (mode==TemplateInstances)
4257  {
4258  findClassRelation(root,context,instanceCd,&tbi,formTemplateNames,TemplateInstances,isArtificial);
4259  }
4260  }
4261 }
4262 
4263 //----------------------------------------------------------------------
4264 
4265 static void findTemplateInstanceRelation(const Entry *root,
4266  Definition *context,
4267  ClassDefMutable *templateClass,const QCString &templSpec,
4268  const TemplateNameMap &templateNames,
4269  bool isArtificial)
4270 {
4271  Debug::print(Debug::Classes,0," derived from template %s with parameters %s isArtificial=%d\n",
4272  qPrint(templateClass->name()),qPrint(templSpec),isArtificial);
4273  //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4274  // qPrint(templateClass->name()),qPrint(templSpec));
4275  //for (const auto &kv : templNames)
4276  //{
4277  // printf("(%s->%d) ",kv.first.c_str(),kv.second);
4278  //}
4279  //printf("\n");
4280 
4281  bool existingClass = (templSpec ==
4282  tempArgListToString(templateClass->templateArguments(),root->lang,false)
4283  );
4284  if (existingClass) return;
4285 
4286  bool freshInstance=FALSE;
4287  ClassDefMutable *instanceClass = toClassDefMutable(
4288  templateClass->insertTemplateInstance(
4289  root->fileName,root->startLine,root->startColumn,templSpec,freshInstance));
4290  if (instanceClass)
4291  {
4292  instanceClass->setArtificial(TRUE);
4293  instanceClass->setLanguage(root->lang);
4294 
4295  if (freshInstance)
4296  {
4297  Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",qPrint(instanceClass->name()));
4298  instanceClass->setTemplateBaseClassNames(templateNames);
4299 
4300  // search for new template instances caused by base classes of
4301  // instanceClass
4302  auto it_pair = g_classEntries.equal_range(templateClass->name().str());
4303  for (auto it=it_pair.first ; it!=it_pair.second ; ++it)
4304  {
4305  const Entry *templateRoot = it->second;
4306  Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",
4307  qPrint(templateRoot->name),qPrint(templSpec));
4308  std::unique_ptr<ArgumentList> templArgs = stringToArgumentList(root->lang,templSpec);
4309  findBaseClassesForClass(templateRoot,context,templateClass,instanceClass,
4310  TemplateInstances,isArtificial,templArgs,templateNames);
4311 
4312  findUsedClassesForClass(templateRoot,context,templateClass,instanceClass,
4313  isArtificial,templArgs,templateNames);
4314  }
4315 
4316  //Debug::print(Debug::Classes,0," Template instance %s : \n",qPrint(instanceClass->name()));
4317  //ArgumentList *tl = templateClass->templateArguments();
4318  }
4319  else
4320  {
4321  Debug::print(Debug::Classes,0," instance already exists!\n");
4322  }
4323  }
4324 }
4325 
4326 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4327 {
4328  QCString n=name;
4329  int index=n.find('<');
4330  if (index!=-1)
4331  {
4332  n=n.left(index);
4333  }
4334  bool result = rightScopeMatch(scope,n);
4335  return result;
4336 }
4337 
4338 /*! Searches for the end of a template in prototype \a s starting from
4339  * character position \a startPos. If the end was found the position
4340  * of the closing > is returned, otherwise -1 is returned.
4341  *
4342  * Handles exotic cases such as
4343  * \code
4344  * Class<(id<0)>
4345  * Class<bits<<2>
4346  * Class<"<">
4347  * Class<'<'>
4348  * Class<(")<")>
4349  * \endcode
4350  */
4351 static int findEndOfTemplate(const QCString &s,int startPos)
4352 {
4353  // locate end of template
4354  int e=startPos;
4355  int brCount=1;
4356  int roundCount=0;
4357  int len = s.length();
4358  bool insideString=FALSE;
4359  bool insideChar=FALSE;
4360  char pc = 0;
4361  while (e<len && brCount!=0)
4362  {
4363  char c=s.at(e);
4364  switch(c)
4365  {
4366  case '<':
4367  if (!insideString && !insideChar)
4368  {
4369  if (e<len-1 && s.at(e+1)=='<')
4370  e++;
4371  else if (roundCount==0)
4372  brCount++;
4373  }
4374  break;
4375  case '>':
4376  if (!insideString && !insideChar)
4377  {
4378  if (e<len-1 && s.at(e+1)=='>')
4379  e++;
4380  else if (roundCount==0)
4381  brCount--;
4382  }
4383  break;
4384  case '(':
4385  if (!insideString && !insideChar)
4386  roundCount++;
4387  break;
4388  case ')':
4389  if (!insideString && !insideChar)
4390  roundCount--;
4391  break;
4392  case '"':
4393  if (!insideChar)
4394  {
4395  if (insideString && pc!='\\')
4396  insideString=FALSE;
4397  else
4398  insideString=TRUE;
4399  }
4400  break;
4401  case '\'':
4402  if (!insideString)
4403  {
4404  if (insideChar && pc!='\\')
4405  insideChar=FALSE;
4406  else
4407  insideChar=TRUE;
4408  }
4409  break;
4410  }
4411  pc = c;
4412  e++;
4413  }
4414  return brCount==0 ? e : -1;
4415 }
4416 
4418 {
4419  if (name.isEmpty()) return 0;
4420  int l = static_cast<int>(name.length());
4421  if (name[l-1]=='>') // search backward to find the matching <, allowing nested <...> and strings.
4422  {
4423  int count=1;
4424  int i=l-2;
4425  char insideQuote=0;
4426  while (count>0 && i>=0)
4427  {
4428  char c = name[i--];
4429  switch (c)
4430  {
4431  case '>': if (!insideQuote) count++; break;
4432  case '<': if (!insideQuote) count--; break;
4433  case '\'': if (!insideQuote) insideQuote=c;
4434  else if (insideQuote==c && (i<0 || name[i]!='\\')) insideQuote=0;
4435  break;
4436  case '"': if (!insideQuote) insideQuote=c;
4437  else if (insideQuote==c && (i<0 || name[i]!='\\')) insideQuote=0;
4438  break;
4439  default: break;
4440  }
4441  }
4442  if (i>=0) l=i+1;
4443  }
4444  return l;
4445 }
4446 
4447 static bool findClassRelation(
4448  const Entry *root,
4449  Definition *context,
4450  ClassDefMutable *cd,
4451  const BaseInfo *bi,
4452  const TemplateNameMap &templateNames,
4454  bool isArtificial
4455  )
4456 {
4457  //printf("findClassRelation(class=%s base=%s templateNames=",
4458  // qPrint(cd->name()),qPrint(bi->name));
4459  //for (const auto &kv : templateNames)
4460  //{
4461  // printf("(%s->%d) ",kv.first.c_str(),kv.second);
4462  //}
4463  //printf("\n");
4464 
4465  QCString biName=bi->name;
4466  bool explicitGlobalScope=FALSE;
4467  //printf("findClassRelation: biName='%s'\n",qPrint(biName));
4468  if (biName.left(2)=="::") // explicit global scope
4469  {
4470  biName=biName.right(biName.length()-2);
4471  explicitGlobalScope=TRUE;
4472  }
4473 
4474  Entry *parentNode=root->parent();
4475  bool lastParent=FALSE;
4476  do // for each parent scope, starting with the largest scope
4477  // (in case of nested classes)
4478  {
4479  QCString scopeName= parentNode ? parentNode->name : QCString();
4480  int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4481  do // try all parent scope prefixes, starting with the largest scope
4482  {
4483  //printf("scopePrefix='%s' biName='%s'\n",
4484  // qPrint(scopeName.left(scopeOffset)),qPrint(biName));
4485 
4486  QCString baseClassName=biName;
4487  if (scopeOffset>0)
4488  {
4489  baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4490  }
4491  //QCString stripped;
4492  //baseClassName=stripTemplateSpecifiersFromScope
4493  // (removeRedundantWhiteSpace(baseClassName),TRUE,
4494  // &stripped);
4495  SymbolResolver resolver(cd->getFileDef());
4496  ClassDefMutable *baseClass = resolver.resolveClassMutable(explicitGlobalScope ? Doxygen::globalScope : context,
4497  baseClassName,
4498  mode==Undocumented,
4499  true
4500  );
4501  const MemberDef *baseClassTypeDef = resolver.getTypedef();
4502  QCString templSpec = resolver.getTemplateSpec();
4503  //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4504  // qPrint(baseClassName),baseClass,cd,explicitGlobalScope);
4505  //printf(" scope='%s' baseClassName='%s' baseClass=%s templSpec=%s\n",
4506  // cd ? qPrint(cd->name()):"<none>",
4507  // qPrint(baseClassName),
4508  // baseClass?qPrint(baseClass->name()):"<none>",
4509  // qPrint(templSpec)
4510  // );
4511  //if (baseClassName.left(root->name.length())!=root->name ||
4512  // baseClassName.at(root->name.length())!='<'
4513  // ) // Check for base class with the same name.
4514  // // If found then look in the outer scope for a match
4515  // // and prevent recursion.
4516  if (!isRecursiveBaseClass(root->name,baseClassName)
4517  || explicitGlobalScope
4518  // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4519  // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4520  || (root->lang==SrcLangExt_IDL &&
4523  {
4524  Debug::print(
4525  Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4526  qPrint(baseClassName),
4527  qPrint(root->name),
4528  (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4529  (bi->virt==Normal)?"normal":"virtual",
4530  qPrint(templSpec)
4531  );
4532 
4533  int i=findTemplateSpecializationPosition(baseClassName);
4534  int si=baseClassName.findRev("::",i);
4535  if (si==-1) si=0;
4536  if (baseClass==0 && static_cast<uint>(i)!=baseClassName.length())
4537  // base class has template specifiers
4538  {
4539  // TODO: here we should try to find the correct template specialization
4540  // but for now, we only look for the unspecialized base class.
4541  int e=findEndOfTemplate(baseClassName,i+1);
4542  //printf("baseClass==0 i=%d e=%d\n",i,e);
4543  if (e!=-1) // end of template was found at e
4544  {
4545  templSpec = removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4546  baseClassName = baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4547  baseClass = resolver.resolveClassMutable(explicitGlobalScope ? Doxygen::globalScope : context,
4548  baseClassName,
4549  mode==Undocumented,
4550  true
4551  );
4552  baseClassTypeDef = resolver.getTypedef();
4553  //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4554  // baseClass,qPrint(baseClassName),qPrint(templSpec));
4555  }
4556  }
4557  else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4558  // know it is a template, so see if
4559  // we can also link to the explicit
4560  // instance (for instance if a class
4561  // derived from a template argument)
4562  {
4563  //printf("baseClass=%s templSpec=%s\n",qPrint(baseClass->name()),qPrint(templSpec));
4564  ClassDefMutable *templClass=getClassMutable(baseClass->name()+templSpec);
4565  if (templClass)
4566  {
4567  // use the template instance instead of the template base.
4568  baseClass = templClass;
4569  templSpec.resize(0);
4570  }
4571  }
4572 
4573  //printf("cd=%p baseClass=%p\n",cd,baseClass);
4574  bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4575  //printf("1. found=%d\n",found);
4576  if (!found && si!=-1)
4577  {
4578  // replace any namespace aliases
4579  replaceNamespaceAliases(baseClassName,si);
4580  baseClass = resolver.resolveClassMutable(explicitGlobalScope ? Doxygen::globalScope : context,
4581  baseClassName,
4582  mode==Undocumented,
4583  true
4584  );
4585  baseClassTypeDef = resolver.getTypedef();
4586  QCString tmpTemplSpec = resolver.getTemplateSpec();
4587  found=baseClass!=0 && baseClass!=cd;
4588  if (found) templSpec = tmpTemplSpec;
4589  }
4590  //printf("2. found=%d\n",found);
4591 
4592  if (!found)
4593  {
4594  baseClass=toClassDefMutable(findClassWithinClassContext(context,cd,baseClassName));
4595  //printf("findClassWithinClassContext(%s,%s)=%p\n",
4596  // qPrint(cd->name()),qPrint(baseClassName),baseClass);
4597  found = baseClass!=0 && baseClass!=cd;
4598 
4599  }
4600  //printf("3. found=%d\n",found);
4601  if (!found)
4602  {
4603  // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4604  // the class name also in the alias mapping.
4605  auto it = Doxygen::namespaceAliasMap.find(baseClassName.str());
4606  if (it!=Doxygen::namespaceAliasMap.end()) // see if it is indeed a class.
4607  {
4608  baseClass=getClassMutable(it->second.c_str());
4609  found = baseClass!=0 && baseClass!=cd;
4610  }
4611  }
4612  bool isATemplateArgument = templateNames.find(biName.str())!=templateNames.end();
4613  // make templSpec canonical
4614  // warning: the following line doesn't work for Mixin classes (see bug 560623)
4615  // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4616 
4617  //printf("4. found=%d\n",found);
4618  if (found)
4619  {
4620  Debug::print(Debug::Classes,0," Documented base class '%s' templSpec=%s\n",qPrint(biName),qPrint(templSpec));
4621  // add base class to this class
4622 
4623  // if templSpec is not empty then we should "instantiate"
4624  // the template baseClass. A new ClassDef should be created
4625  // to represent the instance. To be able to add the (instantiated)
4626  // members and documentation of a template class
4627  // (inserted in that template class at a later stage),
4628  // the template should know about its instances.
4629  // the instantiation process, should be done in a recursive way,
4630  // since instantiating a template may introduce new inheritance
4631  // relations.
4632  if (!templSpec.isEmpty() && mode==TemplateInstances)
4633  {
4634  // if baseClass is actually a typedef then we should not
4635  // instantiate it, since typedefs are in a different namespace
4636  // see bug531637 for an example where this would otherwise hang
4637  // doxygen
4638  if (baseClassTypeDef==0)
4639  {
4640  //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4641  findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,baseClass->isArtificial());
4642  }
4643  }
4644  else if (mode==DocumentedOnly || mode==Undocumented)
4645  {
4646  //printf(" => insert base class\n");
4647  QCString usedName;
4648  if (baseClassTypeDef || cd->isCSharp())
4649  {
4650  usedName=biName;
4651  //printf("***** usedName=%s templSpec=%s\n",qPrint(usedName),qPrint(templSpec));
4652  }
4653  Protection prot = bi->prot;
4654  if (Config_getBool(SIP_SUPPORT)) prot=Public;
4655  if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4656  {
4657  cd->insertBaseClass(baseClass,usedName,prot,bi->virt,templSpec);
4658  // add this class as super class to the base class
4659  baseClass->insertSubClass(cd,prot,bi->virt,templSpec);
4660  }
4661  else
4662  {
4663  warn(root->fileName,root->startLine,
4664  "Detected potential recursive class relation "
4665  "between class %s and base class %s!",
4666  qPrint(cd->name()),qPrint(baseClass->name())
4667  );
4668  }
4669  }
4670  return TRUE;
4671  }
4672  else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4673  {
4675  " New undocumented base class '%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4676  qPrint(biName),qPrint(baseClassName),qPrint(templSpec),isArtificial
4677  );
4678  baseClass=0;
4679  if (isATemplateArgument)
4680  {
4681  baseClass = toClassDefMutable(Doxygen::hiddenClassLinkedMap->find(baseClassName));
4682  if (baseClass==0) // not found (or alias)
4683  {
4684  baseClass= toClassDefMutable(
4685  Doxygen::hiddenClassLinkedMap->add(baseClassName,
4686  std::unique_ptr<ClassDef>(
4687  createClassDef(root->fileName,root->startLine,root->startColumn,
4688  baseClassName,
4689  ClassDef::Class))));
4690  if (baseClass) // really added (not alias)
4691  {
4692  if (isArtificial) baseClass->setArtificial(TRUE);
4693  baseClass->setLanguage(root->lang);
4694  }
4695  }
4696  }
4697  else
4698  {
4699  baseClass = toClassDefMutable(Doxygen::classLinkedMap->find(baseClassName));
4700  //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4701  // qPrint(baseClassName),baseClass,qPrint(biName),qPrint(templSpec));
4702  if (baseClass==0) // not found (or alias)
4703  {
4704  baseClass = toClassDefMutable(
4705  Doxygen::classLinkedMap->add(baseClassName,
4706  std::unique_ptr<ClassDef>(
4707  createClassDef(root->fileName,root->startLine,root->startColumn,
4708  baseClassName,
4709  ClassDef::Class))));
4710  if (baseClass) // really added (not alias)
4711  {
4712  if (isArtificial) baseClass->setArtificial(TRUE);
4713  baseClass->setLanguage(root->lang);
4714  si = baseClassName.findRev("::");
4715  if (si!=-1) // class is nested
4716  {
4717  Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,root->tagInfo());
4718  if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4719  {
4720  baseClass->setArtificial(TRUE); // see bug678139
4721  }
4722  }
4723  }
4724  }
4725  }
4726  if (baseClass)
4727  {
4728  if (biName.right(2)=="-p")
4729  {
4730  biName="<"+biName.left(biName.length()-2)+">";
4731  }
4732  // add base class to this class
4733  cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4734  // add this class as super class to the base class
4735  baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4736  // the undocumented base was found in this file
4737  baseClass->insertUsedFile(root->fileDef());
4738 
4739  Definition *scope = buildScopeFromQualifiedName(baseClass->name(),root->lang,0);
4740  if (scope!=baseClass)
4741  {
4742  baseClass->setOuterScope(scope);
4743  }
4744 
4745  if (baseClassName.right(2)=="-p")
4746  {
4747  baseClass->setCompoundType(ClassDef::Protocol);
4748  }
4749  return TRUE;
4750  }
4751  else
4752  {
4753  Debug::print(Debug::Classes,0," Base class '%s' not created (alias?)\n",qPrint(biName));
4754  }
4755  }
4756  else
4757  {
4758  Debug::print(Debug::Classes,0," Base class '%s' not found\n",qPrint(biName));
4759  }
4760  }
4761  else
4762  {
4763  if (mode!=TemplateInstances)
4764  {
4765  warn(root->fileName,root->startLine,
4766  "Detected potential recursive class relation "
4767  "between class %s and base class %s!\n",
4768  qPrint(root->name),qPrint(baseClassName)
4769  );
4770  }
4771  // for mode==TemplateInstance this case is quite common and
4772  // indicates a relation between a template class and a template
4773  // instance with the same name.
4774  }
4775  if (scopeOffset==0)
4776  {
4777  scopeOffset=-1;
4778  }
4779  else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4780  {
4781  scopeOffset=0;
4782  }
4783  //printf("new scopeOffset='%d'",scopeOffset);
4784  } while (scopeOffset>=0);
4785 
4786  if (parentNode==0)
4787  {
4788  lastParent=TRUE;
4789  }
4790  else
4791  {
4792  parentNode=parentNode->parent();
4793  }
4794  } while (lastParent);
4795 
4796  return FALSE;
4797 }
4798 
4799 //----------------------------------------------------------------------
4800 // Computes the base and super classes for each class in the tree
4801 
4802 static bool isClassSection(const Entry *root)
4803 {
4804  if ( !root->name.isEmpty() )
4805  {
4806  if (root->section & Entry::COMPOUND_MASK)
4807  // is it a compound (class, struct, union, interface ...)
4808  {
4809  return TRUE;
4810  }
4811  else if (root->section & Entry::COMPOUNDDOC_MASK)
4812  // is it a documentation block with inheritance info.
4813  {
4814  bool hasExtends = !root->extends.empty();
4815  if (hasExtends) return TRUE;
4816  }
4817  }
4818  return FALSE;
4819 }
4820 
4821 
4822 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
4823  */
4824 static void findClassEntries(const Entry *root)
4825 {
4826  if (isClassSection(root))
4827  {
4828  g_classEntries.insert({root->name.str(),root});
4829  }
4830  for (const auto &e : root->children()) findClassEntries(e.get());
4831 }
4832 
4833 static QCString extractClassName(const Entry *root)
4834 {
4835  // strip any anonymous scopes first
4837  bName=stripTemplateSpecifiersFromScope(bName);
4838  int i;
4839  if ((root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java) &&
4840  (i=bName.find('<'))!=-1)
4841  {
4842  // a Java/C# generic class looks like a C++ specialization, so we need to strip the
4843  // template part before looking for matches
4844  bName=bName.left(i);
4845  }
4846  return bName;
4847 }
4848 
4849 /*! Using the dictionary build by findClassEntries(), this
4850  * function will look for additional template specialization that
4851  * exists as inheritance relations only. These instances will be
4852  * added to the template they are derived from.
4853  */
4855 {
4856  ClassDefSet visitedClasses;
4857  for (const auto &kv : g_classEntries)
4858  {
4859  const Entry *root = kv.second;
4860  ClassDef *cd;
4861  QCString bName = extractClassName(root);
4862  Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",qPrint(bName));
4863  if ((cd=getClass(bName)))
4864  {
4866  if (cdm)
4867  {
4868  //printf("Class %s %zu\n",qPrint(cd->name()),root->extends.size());
4870  }
4871  }
4872  }
4873 }
4874 
4876 {
4877  for (const auto &kv : g_classEntries)
4878  {
4879  const Entry *root = kv.second;
4880  ClassDef *cd;
4881  QCString bName = extractClassName(root);
4882  Debug::print(Debug::Classes,0," Usage: Class %s : \n",qPrint(bName));
4883  if ((cd=getClass(bName)))
4884  {
4886  if (cdm)
4887  {
4888  findUsedClassesForClass(root,cd,cdm,cdm,TRUE);
4889  cdm->addTypeConstraints();
4890  }
4891  }
4892  }
4893 }
4894 
4896 {
4897  for (const auto &kv : g_classEntries)
4898  {
4899  const Entry *root = kv.second;
4900  ClassDefMutable *cd;
4901 
4902  QCString bName = extractClassName(root);
4903  Debug::print(Debug::Classes,0," Relations: Class %s : \n",qPrint(bName));
4904  if ((cd=getClassMutable(bName)))
4905  {
4907  }
4908  size_t numMembers = cd ? cd->memberNameInfoLinkedMap().size() : 0;
4909  if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
4910  bName.right(2)!="::")
4911  {
4912  if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
4914  Config_getBool(EXTRACT_LOCAL_CLASSES)) && // not defined in source file
4915  protectionLevelVisible(root->protection) && // hidden by protection
4916  !Config_getBool(HIDE_UNDOC_CLASSES) // undocumented class are visible
4917  )
4918  warn_undoc(
4919  root->fileName,root->startLine,
4920  "Compound %s is not documented.",
4921  qPrint(root->name)
4922  );
4923  }
4924  }
4925 }
4926 
4928 {
4929  for (const auto &kv : g_classEntries)
4930  {
4931  const Entry *root = kv.second;
4933  bName=stripTemplateSpecifiersFromScope(bName);
4934  ClassDefMutable *cd=getClassMutable(bName);
4935  // strip any anonymous scopes first
4936  if (cd && !cd->getTemplateInstances().empty())
4937  {
4938  Debug::print(Debug::Classes,0," Template class %s : \n",qPrint(cd->name()));
4939  for (const auto &ti : cd->getTemplateInstances()) // for each template instance
4940  {
4941  ClassDefMutable *tcd=toClassDefMutable(ti.classDef);
4942  if (tcd)
4943  {
4944  Debug::print(Debug::Classes,0," Template instance %s : \n",qPrint(tcd->name()));
4945  QCString templSpec = ti.templSpec;
4946  std::unique_ptr<ArgumentList> templArgs = stringToArgumentList(tcd->getLanguage(),templSpec);
4947  for (const BaseInfo &bi : root->extends)
4948  {
4949  // check if the base class is a template argument
4950  BaseInfo tbi = bi;
4951  const ArgumentList &tl = cd->templateArguments();
4952  if (!tl.empty())
4953  {
4954  TemplateNameMap baseClassNames = tcd->getTemplateBaseClassNames();
4955  TemplateNameMap templateNames = getTemplateArgumentsInName(tl,bi.name.str());
4956  // for each template name that we inherit from we need to
4957  // substitute the formal with the actual arguments
4958  TemplateNameMap actualTemplateNames;
4959  for (const auto &tn_kv : templateNames)
4960  {
4961  int templIndex = tn_kv.second;
4962  Argument actArg;
4963  bool hasActArg=FALSE;
4964  if (templIndex<(int)templArgs->size())
4965  {
4966  actArg=templArgs->at(templIndex);
4967  hasActArg=TRUE;
4968  }
4969  if (hasActArg &&
4970  baseClassNames.find(actArg.type.str())!=baseClassNames.end() &&
4971  actualTemplateNames.find(actArg.type.str())==actualTemplateNames.end()
4972  )
4973  {
4974  actualTemplateNames.insert(std::make_pair(actArg.type.str(),templIndex));
4975  }
4976  }
4977 
4978  tbi.name = substituteTemplateArgumentsInString(bi.name,tl,templArgs);
4979  // find a documented base class in the correct scope
4980  if (!findClassRelation(root,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
4981  {
4982  // no documented base class -> try to find an undocumented one
4983  findClassRelation(root,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
4984  }
4985  }
4986  }
4987  }
4988  }
4989  }
4990  }
4991 }
4992 
4993 //-----------------------------------------------------------------------
4994 // compute the references (anchors in HTML) for each function in the file
4995 
4997 {
4998  for (const auto &cd : *Doxygen::classLinkedMap)
4999  {
5000  ClassDefMutable *cdm = toClassDefMutable(cd.get());
5001  if (cdm)
5002  {
5003  cdm->computeAnchors();
5004  }
5005  }
5006  for (const auto &fn : *Doxygen::inputNameLinkedMap)
5007  {
5008  for (const auto &fd : *fn)
5009  {
5010  fd->computeAnchors();
5011  }
5012  }
5013  for (const auto &nd : *Doxygen::namespaceLinkedMap)
5014  {
5015  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
5016  if (ndm)
5017  {
5018  ndm->computeAnchors();
5019  }
5020  }
5021  for (const auto &gd : *Doxygen::groupLinkedMap)
5022  {
5023  gd->computeAnchors();
5024  }
5025 }
5026 
5027 //----------------------------------------------------------------------
5028 
5029 static void addListReferences()
5030 {
5031  for (const auto &cd : *Doxygen::classLinkedMap)
5032  {
5033  ClassDefMutable *cdm = toClassDefMutable(cd.get());
5034  if (cdm)
5035  {
5036  cdm->addListReferences();
5037  }
5038  }
5039 
5040  for (const auto &fn : *Doxygen::inputNameLinkedMap)
5041  {
5042  for (const auto &fd : *fn)
5043  {
5044  fd->addListReferences();
5045  }
5046  }
5047 
5048  for (const auto &nd : *Doxygen::namespaceLinkedMap)
5049  {
5050  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
5051  if (ndm)
5052  {
5053  ndm->addListReferences();
5054  }
5055  }
5056 
5057  for (const auto &gd : *Doxygen::groupLinkedMap)
5058  {
5059  gd->addListReferences();
5060  }
5061 
5062  for (const auto &pd : *Doxygen::pageLinkedMap)
5063  {
5064  QCString name = pd->getOutputFileBase();
5065  if (pd->getGroupDef())
5066  {
5067  name = pd->getGroupDef()->getOutputFileBase();
5068  }
5069  {
5070  const RefItemVector &xrefItems = pd->xrefListItems();
5071  addRefItem(xrefItems,
5072  name,
5074  name,pd->title(),QCString(),0);
5075  }
5076  }
5077 
5078  for (const auto &dd : *Doxygen::dirLinkedMap)
5079  {
5080  QCString name = dd->getOutputFileBase();
5081  //if (dd->getGroupDef())
5082  //{
5083  // name = dd->getGroupDef()->getOutputFileBase();
5084  //}
5085  const RefItemVector &xrefItems = dd->xrefListItems();
5086  addRefItem(xrefItems,
5087  name,
5089  name,dd->displayName(),QCString(),0);
5090  }
5091 }
5092 
5093 //----------------------------------------------------------------------
5094 
5095 static void generateXRefPages()
5096 {
5098  {
5099  rl->generatePage();
5100  }
5101 }
5102 
5103 //----------------------------------------------------------------------
5104 // Copy the documentation in entry 'root' to member definition 'md' and
5105 // set the function declaration of the member to 'funcDecl'. If the boolean
5106 // over_load is set the standard overload text is added.
5107 
5108 static void addMemberDocs(const Entry *root,
5109  MemberDefMutable *md, const QCString &funcDecl,
5110  const ArgumentList *al,
5111  bool over_load,
5112  uint64 spec
5113  )
5114 {
5115  if (md==0) return;
5116  //printf("addMemberDocs: '%s'::'%s' '%s' funcDecl='%s' mSpec=%lld\n",
5117  // qPrint(root->parent()->name),qPrint(md->name()),md->argsString(),funcDecl,spec);
5118  QCString fDecl=funcDecl;
5119  // strip extern specifier
5120  fDecl.stripPrefix("extern ");
5121  md->setDefinition(fDecl);
5122  md->enableCallGraph(root->callGraph);
5123  md->enableCallerGraph(root->callerGraph);
5127  const NamespaceDef *nd=md->getNamespaceDef();
5128  QCString fullName;
5129  if (cd)
5130  fullName = cd->name();
5131  else if (nd)
5132  fullName = nd->name();
5133 
5134  if (!fullName.isEmpty()) fullName+="::";
5135  fullName+=md->name();
5136  FileDef *rfd=root->fileDef();
5137 
5138  // TODO determine scope based on root not md
5139  Definition *rscope = md->getOuterScope();
5140 
5141  const ArgumentList &mdAl = md->argumentList();
5142  if (al)
5143  {
5144  ArgumentList mergedAl = *al;
5145  //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5146  mergeArguments(const_cast<ArgumentList&>(mdAl),mergedAl,!root->doc.isEmpty());
5147  }
5148  else
5149  {
5150  if (
5151  matchArguments2( md->getOuterScope(), md->getFileDef(),const_cast<ArgumentList*>(&mdAl),
5152  rscope,rfd,&root->argList,
5153  TRUE
5154  )
5155  )
5156  {
5157  //printf("merging arguments (2)\n");
5158  ArgumentList mergedArgList = root->argList;
5159  mergeArguments(const_cast<ArgumentList&>(mdAl),mergedArgList,!root->doc.isEmpty());
5160  }
5161  }
5162  if (over_load) // the \overload keyword was used
5163  {
5164  QCString doc=getOverloadDocs();
5165  if (!root->doc.isEmpty())
5166  {
5167  doc+="<p>";
5168  doc+=root->doc;
5169  }
5170  md->setDocumentation(doc,root->docFile,root->docLine);
5171  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5172  md->setDocsForDefinition(!root->proto);
5173  }
5174  else
5175  {
5176  //printf("overwrite!\n");
5177  md->setDocumentation(root->doc,root->docFile,root->docLine);
5178  md->setDocsForDefinition(!root->proto);
5179 
5180  //printf("overwrite!\n");
5181  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5182 
5183  if (
5184  (md->inbodyDocumentation().isEmpty() ||
5185  !root->parent()->name.isEmpty()
5186  ) && !root->inbodyDocs.isEmpty()
5187  )
5188  {
5189  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5190  }
5191  }
5192 
5193  //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5194  // qPrint(md->initializer()),md->initializer().isEmpty(),
5195  // qPrint(root->initializer),root->initializer.isEmpty()
5196  // );
5197  std::string rootInit = root->initializer.str();
5198  if (md->initializer().isEmpty() && !rootInit.empty())
5199  {
5200  //printf("setInitializer\n");
5201  md->setInitializer(rootInit.c_str());
5202  }
5203  if (md->requiresClause().isEmpty() && !root->req.isEmpty())
5204  {
5205  md->setRequiresClause(root->req);
5206  }
5207 
5208  md->setMaxInitLines(root->initLines);
5209 
5210  if (rfd)
5211  {
5212  if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5213  )
5214  {
5215  //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5216  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
5217  md->setBodyDef(rfd);
5218  }
5219 
5220  md->setRefItems(root->sli);
5221  }
5222 
5223  md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5224  md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5227 
5228  md->mergeMemberSpecifiers(spec);
5229  md->addSectionsToDefinition(root->anchors);
5230  addMemberToGroups(root,md);
5231  if (cd) cd->insertUsedFile(rfd);
5232  //printf("root->mGrpId=%d\n",root->mGrpId);
5233  if (root->mGrpId!=-1)
5234  {
5235  if (md->getMemberGroupId()!=-1)
5236  {
5237  if (md->getMemberGroupId()!=root->mGrpId)
5238  {
5239  warn(
5240  root->fileName,root->startLine,
5241  "member %s belongs to two different groups. The second "
5242  "one found here will be ignored.",
5243  qPrint(md->name())
5244  );
5245  }
5246  }
5247  else // set group id
5248  {
5249  //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,qPrint(md->name()));
5250  md->setMemberGroupId(root->mGrpId);
5251  }
5252  }
5253 }
5254 
5255 //----------------------------------------------------------------------
5256 // find a class definition given the scope name and (optionally) a
5257 // template list specifier
5258 
5260  const QCString &scopeName)
5261 {
5262  SymbolResolver resolver(fd);
5263  const ClassDef *tcd = resolver.resolveClass(nd,scopeName,true,true);
5264  return tcd;
5265 }
5266 
5267 
5268 //----------------------------------------------------------------------
5269 // Adds the documentation contained in 'root' to a global function
5270 // with name 'name' and argument list 'args' (for overloading) and
5271 // function declaration 'decl' to the corresponding member definition.
5272 
5273 static bool findGlobalMember(const Entry *root,
5274  const QCString &namespaceName,
5275  const QCString &type,
5276  const QCString &name,
5277  const QCString &tempArg,
5278  const QCString &,
5279  const QCString &decl,
5280  uint64 spec)
5281 {
5283  "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5284  qPrint(namespaceName),qPrint(type),qPrint(name),qPrint(tempArg),qPrint(decl));
5285  QCString n=name;
5286  if (n.isEmpty()) return FALSE;
5287  if (n.find("::")!=-1) return FALSE; // skip undefined class members
5288  MemberName *mn=Doxygen::functionNameLinkedMap->find(n+tempArg); // look in function dictionary
5289  if (mn==0)
5290  {
5291  mn=Doxygen::functionNameLinkedMap->find(n); // try without template arguments
5292  }
5293  if (mn) // function name defined
5294  {
5295  Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5296  //int count=0;
5297  bool found=FALSE;
5298  for (const auto &md : *mn)
5299  {
5300  const NamespaceDef *nd=0;
5301  if (md->isAlias() && md->getOuterScope() &&
5303  {
5304  nd = toNamespaceDef(md->getOuterScope());
5305  }
5306  else
5307  {
5308  nd = md->getNamespaceDef();
5309  }
5310 
5311  // special case for strong enums
5312  int enumNamePos=0;
5313  if (nd && md->isEnumValue() && (enumNamePos=namespaceName.findRev("::"))!=-1)
5314  { // md part of a strong enum in a namespace?
5315  QCString enumName = namespaceName.mid(enumNamePos+2);
5316  if (namespaceName.left(enumNamePos)==nd->name())
5317  {
5318  MemberName *enumMn=Doxygen::functionNameLinkedMap->find(enumName);
5319  if (enumMn)
5320  {
5321  for (const auto &emd : *enumMn)
5322  {
5323  found = emd->isStrong() && md->getEnumScope()==emd.get();
5324  if (found)
5325  {
5326  addMemberDocs(root,toMemberDefMutable(md->resolveAlias()),decl,0,FALSE,root->spec);
5327  break;
5328  }
5329  }
5330  }
5331  }
5332  if (found)
5333  {
5334  break;
5335  }
5336  }
5337  else if (nd==0 && md->isEnumValue()) // md part of global strong enum?
5338  {
5339  MemberName *enumMn=Doxygen::functionNameLinkedMap->find(namespaceName);
5340  if (enumMn)
5341  {
5342  for (const auto &emd : *enumMn)
5343  {
5344  found = emd->isStrong() && md->getEnumScope()==emd.get();
5345  if (found)
5346  {
5347  addMemberDocs(root,toMemberDefMutable(md->resolveAlias()),decl,0,FALSE,root->spec);
5348  break;
5349  }
5350  }
5351  }
5352  }
5353 
5354  const FileDef *fd=root->fileDef();
5355  //printf("File %s\n",fd ? qPrint(fd->name()) : "<none>");
5357  if (fd)
5358  {
5359  nl = fd->getUsedNamespaces();
5360  }
5361  //printf("NamespaceList %p\n",nl);
5362 
5363  // search in the list of namespaces that are imported via a
5364  // using declaration
5365  bool viaUsingDirective = nd && nl.find(nd->qualifiedName())!=0;
5366 
5367  if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
5368  (nd && nd->name()==namespaceName) || // or in the same namespace
5369  viaUsingDirective // member in 'using' namespace
5370  )
5371  {
5372  Debug::print(Debug::FindMembers,0,"4. Try to add member '%s' to scope '%s'\n",
5373  qPrint(md->name()),qPrint(namespaceName));
5374 
5375  NamespaceDef *rnd = 0;
5376  if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceLinkedMap->find(namespaceName);
5377 
5378  const ArgumentList &mdAl = const_cast<const MemberDef *>(md.get())->argumentList();
5379  bool matching=
5380  (mdAl.empty() && root->argList.empty()) ||
5381  md->isVariable() || md->isTypedef() || /* in case of function pointers */
5382  matchArguments2(md->getOuterScope(),const_cast<const MemberDef *>(md.get())->getFileDef(),&mdAl,
5383  rnd ? rnd : Doxygen::globalScope,fd,&root->argList,
5384  FALSE);
5385 
5386  // for template members we need to check if the number of
5387  // template arguments is the same, otherwise we are dealing with
5388  // different functions.
5389  if (matching && !root->tArgLists.empty())
5390  {
5391  const ArgumentList &mdTempl = md->templateArguments();
5392  if (root->tArgLists.back().size()!=mdTempl.size())
5393  {
5394  matching=FALSE;
5395  }
5396  }
5397 
5398  //printf("%s<->%s\n",
5399  // qPrint(argListToString(md->argumentList())),
5400  // qPrint(argListToString(root->argList)));
5401 
5402  // for static members we also check if the comment block was found in
5403  // the same file. This is needed because static members with the same
5404  // name can be in different files. Thus it would be wrong to just
5405  // put the comment block at the first syntactically matching member.
5406  if (matching && md->isStatic() &&
5407  md->getDefFileName()!=root->fileName &&
5408  mn->size()>1)
5409  {
5410  matching = FALSE;
5411  }
5412 
5413  // for template member we also need to check the return type and requires
5414  if (!md->templateArguments().empty() && !root->tArgLists.empty())
5415  {
5416  //printf("Comparing return types '%s'<->'%s'\n",
5417  // md->typeString(),type);
5418  if (md->templateArguments().size()!=root->tArgLists.back().size() ||
5419  md->typeString()!=type ||
5420  md->requiresClause()!=root->req)
5421  {
5422  //printf(" ---> no matching\n");
5423  matching = FALSE;
5424  }
5425  }
5426 
5427  if (matching) // add docs to the member
5428  {
5429  Debug::print(Debug::FindMembers,0,"5. Match found\n");
5430  addMemberDocs(root,toMemberDefMutable(md->resolveAlias()),decl,&root->argList,FALSE,root->spec);
5431  found=TRUE;
5432  break;
5433  }
5434  }
5435  }
5436  if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5437  {
5438  QCString fullFuncDecl=decl;
5439  if (!root->argList.empty()) fullFuncDecl+=argListToString(root->argList,TRUE);
5440  QCString warnMsg =
5441  QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5442  if (mn->size()>0)
5443  {
5444  warnMsg+="\nPossible candidates:\n";
5445  for (const auto &md : *mn)
5446  {
5447  warnMsg+=" '";
5448  warnMsg+=substitute(md->declaration(),"%","%%");
5449  warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5450  " of file "+md->getDefFileName()+"\n";
5451  }
5452  }
5453  warn(root->fileName,root->startLine, "%s", qPrint(warnMsg));
5454  }
5455  }
5456  else // got docs for an undefined member!
5457  {
5458  if (root->type!="friend class" &&
5459  root->type!="friend struct" &&
5460  root->type!="friend union" &&
5461  root->type!="friend" &&
5462  (!Config_getBool(TYPEDEF_HIDES_STRUCT) ||
5463  root->type.find("typedef ")==-1)
5464  )
5465  {
5466  warn(root->fileName,root->startLine,
5467  "documented symbol '%s' was not declared or defined.",qPrint(decl)
5468  );
5469  }
5470  }
5471  return TRUE;
5472 }
5473 
5474 static bool isSpecialization(
5475  const ArgumentLists &srcTempArgLists,
5476  const ArgumentLists &dstTempArgLists
5477  )
5478 {
5479  auto srcIt = srcTempArgLists.begin();
5480  auto dstIt = dstTempArgLists.begin();
5481  while (srcIt!=srcTempArgLists.end() && dstIt!=dstTempArgLists.end())
5482  {
5483  if ((*srcIt).size()!=(*dstIt).size()) return TRUE;
5484  ++srcIt;
5485  ++dstIt;
5486  }
5487  return FALSE;
5488 }
5489 
5490 static bool scopeIsTemplate(const Definition *d)
5491 {
5492  bool result=FALSE;
5493  if (d && d->definitionType()==Definition::TypeClass)
5494  {
5495  result = !(toClassDef(d))->templateArguments().empty() ||
5497  }
5498  return result;
5499 }
5500 
5502  const ArgumentLists &srcTempArgLists,
5503  const ArgumentLists &dstTempArgLists,
5504  const std::string &src
5505  )
5506 {
5507  std::string dst;
5508  static const reg::Ex re(R"(\a\w*)");
5509  reg::Iterator it(src,re);
5511  //printf("type=%s\n",qPrint(sa->type));
5512  size_t p=0;
5513  for (; it!=end ; ++it) // for each word in srcType
5514  {
5515  const auto &match = *it;
5516  size_t i = match.position();
5517  size_t l = match.length();
5518  bool found=FALSE;
5519  dst+=src.substr(p,i-p);
5520  std::string name=match.str();
5521 
5522  auto srcIt = srcTempArgLists.begin();
5523  auto dstIt = dstTempArgLists.begin();
5524  while (srcIt!=srcTempArgLists.end() && !found)
5525  {
5526  const ArgumentList *tdAli = 0;
5527  std::vector<Argument>::const_iterator tdaIt;
5528  if (dstIt!=dstTempArgLists.end())
5529  {
5530  tdAli = &(*dstIt);
5531  tdaIt = tdAli->begin();
5532  ++dstIt;
5533  }
5534 
5535  const ArgumentList &tsaLi = *srcIt;
5536  for (auto tsaIt = tsaLi.begin(); tsaIt!=tsaLi.end() && !found; ++tsaIt)
5537  {
5538  Argument tsa = *tsaIt;
5539  const Argument *tda = 0;
5540  if (tdAli && tdaIt!=tdAli->end())
5541  {
5542  tda = &(*tdaIt);
5543  ++tdaIt;
5544  }
5545  //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5546  // qPrint(tsa.type),qPrint(tsa.name),
5547  // qPrint(tda->type),qPrint(tda->name));
5548  if (name==tsa.name.str())
5549  {
5550  if (tda && tda->name.isEmpty())
5551  {
5552  QCString tdaName = tda->name;
5553  QCString tdaType = tda->type;
5554  int vc=0;
5555  if (tdaType.left(6)=="class ") vc=6;
5556  else if (tdaType.left(9)=="typename ") vc=9;
5557  if (vc>0) // convert type=="class T" to type=="class" name=="T"
5558  {
5559  tdaName = tdaType.mid(vc);
5560  }
5561  if (!tdaName.isEmpty())
5562  {
5563  name=tdaName.str(); // substitute
5564  found=TRUE;
5565  }
5566  }
5567  }
5568  }
5569 
5570  //printf(" srcList='%s' dstList='%s faList='%s'\n",
5571  // qPrint(argListToString(srclali.current())),
5572  // qPrint(argListToString(dstlali.current())),
5573  // funcTempArgList ? qPrint(argListToString(funcTempArgList)) : "<none>");
5574  ++srcIt;
5575  }
5576  dst+=name;
5577  p=i+l;
5578  }
5579  dst+=src.substr(p);
5580  //printf(" substituteTemplatesInString(%s)=%s\n",
5581  // qPrint(src),qPrint(dst));
5582  return QCString(dst);
5583 }
5584 
5586  const ArgumentLists &srcTempArgLists,
5587  const ArgumentLists &dstTempArgLists,
5588  const ArgumentList &src,
5589  ArgumentList &dst
5590  )
5591 {
5592  auto dstIt = dst.begin();
5593  for (const Argument &sa : src)
5594  {
5595  QCString dstType = substituteTemplatesInString(srcTempArgLists,dstTempArgLists,sa.type.str());
5596  QCString dstArray = substituteTemplatesInString(srcTempArgLists,dstTempArgLists,sa.array.str());
5597  if (dstIt == dst.end())
5598  {
5599  Argument da = sa;
5600  da.type = dstType;
5601  da.array = dstArray;
5602  dst.push_back(da);
5603  dstIt = dst.end();
5604  }
5605  else
5606  {
5607  Argument da = *dstIt;
5608  da.type = dstType;
5609  da.array = dstArray;
5610  ++dstIt;
5611  }
5612  }
5613  dst.setConstSpecifier(src.constSpecifier());
5614  dst.setVolatileSpecifier(src.volatileSpecifier());
5615  dst.setPureSpecifier(src.pureSpecifier());
5617  srcTempArgLists,dstTempArgLists,
5618  src.trailingReturnType().str()));
5619  //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5620  // qPrint(argListToString(src)),qPrint(argListToString(dst))
5621  // );
5622 }
5623 
5624 //-------------------------------------------------------------------------------------------
5625 
5626 static void addLocalObjCMethod(const Entry *root,
5627  const QCString &scopeName,
5628  const QCString &funcType,const QCString &funcName,const QCString &funcArgs,
5629  const QCString &exceptions,const QCString &funcDecl,
5630  uint64 spec)
5631 {
5632  //printf("scopeName='%s' className='%s'\n",qPrint(scopeName),qPrint(className));
5633  ClassDefMutable *cd=0;
5634  if (Config_getBool(EXTRACT_LOCAL_METHODS) && (cd=getClassMutable(scopeName)))
5635  {
5636  Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
5637  " scopeName=%s\n",qPrint(root->name),qPrint(scopeName));
5638  //printf("Local objective C method '%s' of class '%s' found\n",qPrint(root->name),qPrint(cd->name()));
5639  std::unique_ptr<MemberDefMutable> md { createMemberDef(
5640  root->fileName,root->startLine,root->startColumn,
5641  funcType,funcName,funcArgs,exceptions,
5642  root->protection,root->virt,root->stat,Member,
5644  md->setTagInfo(root->tagInfo());
5645  md->setLanguage(root->lang);
5646  md->setId(root->id);
5648  md->setMemberClass(cd);
5649  md->setDefinition(funcDecl);
5650  md->enableCallGraph(root->callGraph);
5651  md->enableCallerGraph(root->callerGraph);
5654  md->setDocumentation(root->doc,root->docFile,root->docLine);
5655  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5656  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5657  md->setDocsForDefinition(!root->proto);
5658  md->setPrototype(root->proto,root->fileName,root->startLine,root->startColumn);
5659  md->addSectionsToDefinition(root->anchors);
5660  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
5661  FileDef *fd=root->fileDef();
5662  md->setBodyDef(fd);
5663  md->setMemberSpecifiers(spec);
5664  md->setMemberGroupId(root->mGrpId);
5665  cd->insertMember(md.get());
5666  cd->insertUsedFile(fd);
5667  md->setRefItems(root->sli);
5668 
5670  mn->push_back(std::move(md));
5671  }
5672  else
5673  {
5674  // local objective C method found for class without interface
5675  }
5676 }
5677 
5678 //-------------------------------------------------------------------------------------------
5679 
5680 static void addMemberFunction(const Entry *root,
5681  MemberName *mn,
5682  const QCString &scopeName,
5683  const QCString &namespaceName,
5684  const QCString &className,
5685  const QCString &funcTyp,
5686  const QCString &funcName,
5687  const QCString &funcArgs,
5688  const QCString &funcTempList,
5689  const QCString &exceptions,
5690  const QCString &type,
5691  const QCString &args,
5692  bool isFriend,
5693  uint64 spec,
5694  const QCString &relates,
5695  const QCString &funcDecl,
5696  bool overloaded,
5697  bool isFunc)
5698 {
5699  QCString funcType = funcTyp;
5700  int count=0;
5701  int noMatchCount=0;
5702  bool memFound=FALSE;
5703  for (const auto &imd : *mn)
5704  {
5705  MemberDefMutable *md = toMemberDefMutable(imd.get());
5706  if (md==0) continue;
5708  if (cd==0) continue;
5710  "3. member definition found, "
5711  "scope needed='%s' scope='%s' args='%s' fileName=%s\n",
5712  qPrint(scopeName),qPrint(cd->name()),
5713  qPrint(md->argsString()),
5714  qPrint(root->fileName));
5715  //printf("Member %s (member scopeName=%s) (this scopeName=%s) isEnumValue()=%d\n",
5716  // qPrint(md->name()),qPrint(cd->name()),qPrint(scopeName),md->isEnumValue());
5717  FileDef *fd=root->fileDef();
5718  NamespaceDef *nd=0;
5719  if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
5720 
5721  //printf("scopeName %s->%s\n",qPrint(scopeName),
5722  // qPrint(stripTemplateSpecifiersFromScope(scopeName,FALSE)));
5723 
5724  // if the member we are searching for is an enum value that is part of
5725  // a "strong" enum, we need to look into the fields of the enum for a match
5726  int enumNamePos=0;
5727  if (md->isEnumValue() && (enumNamePos=className.findRev("::"))!=-1)
5728  {
5729  QCString enumName = className.mid(enumNamePos+2);
5730  QCString fullScope = className.left(enumNamePos);
5731  if (!namespaceName.isEmpty()) fullScope.prepend(namespaceName+"::");
5732  if (fullScope==cd->name())
5733  {
5734  MemberName *enumMn=Doxygen::memberNameLinkedMap->find(enumName);
5735  //printf("enumMn(%s)=%p\n",qPrint(className),(void*)enumMn);
5736  if (enumMn)
5737  {
5738  for (const auto &emd : *enumMn)
5739  {
5740  memFound = emd->isStrong() && md->getEnumScope()==emd.get();
5741  if (memFound)
5742  {
5743  addMemberDocs(root,md,funcDecl,0,overloaded,spec);
5744  count++;
5745  }
5746  if (memFound) break;
5747  }
5748  }
5749  }
5750  }
5751  if (memFound) break;
5752 
5753  const ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
5754  if (tcd==0 && cd && stripAnonymousNamespaceScope(cd->name())==scopeName)
5755  {
5756  // don't be fooled by anonymous scopes
5757  tcd=cd;
5758  }
5759  //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
5760  // qPrint(scopeName),nd?qPrint(nd->name()):"<none>",tcd,tcd?qPrint(tcd->name()):"",cd);
5761 
5762  if (cd && tcd==cd) // member's classes match
5763  {
5765  "4. class definition %s found\n",qPrint(cd->name()));
5766 
5767  // get the template parameter lists found at the member declaration
5768  ArgumentLists declTemplArgs = cd->getTemplateParameterLists();
5769  const ArgumentList &templAl = md->templateArguments();
5770  if (!templAl.empty())
5771  {
5772  declTemplArgs.push_back(templAl);
5773  }
5774 
5775  // get the template parameter lists found at the member definition
5776  const ArgumentLists &defTemplArgs = root->tArgLists;
5777  //printf("defTemplArgs=%p\n",defTemplArgs);
5778 
5779  // do we replace the decl argument lists with the def argument lists?
5780  bool substDone=FALSE;
5781  ArgumentList argList;
5782 
5783  /* substitute the occurrences of class template names in the
5784  * argument list before matching
5785  */
5786  const ArgumentList &mdAl = md->argumentList();
5787  if (declTemplArgs.size()>0 && declTemplArgs.size()==defTemplArgs.size())
5788  {
5789  /* the function definition has template arguments
5790  * and the class definition also has template arguments, so
5791  * we must substitute the template names of the class by that
5792  * of the function definition before matching.
5793  */
5794  substituteTemplatesInArgList(declTemplArgs,defTemplArgs,mdAl,argList);
5795 
5796  substDone=TRUE;
5797  }
5798  else /* no template arguments, compare argument lists directly */
5799  {
5800  argList = mdAl;
5801  }
5802 
5804  "5. matching '%s'<=>'%s' className=%s namespaceName=%s\n",
5806  qPrint(className),qPrint(namespaceName)
5807  );
5808 
5809  bool matching=
5810  md->isVariable() || md->isTypedef() || // needed for function pointers
5812  md->getClassDef(),md->getFileDef(),&argList,
5813  cd,fd,&root->argList,
5814  TRUE);
5815 
5816  if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
5817  {
5818  matching = FALSE; // don't match methods and attributes with the same name
5819  }
5820 
5821  // for template member we also need to check the return type
5822  if (!md->templateArguments().empty() && !root->tArgLists.empty())
5823  {
5824  QCString memType = md->typeString();
5825  memType.stripPrefix("static "); // see bug700696
5827  className+"::",""); // see bug700693 & bug732594
5829  className+"::",""); // see bug758900
5831  "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
5832  qPrint(md->typeString()),qPrint(funcType),
5833  md->templateArguments().size(),root->tArgLists.back().size());
5834  if (md->templateArguments().size()!=root->tArgLists.back().size() || memType!=funcType)
5835  {
5836  //printf(" ---> no matching\n");
5837  matching = FALSE;
5838  }
5839  }
5840  bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
5841  bool classIsTemplate = scopeIsTemplate(md->getClassDef());
5842  bool mdIsTemplate = md->templateArguments().hasParameters();
5843  bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
5844  bool rootIsTemplate = !root->tArgLists.empty();
5845  //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
5846  if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
5847  (mdIsTemplate || rootIsTemplate) && // either md or root is a template
5848  ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
5849  )
5850  {
5851  // Method with template return type does not match method without return type
5852  // even if the parameters are the same. See also bug709052
5854  "5b. Comparing return types: template v.s. non-template\n");
5855  matching = FALSE;
5856  }
5857 
5858 
5860  "6. match results of matchArguments2 = %d substDone=%d\n",matching,substDone);
5861 
5862  if (substDone) // found a new argument list
5863  {
5864  if (matching) // replace member's argument list
5865  {
5867  md->moveArgumentList(std::make_unique<ArgumentList>(argList));
5868  }
5869  else // no match
5870  {
5871  if (!funcTempList.isEmpty() &&
5872  isSpecialization(declTemplArgs,defTemplArgs))
5873  {
5874  // check if we are dealing with a partial template
5875  // specialization. In this case we add it to the class
5876  // even though the member arguments do not match.
5877 
5878  addMethodToClass(root,cd,type,md->name(),args,isFriend,
5879  md->protection(),md->isStatic(),md->virtualness(),spec,relates);
5880  return;
5881  }
5882  }
5883  }
5884  if (matching)
5885  {
5886  addMemberDocs(root,md,funcDecl,0,overloaded,spec);
5887  count++;
5888  memFound=TRUE;
5889  }
5890  }
5891  else if (cd && cd!=tcd) // we did find a class with the same name as cd
5892  // but in a different namespace
5893  {
5894  noMatchCount++;
5895  }
5896 
5897  if (memFound) break;
5898  }
5899  if (count==0 && root->parent() &&
5901  {
5902  addLocalObjCMethod(root,scopeName,funcType,funcName,funcArgs,exceptions,funcDecl,spec);
5903  return;
5904  }
5905  if (count==0 && !(isFriend && funcType=="class"))
5906  {
5907  int candidates=0;
5908  const ClassDef *ecd = 0, *ucd = 0;
5909  MemberDef *emd = 0, *umd = 0;
5910  //printf("Assume template class\n");
5911  for (const auto &md : *mn)
5912  {
5914  MemberDef *cmd=md.get();
5915  //printf("ccd->name()==%s className=%s\n",qPrint(ccd->name()),qPrint(className));
5916  if (ccd!=0 && rightScopeMatch(ccd->name(),className))
5917  {
5918  const ArgumentList &templAl = md->templateArguments();
5919  if (!root->tArgLists.empty() && !templAl.empty() &&
5920  root->tArgLists.back().size()<=templAl.size())
5921  {
5922  Debug::print(Debug::FindMembers,0,"7. add template specialization\n");
5923  addMethodToClass(root,ccd,type,md->name(),args,isFriend,
5924  root->protection,root->stat,root->virt,spec,relates);
5925  return;
5926  }
5927  if (md->argsString()==argListToString(root->argList,FALSE,FALSE))
5928  { // exact argument list match -> remember
5929  ucd = ecd = ccd;
5930  umd = emd = cmd;
5932  "7. new candidate className=%s scope=%s args=%s exact match\n",
5933  qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
5934  }
5935  else // arguments do not match, but member name and scope do -> remember
5936  {
5937  ucd = ccd;
5938  umd = cmd;
5940  "7. new candidate className=%s scope=%s args=%s no match\n",
5941  qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
5942  }
5943  candidates++;
5944  }
5945  }
5946  static bool strictProtoMatching = Config_getBool(STRICT_PROTO_MATCHING);
5947  if (!strictProtoMatching)
5948  {
5949  if (candidates==1 && ucd && umd)
5950  {
5951  // we didn't find an actual match on argument lists, but there is only 1 member with this
5952  // name in the same scope, so that has to be the one.
5953  addMemberDocs(root,toMemberDefMutable(umd),funcDecl,0,overloaded,spec);
5954  return;
5955  }
5956  else if (candidates>1 && ecd && emd)
5957  {
5958  // we didn't find a unique match using type resolution,
5959  // but one of the matches has the exact same signature so
5960  // we take that one.
5961  addMemberDocs(root,toMemberDefMutable(emd),funcDecl,0,overloaded,spec);
5962  return;
5963  }
5964  }
5965 
5966  QCString warnMsg = "no ";
5967  if (noMatchCount>1) warnMsg+="uniquely ";
5968  warnMsg+="matching class member found for \n";
5969 
5970  for (const ArgumentList &al : root->tArgLists)
5971  {
5972  warnMsg+=" template ";
5973  warnMsg+=tempArgListToString(al,root->lang);
5974  warnMsg+='\n';
5975  }
5976 
5977  QCString fullFuncDecl=funcDecl;
5978  if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
5979 
5980  warnMsg+=" ";
5981  warnMsg+=fullFuncDecl;
5982  warnMsg+='\n';
5983 
5984  if (candidates>0)
5985  {
5986  warnMsg+="Possible candidates:\n";
5987  for (const auto &md : *mn)
5988  {
5989  const ClassDef *cd=md->getClassDef();
5990  if (cd!=0 && rightScopeMatch(cd->name(),className))
5991  {
5992  const ArgumentList &templAl = md->templateArguments();
5993  warnMsg+=" '";
5994  if (templAl.hasParameters())
5995  {
5996  warnMsg+="template ";
5997  warnMsg+=tempArgListToString(templAl,root->lang);
5998  warnMsg+='\n';
5999  warnMsg+=" ";
6000  }
6001  if (!md->typeString().isEmpty())
6002  {
6003  warnMsg+=md->typeString();
6004  warnMsg+=' ';
6005  }
6007  if (!qScope.isEmpty())
6008  warnMsg+=qScope+"::"+md->name();
6009  warnMsg+=md->argsString();
6010  if (noMatchCount>1)
6011  {
6012  warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6013  " of file "+md->getDefFileName();
6014  }
6015  else
6016  warnMsg += "'";
6017 
6018  warnMsg+='\n';
6019  }
6020  }
6021  }
6022  warn_simple(root->fileName,root->startLine,qPrint(warnMsg));
6023  }
6024 }
6025 
6026 //-------------------------------------------------------------------------------------------
6027 
6028 static void addMemberSpecialization(const Entry *root,
6029  MemberName *mn,
6030  ClassDefMutable *cd,
6031  const QCString &funcType,
6032  const QCString &funcName,
6033  const QCString &funcArgs,
6034  const QCString &funcDecl,
6035  const QCString &exceptions,
6036  uint64 spec
6037  )
6038 {
6039  MemberDef *declMd=0;
6040  for (const auto &md : *mn)
6041  {
6042  if (md->getClassDef()==cd)
6043  {
6044  // TODO: we should probably also check for matching arguments
6045  declMd = md.get();
6046  break;
6047  }
6048  }
6050  ArgumentList tArgList;
6051  // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6052  std::unique_ptr<MemberDefMutable> md { createMemberDef(
6053  root->fileName,root->startLine,root->startColumn,
6054  funcType,funcName,funcArgs,exceptions,
6055  declMd ? declMd->protection() : root->protection,
6056  root->virt,root->stat,Member,
6057  mtype,tArgList,root->argList,root->metaData) };
6058  //printf("new specialized member %s args='%s'\n",qPrint(md->name()),qPrint(funcArgs));
6059  md->setTagInfo(root->tagInfo());
6060  md->setLanguage(root->lang);
6061  md->setId(root->id);
6062  md->setMemberClass(cd);
6064  md->setTypeConstraints(root->typeConstr);
6065  md->setDefinition(funcDecl);
6066  md->enableCallGraph(root->callGraph);
6067  md->enableCallerGraph(root->callerGraph);
6070  md->setDocumentation(root->doc,root->docFile,root->docLine);
6071  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6072  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6073  md->setDocsForDefinition(!root->proto);
6074  md->setPrototype(root->proto,root->fileName,root->startLine,root->startColumn);
6075  md->addSectionsToDefinition(root->anchors);
6076  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
6077  FileDef *fd=root->fileDef();
6078  md->setBodyDef(fd);
6079  md->setMemberSpecifiers(spec);
6080  md->setMemberGroupId(root->mGrpId);
6081  cd->insertMember(md.get());
6082  md->setRefItems(root->sli);
6083 
6084  mn->push_back(std::move(md));
6085 }
6086 
6087 //-------------------------------------------------------------------------------------------
6088 
6089 static void addOverloaded(const Entry *root,MemberName *mn,
6090  const QCString &funcType,const QCString &funcName,const QCString &funcArgs,
6091  const QCString &funcDecl,const QCString &exceptions,uint64 spec)
6092 {
6093  // for unique overloaded member we allow the class to be
6094  // omitted, this is to be Qt compatible. Using this should
6095  // however be avoided, because it is error prone
6096  bool sameClass=false;
6097  if (mn->size()>0)
6098  {
6099  // check if all members with the same name are also in the same class
6100  sameClass = std::equal(mn->begin()+1,mn->end(),mn->begin(),
6101  [](const auto &md1,const auto &md2)
6102  { return md1->getClassDef()->name()==md2->getClassDef()->name(); });
6103  }
6104  if (sameClass)
6105  {
6106  ClassDefMutable *cd = mn->front()->getClassDefMutable();
6107  MemberType mtype;
6108  if (root->mtype==Signal) mtype=MemberType_Signal;
6109  else if (root->mtype==Slot) mtype=MemberType_Slot;
6110  else if (root->mtype==DCOP) mtype=MemberType_DCOP;
6111  else mtype=MemberType_Function;
6112 
6113  // new overloaded member function
6114  std::unique_ptr<ArgumentList> tArgList =
6115  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6116  //printf("new related member %s args='%s'\n",qPrint(md->name()),qPrint(funcArgs));
6117  std::unique_ptr<MemberDefMutable> md { createMemberDef(
6118  root->fileName,root->startLine,root->startColumn,
6119  funcType,funcName,funcArgs,exceptions,
6120  root->protection,root->virt,root->stat,Related,
6121  mtype,tArgList ? *tArgList : ArgumentList(),root->argList,root->metaData) };
6122  md->setTagInfo(root->tagInfo());
6123  md->setLanguage(root->lang);
6124  md->setId(root->id);
6125  md->setTypeConstraints(root->typeConstr);
6126  md->setMemberClass(cd);
6127  md->setDefinition(funcDecl);
6128  md->enableCallGraph(root->callGraph);
6129  md->enableCallerGraph(root->callerGraph);
6132  QCString doc=getOverloadDocs();
6133  doc+="<p>";
6134  doc+=root->doc;
6135  md->setDocumentation(doc,root->docFile,root->docLine);
6136  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6137  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6138  md->setDocsForDefinition(!root->proto);
6139  md->setPrototype(root->proto,root->fileName,root->startLine,root->startColumn);
6140  md->addSectionsToDefinition(root->anchors);
6141  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
6142  FileDef *fd=root->fileDef();
6143  md->setBodyDef(fd);
6144  md->setMemberSpecifiers(spec);
6145  md->setMemberGroupId(root->mGrpId);
6146  cd->insertMember(md.get());
6147  cd->insertUsedFile(fd);
6148  md->setRefItems(root->sli);
6149 
6150  mn->push_back(std::move(md));
6151  }
6152 }
6153 
6154 //-------------------------------------------------------------------------------------------
6155 
6156 /*! This function tries to find a member (in a documented class/file/namespace)
6157  * that corresponds to the function/variable declaration given in \a funcDecl.
6158  *
6159  * The boolean \a overloaded is used to specify whether or not a standard
6160  * overload documentation line should be generated.
6161  *
6162  * The boolean \a isFunc is a hint that indicates that this is a function
6163  * instead of a variable or typedef.
6164  */
6165 static void findMember(const Entry *root,
6166  const QCString &relates,
6167  const QCString &type,
6168  const QCString &args,
6169  QCString funcDecl,
6170  bool overloaded,
6171  bool isFunc
6172  )
6173 {
6175  "findMember(root=%p,funcDecl='%s',related='%s',overload=%d,"
6176  "isFunc=%d mGrpId=%d #tArgList=%d "
6177  "spec=%lld lang=%x\n",
6178  root,qPrint(funcDecl),qPrint(relates),overloaded,isFunc,root->mGrpId,
6179  root->tArgLists.size(),
6180  root->spec,root->lang
6181  );
6182 
6183  QCString scopeName;
6184  QCString className;
6185  QCString namespaceName;
6186  QCString funcType;
6187  QCString funcName;
6188  QCString funcArgs;
6189  QCString funcTempList;
6190  QCString exceptions;
6191  QCString funcSpec;
6192  bool isRelated=FALSE;
6193  bool isMemberOf=FALSE;
6194  bool isFriend=FALSE;
6195  bool done;
6196  uint64 spec = root->spec;
6197  do
6198  {
6199  done=TRUE;
6200  if (funcDecl.stripPrefix("friend ")) // treat friends as related members
6201  {
6202  isFriend=TRUE;
6203  done=FALSE;
6204  }
6205  if (funcDecl.stripPrefix("inline "))
6206  {
6207  spec|=Entry::Inline;
6208  done=FALSE;
6209  }
6210  if (funcDecl.stripPrefix("explicit "))
6211  {
6212  spec|=Entry::Explicit;
6213  done=FALSE;
6214  }
6215  if (funcDecl.stripPrefix("mutable "))
6216  {
6217  spec|=Entry::Mutable;
6218  done=FALSE;
6219  }
6220  if (funcDecl.stripPrefix("virtual "))
6221  {
6222  done=FALSE;
6223  }
6224  } while (!done);
6225 
6226  // delete any ; from the function declaration
6227  int sep;
6228  while ((sep=funcDecl.find(';'))!=-1)
6229  {
6230  funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
6231  }
6232 
6233  // make sure the first character is a space to simplify searching.
6234  if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
6235 
6236  // remove some superfluous spaces
6237  funcDecl= substitute(
6238  substitute(
6239  substitute(funcDecl,"~ ","~"),
6240  ":: ","::"
6241  ),
6242  " ::","::"
6243  ).stripWhiteSpace();
6244 
6245  //printf("funcDecl='%s'\n",qPrint(funcDecl));
6246  if (isFriend && funcDecl.left(6)=="class ")
6247  {
6248  //printf("friend class\n");
6249  funcDecl=funcDecl.right(funcDecl.length()-6);
6250  funcName = funcDecl;
6251  }
6252  else if (isFriend && funcDecl.left(7)=="struct ")
6253  {
6254  funcDecl=funcDecl.right(funcDecl.length()-7);
6255  funcName = funcDecl;
6256  }
6257  else
6258  {
6259  // extract information from the declarations
6260  parseFuncDecl(funcDecl,root->lang,scopeName,funcType,funcName,
6261  funcArgs,funcTempList,exceptions
6262  );
6263  }
6264  //printf("scopeName='%s' funcType='%s' funcName='%s' funcArgs='%s'\n",
6265  // qPrint(scopeName),qPrint(funcType),qPrint(funcName),qPrint(funcArgs));
6266 
6267  // the class name can also be a namespace name, we decide this later.
6268  // if a related class name is specified and the class name could
6269  // not be derived from the function declaration, then use the
6270  // related field.
6271  //printf("scopeName='%s' className='%s' namespaceName='%s'\n",
6272  // qPrint(scopeName),qPrint(className),qPrint(namespaceName));
6273  if (!relates.isEmpty())
6274  { // related member, prefix user specified scope
6275  isRelated=TRUE;
6276  isMemberOf=(root->relatesType == MemberOf);
6277  if (getClass(relates)==0 && !scopeName.isEmpty())
6278  {
6279  scopeName= mergeScopes(scopeName,relates);
6280  }
6281  else
6282  {
6283  scopeName = relates;
6284  }
6285  }
6286 
6287  if (relates.isEmpty() && root->parent() &&
6288  ((root->parent()->section&Entry::SCOPE_MASK) ||
6289  (root->parent()->section==Entry::OBJCIMPL_SEC)
6290  ) &&
6291  !root->parent()->name.isEmpty()) // see if we can combine scopeName
6292  // with the scope in which it was found
6293  {
6294  QCString joinedName = root->parent()->name+"::"+scopeName;
6295  if (!scopeName.isEmpty() &&
6296  (getClass(joinedName) || Doxygen::namespaceLinkedMap->find(joinedName)))
6297  {
6298  scopeName = joinedName;
6299  }
6300  else
6301  {
6302  scopeName = mergeScopes(root->parent()->name,scopeName);
6303  }
6304  }
6305  else // see if we can prefix a namespace or class that is used from the file
6306  {
6307  FileDef *fd=root->fileDef();
6308  if (fd)
6309  {
6310  for (const auto &fnd : fd->getUsedNamespaces())
6311  {
6312  QCString joinedName = fnd->name()+"::"+scopeName;
6313  if (Doxygen::namespaceLinkedMap->find(joinedName))
6314  {
6315  scopeName=joinedName;
6316  break;
6317  }
6318  }
6319  }
6320  }
6322  removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
6323 
6324  // funcSpec contains the last template specifiers of the given scope.
6325  // If this method does not have any template arguments or they are
6326  // empty while funcSpec is not empty we assume this is a
6327  // specialization of a method. If not, we clear the funcSpec and treat
6328  // this as a normal method of a template class.
6329  if (!(root->tArgLists.size()>0 &&
6330  root->tArgLists.front().size()==0
6331  )
6332  )
6333  {
6334  funcSpec.resize(0);
6335  }
6336 
6337  // split scope into a namespace and a class part
6338  extractNamespaceName(scopeName,className,namespaceName,TRUE);
6339  //printf("scopeName='%s' className='%s' namespaceName='%s'\n",
6340  // qPrint(scopeName),qPrint(className),qPrint(namespaceName));
6341 
6342  //namespaceName=removeAnonymousScopes(namespaceName);
6343  if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
6344 
6345  //printf("namespaceName='%s' className='%s'\n",qPrint(namespaceName),qPrint(className));
6346  // merge class and namespace scopes again
6347  scopeName.resize(0);
6348  if (!namespaceName.isEmpty())
6349  {
6350  if (className.isEmpty())
6351  {
6352  scopeName=namespaceName;
6353  }
6354  else if (!relates.isEmpty() || // relates command with explicit scope
6355  !getClass(className)) // class name only exists in a namespace
6356  {
6357  scopeName=namespaceName+"::"+className;
6358  }
6359  else
6360  {
6361  scopeName=className;
6362  }
6363  }
6364  else if (!className.isEmpty())
6365  {
6366  scopeName=className;
6367  }
6368  //printf("new scope='%s'\n",qPrint(scopeName));
6369 
6370  QCString tempScopeName=scopeName;
6371  ClassDefMutable *cd=getClassMutable(scopeName);
6372  if (cd)
6373  {
6374  if (funcSpec.isEmpty())
6375  {
6376  uint argListIndex=0;
6377  tempScopeName=cd->qualifiedNameWithTemplateParameters(&root->tArgLists,&argListIndex);
6378  }
6379  else
6380  {
6381  tempScopeName=scopeName+funcSpec;
6382  }
6383  }
6384  //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
6385  // qPrint(scopeName),cd,root->tArgLists,qPrint(tempScopeName));
6386 
6387  //printf("scopeName='%s' className='%s'\n",qPrint(scopeName),qPrint(className));
6388  // rebuild the function declaration (needed to get the scope right).
6389  if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool(HIDE_SCOPE_NAMES))
6390  {
6391  if (!funcType.isEmpty())
6392  {
6393  if (isFunc) // a function -> we use argList for the arguments
6394  {
6395  funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
6396  }
6397  else
6398  {
6399  funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
6400  }
6401  }
6402  else
6403  {
6404  if (isFunc) // a function => we use argList for the arguments
6405  {
6406  funcDecl=tempScopeName+"::"+funcName+funcTempList;
6407  }
6408  else // variable => add 'argument' list
6409  {
6410  funcDecl=tempScopeName+"::"+funcName+funcArgs;
6411  }
6412  }
6413  }
6414  else // build declaration without scope
6415  {
6416  if (!funcType.isEmpty()) // but with a type
6417  {
6418  if (isFunc) // function => omit argument list
6419  {
6420  funcDecl=funcType+" "+funcName+funcTempList;
6421  }
6422  else // variable => add 'argument' list
6423  {
6424  funcDecl=funcType+" "+funcName+funcArgs;
6425  }
6426  }
6427  else // no type
6428  {
6429  if (isFunc)
6430  {
6431  funcDecl=funcName+funcTempList;
6432  }
6433  else
6434  {
6435  funcDecl=funcName+funcArgs;
6436  }
6437  }
6438  }
6439 
6440  if (funcType=="template class" && !funcTempList.isEmpty())
6441  return; // ignore explicit template instantiations
6442 
6444  "findMember() Parse results:\n"
6445  " namespaceName='%s'\n"
6446  " className=`%s`\n"
6447  " funcType='%s'\n"
6448  " funcSpec='%s'\n"
6449  " funcName='%s'\n"
6450  " funcArgs='%s'\n"
6451  " funcTempList='%s'\n"
6452  " funcDecl='%s'\n"
6453  " related='%s'\n"
6454  " exceptions='%s'\n"
6455  " isRelated=%d\n"
6456  " isMemberOf=%d\n"
6457  " isFriend=%d\n"
6458  " isFunc=%d\n\n",
6459  qPrint(namespaceName),qPrint(className),
6460  qPrint(funcType),qPrint(funcSpec),qPrint(funcName),qPrint(funcArgs),qPrint(funcTempList),
6461  qPrint(funcDecl),qPrint(relates),qPrint(exceptions),isRelated,isMemberOf,isFriend,
6462  isFunc
6463  );
6464 
6465  if (!funcName.isEmpty()) // function name is valid
6466  {
6468  "1. funcName='%s'\n",qPrint(funcName));
6469 
6470  // check if 'className' is actually a scoped enum, in which case we need to
6471  // process it as a global, see issue #6471
6472  bool strongEnum = false;
6473  MemberName *mn=0;
6474  if (!className.isEmpty() && (mn=Doxygen::functionNameLinkedMap->find(className)))
6475  {
6476  for (const auto &imd : *mn)
6477  {
6478  MemberDefMutable *md = toMemberDefMutable(imd.get());
6479  if (md && md->isEnumerate() && md->isStrong())
6480  {
6481  Debug::print(Debug::FindMembers,0,"%s is a strong enum!\n",qPrint(md->name()));
6482  strongEnum = true;
6483  // pass the scope name name as a 'namespace' to the findGlobalMember function
6484  if (!namespaceName.isEmpty())
6485  {
6486  namespaceName+="::"+className;
6487  }
6488  else
6489  {
6490  namespaceName=className;
6491  }
6492  }
6493  }
6494  }
6495 
6496  if (funcName.left(9)=="operator ") // strip class scope from cast operator
6497  {
6498  funcName = substitute(funcName,className+"::","");
6499  }
6500  mn = 0;
6501  if (!funcTempList.isEmpty()) // try with member specialization
6502  {
6503  mn=Doxygen::memberNameLinkedMap->find(funcName+funcTempList);
6504  }
6505  if (mn==0) // try without specialization
6506  {
6507  mn=Doxygen::memberNameLinkedMap->find(funcName);
6508  }
6509  if (!isRelated && !strongEnum && mn) // function name already found
6510  {
6512  "2. member name exists (%d members with this name)\n",mn->size());
6513  if (!className.isEmpty()) // class name is valid
6514  {
6515  if (funcSpec.isEmpty()) // not a member specialization
6516  {
6517  addMemberFunction(root,mn,scopeName,namespaceName,className,funcType,funcName,
6518  funcArgs,funcTempList,exceptions,
6519  type,args,isFriend,spec,relates,funcDecl,overloaded,isFunc);
6520  }
6521  else if (cd) // member specialization
6522  {
6523  addMemberSpecialization(root,mn,cd,funcType,funcName,funcArgs,funcDecl,exceptions,spec);
6524  }
6525  else
6526  {
6527  //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6528  // qPrint(scopeName),qPrint(funcName),qPrint(funcArgs));
6529  }
6530  }
6531  else if (overloaded) // check if the function belongs to only one class
6532  {
6533  addOverloaded(root,mn,funcType,funcName,funcArgs,funcDecl,exceptions,spec);
6534  }
6535  else // unrelated function with the same name as a member
6536  {
6537  if (!findGlobalMember(root,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl,spec))
6538  {
6539  QCString fullFuncDecl=funcDecl;
6540  if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6541  warn(root->fileName,root->startLine,
6542  "Cannot determine class for function\n%s",
6543  qPrint(fullFuncDecl)
6544  );
6545  }
6546  }
6547  }
6548  else if (isRelated && !relates.isEmpty())
6549  {
6550  Debug::print(Debug::FindMembers,0,"2. related function\n"
6551  " scopeName=%s className=%s\n",qPrint(scopeName),qPrint(className));
6552  if (className.isEmpty()) className=relates;
6553  //printf("scopeName='%s' className='%s'\n",qPrint(scopeName),qPrint(className));
6554  if ((cd=getClassMutable(scopeName)))
6555  {
6556  bool newMember=TRUE; // assume we have a new member
6557  MemberDefMutable *mdDefine=0;
6558  {
6559  mn = Doxygen::functionNameLinkedMap->find(funcName);
6560  if (mn)
6561  {
6562  for (const auto &imd : *mn)
6563  {
6564  MemberDefMutable *md = toMemberDefMutable(imd.get());
6565  if (md && md->isDefine())
6566  {
6567  mdDefine = md;
6568  break;
6569  }
6570  }
6571  }
6572  }
6573 
6574  FileDef *fd=root->fileDef();
6575 
6576  if ((mn=Doxygen::memberNameLinkedMap->find(funcName))==0)
6577  {
6578  mn=Doxygen::memberNameLinkedMap->add(funcName);
6579  }
6580  else
6581  {
6582  // see if we got another member with matching arguments
6583  MemberDefMutable *rmd_found = 0;
6584  for (const auto &irmd : *mn)
6585  {
6586  MemberDefMutable *rmd = toMemberDefMutable(irmd.get());
6587  if (rmd)
6588  {
6589  const ArgumentList &rmdAl = rmd->argumentList();
6590 
6591  newMember=
6592  className!=rmd->getOuterScope()->name() ||
6593  !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),&rmdAl,
6594  cd,fd,&root->argList,
6595  TRUE);
6596  if (!newMember)
6597  {
6598  rmd_found = rmd;
6599  }
6600  }
6601  }
6602  if (rmd_found) // member already exists as rmd -> add docs
6603  {
6604  //printf("addMemberDocs for related member %s\n",qPrint(root->name));
6605  //rmd->setMemberDefTemplateArguments(root->mtArgList);
6606  addMemberDocs(root,rmd_found,funcDecl,0,overloaded,spec);
6607  }
6608  }
6609 
6610  if (newMember) // need to create a new member
6611  {
6612  MemberType mtype;
6613  if (mdDefine)
6614  mtype=MemberType_Define;
6615  else if (root->mtype==Signal)
6616  mtype=MemberType_Signal;
6617  else if (root->mtype==Slot)
6618  mtype=MemberType_Slot;
6619  else if (root->mtype==DCOP)
6620  mtype=MemberType_DCOP;
6621  else
6622  mtype=MemberType_Function;
6623 
6624  if (mdDefine)
6625  {
6626  mdDefine->setHidden(TRUE);
6627  funcType="#define";
6628  funcArgs=mdDefine->argsString();
6629  funcDecl=funcType + " " + funcName;
6630  }
6631 
6632  //printf("New related name '%s' '%d'\n",qPrint(funcName),
6633  // root->argList ? (int)root->argList->count() : -1);
6634 
6635  // first note that we pass:
6636  // (root->tArgLists ? root->tArgLists->last() : 0)
6637  // for the template arguments for the new "member."
6638  // this accurately reflects the template arguments of
6639  // the related function, which don't have to do with
6640  // those of the related class.
6641  std::unique_ptr<MemberDefMutable> md { createMemberDef(
6642  root->fileName,root->startLine,root->startColumn,
6643  funcType,funcName,funcArgs,exceptions,
6644  root->protection,root->virt,
6645  root->stat && !isMemberOf,
6646  isMemberOf ? Foreign : Related,
6647  mtype,
6648  (!root->tArgLists.empty() ? root->tArgLists.back() : ArgumentList()),
6649  funcArgs.isEmpty() ? ArgumentList() : root->argList,
6650  root->metaData) };
6651 
6652  if (mdDefine)
6653  {
6654  md->setInitializer(mdDefine->initializer());
6655  }
6656 
6657  //
6658  // we still have the problem that
6659  // MemberDef::writeDocumentation() in memberdef.cpp
6660  // writes the template argument list for the class,
6661  // as if this member is a member of the class.
6662  // fortunately, MemberDef::writeDocumentation() has
6663  // a special mechanism that allows us to totally
6664  // override the set of template argument lists that
6665  // are printed. We use that and set it to the
6666  // template argument lists of the related function.
6667  //
6669 
6670  md->setTagInfo(root->tagInfo());
6671 
6672  //printf("Related member name='%s' decl='%s' bodyLine='%d'\n",
6673  // qPrint(funcName),qPrint(funcDecl),root->bodyLine);
6674 
6675  // try to find the matching line number of the body from the
6676  // global function list
6677  bool found=FALSE;
6678  if (root->bodyLine==-1)
6679  {
6681  if (rmn)
6682  {
6683  const MemberDefMutable *rmd_found=0;
6684  for (const auto &irmd : *rmn)
6685  {
6686  MemberDefMutable *rmd = toMemberDefMutable(irmd.get());
6687  if (rmd)
6688  {
6689  const ArgumentList &rmdAl = rmd->argumentList();
6690  // check for matching argument lists
6691  if (
6692  matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),&rmdAl,
6693  cd,fd,&root->argList,
6694  TRUE)
6695  )
6696  {
6697  found=TRUE;
6698  rmd_found = rmd;
6699  break;
6700  }
6701  }
6702  }
6703  if (rmd_found) // member found -> copy line number info
6704  {
6705  md->setBodySegment(rmd_found->getDefLine(),rmd_found->getStartBodyLine(),rmd_found->getEndBodyLine());
6706  md->setBodyDef(rmd_found->getBodyDef());
6707  //md->setBodyMember(rmd);
6708  }
6709  }
6710  }
6711  if (!found) // line number could not be found or is available in this
6712  // entry
6713  {
6714  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
6715  md->setBodyDef(fd);
6716  }
6717 
6718  //if (root->mGrpId!=-1)
6719  //{
6720  // md->setMemberGroup(memberGroupDict[root->mGrpId]);
6721  //}
6722  md->setMemberClass(cd);
6723  md->setMemberSpecifiers(spec);
6724  md->setDefinition(funcDecl);
6725  md->enableCallGraph(root->callGraph);
6726  md->enableCallerGraph(root->callerGraph);
6729  md->setDocumentation(root->doc,root->docFile,root->docLine);
6730  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6731  md->setDocsForDefinition(!root->proto);
6732  md->setPrototype(root->proto,root->fileName,root->startLine,root->startColumn);
6733  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6734  md->addSectionsToDefinition(root->anchors);
6735  md->setMemberGroupId(root->mGrpId);
6736  md->setLanguage(root->lang);
6737  md->setId(root->id);
6738  //md->setMemberDefTemplateArguments(root->mtArgList);
6739  cd->insertMember(md.get());
6740  cd->insertUsedFile(fd);
6741  md->setRefItems(root->sli);
6742  if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6743  if (!mdDefine)
6744  {
6745  addMemberToGroups(root,md.get());
6746  }
6747  //printf("Adding member=%s\n",qPrint(md->name()));
6748  mn->push_back(std::move(md));
6749  }
6750  if (root->relatesType == Duplicate)
6751  {
6752  if (!findGlobalMember(root,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl,spec))
6753  {
6754  QCString fullFuncDecl=funcDecl;
6755  if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6756  warn(root->fileName,root->startLine,
6757  "Cannot determine file/namespace for relatedalso function\n%s",
6758  qPrint(fullFuncDecl)
6759  );
6760  }
6761  }
6762  }
6763  else
6764  {
6765  warn_undoc(root->fileName,root->startLine,
6766  "class '%s' for related function '%s' is not "
6767  "documented.",
6768  qPrint(className),qPrint(funcName)
6769  );
6770  }
6771  }
6772  else if (root->parent() && root->parent()->section==Entry::OBJCIMPL_SEC)
6773  {
6774  addLocalObjCMethod(root,scopeName,funcType,funcName,funcArgs,exceptions,funcDecl,spec);
6775  }
6776  else // unrelated not overloaded member found
6777  {
6778  bool globMem = findGlobalMember(root,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl,spec);
6779  if (className.isEmpty() && !globMem)
6780  {
6781  warn(root->fileName,root->startLine,
6782  "class for member '%s' cannot "
6783  "be found.", qPrint(funcName)
6784  );
6785  }
6786  else if (!className.isEmpty() && !globMem)
6787  {
6788  warn(root->fileName,root->startLine,
6789  "member '%s' of class '%s' cannot be found",
6790  qPrint(funcName),qPrint(className));
6791  }
6792  }
6793  }
6794  else
6795  {
6796  // this should not be called
6797  warn(root->fileName,root->startLine,
6798  "member with no name found.");
6799  }
6800  return;
6801 }
6802 
6803 //----------------------------------------------------------------------
6804 // find the members corresponding to the different documentation blocks
6805 // that are extracted from the sources.
6806 
6807 static void filterMemberDocumentation(const Entry *root,const QCString &relates)
6808 {
6809  int i=-1,l;
6811  "findMemberDocumentation(): root->type='%s' root->inside='%s' root->name='%s' root->args='%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6812  qPrint(root->type),qPrint(root->inside),qPrint(root->name),qPrint(root->args),root->section,root->spec,root->mGrpId
6813  );
6814  //printf("root->parent()->name=%s\n",qPrint(root->parent()->name));
6815  bool isFunc=TRUE;
6816 
6817  QCString type = root->type;
6818  QCString args = root->args;
6819  if ( // detect func variable/typedef to func ptr
6820  (i=findFunctionPtr(type.str(),root->lang,&l))!=-1
6821  )
6822  {
6823  //printf("Fixing function pointer!\n");
6824  // fix type and argument
6825  args.prepend(type.right(type.length()-i-l));
6826  type=type.left(i+l);
6827  //printf("Results type=%s,name=%s,args=%s\n",qPrint(type),qPrint(root->name),qPrint(args));
6828  isFunc=FALSE;
6829  }
6830  else if ((type.left(8)=="typedef " && args.find('(')!=-1))
6831  // detect function types marked as functions
6832  {
6833  isFunc=FALSE;
6834  }
6835 
6836  //printf("Member %s isFunc=%d\n",qPrint(root->name),isFunc);
6837  if (root->section==Entry::MEMBERDOC_SEC)
6838  {
6839  //printf("Documentation for inline member '%s' found args='%s'\n",
6840  // qPrint(root->name),qPrint(args));
6841  //if (relates.length()) printf(" Relates %s\n",qPrint(relates));
6842  if (type.isEmpty())
6843  {
6844  findMember(root,
6845  relates,
6846  type,
6847  args,
6848  root->name + args + root->exception,
6849  FALSE,
6850  isFunc);
6851  }
6852  else
6853  {
6854  findMember(root,
6855  relates,
6856  type,
6857  args,
6858  type + " " + root->name + args + root->exception,
6859  FALSE,
6860  isFunc);
6861  }
6862  }
6863  else if (root->section==Entry::OVERLOADDOC_SEC)
6864  {
6865  //printf("Overloaded member %s found\n",qPrint(root->name));
6866  findMember(root,
6867  relates,
6868  type,
6869  args,
6870  root->name,
6871  TRUE,
6872  isFunc);
6873  }
6874  else if
6875  ((root->section==Entry::FUNCTION_SEC // function
6876  ||
6877  (root->section==Entry::VARIABLE_SEC && // variable
6878  !type.isEmpty() && // with a type
6879  g_compoundKeywords.find(type.str())==g_compoundKeywords.end() // that is not a keyword
6880  // (to skip forward declaration of class etc.)
6881  )
6882  )
6883  )
6884  {
6885  //printf("Documentation for member '%s' found args='%s' excp='%s'\n",
6886  // qPrint(root->name),qPrint(args),qPrint(root->exception));
6887  //if (relates.length()) printf(" Relates %s\n",qPrint(relates));
6888  //printf("Inside=%s\n Relates=%s\n",qPrint(root->inside),qPrint(relates));
6889  if (type=="friend class" || type=="friend struct" ||
6890  type=="friend union")
6891  {
6892  findMember(root,
6893  relates,
6894  type,
6895  args,
6896  type+" "+root->name,
6897  FALSE,FALSE);
6898 
6899  }
6900  else if (!type.isEmpty())
6901  {
6902  findMember(root,
6903  relates,
6904  type,
6905  args,
6906  type+" "+ root->inside + root->name + args + root->exception,
6907  FALSE,isFunc);
6908  }
6909  else
6910  {
6911  findMember(root,
6912  relates,
6913  type,
6914  args,
6915  root->inside + root->name + args + root->exception,
6916  FALSE,isFunc);
6917  }
6918  }
6919  else if (root->section==Entry::DEFINE_SEC && !relates.isEmpty())
6920  {
6921  findMember(root,
6922  relates,
6923  type,
6924  args,
6925  root->name + args,
6926  FALSE,
6927  !args.isEmpty());
6928  }
6929  else if (root->section==Entry::VARIABLEDOC_SEC)
6930  {
6931  //printf("Documentation for variable %s found\n",qPrint(root->name));
6932  //if (!relates.isEmpty()) printf(" Relates %s\n",qPrint(relates));
6933  findMember(root,
6934  relates,
6935  type,
6936  args,
6937  root->name,
6938  FALSE,
6939  FALSE);
6940  }
6941  else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
6943  {
6944  findMember(root,
6945  relates,
6946  type,
6947  args,
6948  type + " " + root->name,
6949  FALSE,
6950  FALSE);
6951  }
6952  else
6953  {
6954  // skip section
6955  //printf("skip section\n");
6956  }
6957 }
6958 
6959 static void findMemberDocumentation(const Entry *root)
6960 {
6961  if (root->section==Entry::MEMBERDOC_SEC ||
6963  root->section==Entry::FUNCTION_SEC ||
6964  root->section==Entry::VARIABLE_SEC ||
6966  root->section==Entry::DEFINE_SEC ||
6969  )
6970  {
6971  if (root->relatesType == Duplicate && !root->relates.isEmpty())
6972  {
6973  filterMemberDocumentation(root,"");
6974  }
6975  filterMemberDocumentation(root,root->relates);
6976  }
6977  for (const auto &e : root->children())
6978  {
6979  if (e->section!=Entry::ENUM_SEC)
6980  {
6981  findMemberDocumentation(e.get());
6982  }
6983  }
6984 }
6985 
6986 //----------------------------------------------------------------------
6987 
6988 static void findObjCMethodDefinitions(const Entry *root)
6989 {
6990  for (const auto &objCImpl : root->children())
6991  {
6992  if (objCImpl->section==Entry::OBJCIMPL_SEC)
6993  {
6994  for (const auto &objCMethod : objCImpl->children())
6995  {
6996  if (objCMethod->section==Entry::FUNCTION_SEC)
6997  {
6998  //Printf(" Found ObjC method definition %s\n",qPrint(objCMethod->name));
6999  findMember(objCMethod.get(),
7000  objCMethod->relates,
7001  objCMethod->type,
7002  objCMethod->args,
7003  objCMethod->type+" "+objCImpl->name+"::"+objCMethod->name+" "+objCMethod->args,
7004  FALSE,TRUE);
7005  objCMethod->section=Entry::EMPTY_SEC;
7006  }
7007  }
7008  }
7009  }
7010 }
7011 
7012 //----------------------------------------------------------------------
7013 // find and add the enumeration to their classes, namespaces or files
7014 
7015 static void findEnums(const Entry *root)
7016 {
7017  if (root->section==Entry::ENUM_SEC)
7018  {
7019  ClassDefMutable *cd=0;
7020  FileDef *fd=0;
7021  NamespaceDefMutable *nd=0;
7022  MemberNameLinkedMap *mnsd=0;
7023  bool isGlobal;
7024  bool isRelated=FALSE;
7025  bool isMemberOf=FALSE;
7026  //printf("Found enum with name '%s' relates=%s\n",qPrint(root->name),qPrint(root->relates));
7027  int i;
7028 
7029  QCString name;
7030  QCString scope;
7031 
7032  if ((i=root->name.findRev("::"))!=-1) // scope is specified
7033  {
7034  scope=root->name.left(i); // extract scope
7035  name=root->name.right(root->name.length()-i-2); // extract name
7036  if ((cd=getClassMutable(scope))==0) nd=getResolvedNamespaceMutable(scope);
7037  }
7038  else // no scope, check the scope in which the docs where found
7039  {
7040  if (( root->parent()->section & Entry::SCOPE_MASK )
7041  && !root->parent()->name.isEmpty()
7042  ) // found enum docs inside a compound
7043  {
7044  scope=root->parent()->name;
7045  if ((cd=getClassMutable(scope))==0) nd=getResolvedNamespaceMutable(scope);
7046  }
7047  name=root->name;
7048  }
7049 
7050  if (!root->relates.isEmpty())
7051  { // related member, prefix user specified scope
7052  isRelated=TRUE;
7053  isMemberOf=(root->relatesType == MemberOf);
7054  if (getClass(root->relates)==0 && !scope.isEmpty())
7055  scope=mergeScopes(scope,root->relates);
7056  else
7057  scope=root->relates;
7058  if ((cd=getClassMutable(scope))==0) nd=getResolvedNamespaceMutable(scope);
7059  }
7060 
7061  if (cd && !name.isEmpty()) // found a enum inside a compound
7062  {
7063  //printf("Enum '%s'::'%s'\n",qPrint(cd->name()),qPrint(name));
7064  fd=0;
7066  isGlobal=FALSE;
7067  }
7068  else if (nd) // found enum inside namespace
7069  {
7071  isGlobal=TRUE;
7072  }
7073  else // found a global enum
7074  {
7075  fd=root->fileDef();
7077  isGlobal=TRUE;
7078  }
7079 
7080  if (!name.isEmpty())
7081  {
7082  // new enum type
7083  std::unique_ptr<MemberDefMutable> md { createMemberDef(
7084  root->fileName,root->startLine,root->startColumn,
7085  QCString(),name,QCString(),QCString(),
7086  root->protection,Normal,FALSE,
7087  isMemberOf ? Foreign : isRelated ? Related : Member,
7089  ArgumentList(),ArgumentList(),root->metaData) };
7090  md->setTagInfo(root->tagInfo());
7091  md->setLanguage(root->lang);
7092  md->setId(root->id);
7093  if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7094  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
7095  md->setBodyDef(root->fileDef());
7096  md->setMemberSpecifiers(root->spec);
7097  md->setEnumBaseType(root->args);
7098  //printf("Enum %s definition at line %d of %s: protection=%d scope=%s\n",
7099  // qPrint(root->name),root->bodyLine,qPrint(root->fileName),root->protection,cd?qPrint(cd->name()):"<none>");
7100  md->addSectionsToDefinition(root->anchors);
7101  md->setMemberGroupId(root->mGrpId);
7102  md->enableCallGraph(root->callGraph);
7103  md->enableCallerGraph(root->callerGraph);
7106  //printf("%s::setRefItems(%zu)\n",qPrint(md->name()),root->sli.size());
7107  md->setRefItems(root->sli);
7108  //printf("found enum %s nd=%p\n",qPrint(md->name()),nd);
7109  bool defSet=FALSE;
7110 
7111  QCString baseType = root->args;
7112  if (!baseType.isEmpty())
7113  {
7114  baseType.prepend(" : ");
7115  }
7116 
7117  if (nd)
7118  {
7119  if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7120  {
7121  md->setDefinition(name+baseType);
7122  }
7123  else
7124  {
7125  md->setDefinition(nd->name()+"::"+name+baseType);
7126  }
7127  //printf("definition=%s\n",md->definition());
7128  defSet=TRUE;
7129  md->setNamespace(nd);
7130  nd->insertMember(md.get());
7131  }
7132 
7133  // even if we have already added the enum to a namespace, we still
7134  // also want to add it to other appropriate places such as file
7135  // or class.
7136  if (isGlobal && (nd==0 || !nd->isAnonymous()))
7137  {
7138  if (!defSet) md->setDefinition(name+baseType);
7139  if (fd==0 && root->parent())
7140  {
7141  fd=root->parent()->fileDef();
7142  }
7143  if (fd)
7144  {
7145  md->setFileDef(fd);
7146  fd->insertMember(md.get());
7147  }
7148  }
7149  else if (cd)
7150  {
7151  if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7152  {
7153  md->setDefinition(name+baseType);
7154  }
7155  else
7156  {
7157  md->setDefinition(cd->name()+"::"+name+baseType);
7158  }
7159  cd->insertMember(md.get());
7160  cd->insertUsedFile(fd);
7161  }
7162  md->setDocumentation(root->doc,root->docFile,root->docLine);
7163  md->setDocsForDefinition(!root->proto);
7164  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7165  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7166 
7167  //printf("Adding member=%s\n",qPrint(md->name()));
7168  addMemberToGroups(root,md.get());
7169 
7170  MemberName *mn = mnsd->add(name);
7171  mn->push_back(std::move(md));
7172  }
7173  }
7174  else
7175  {
7176  for (const auto &e : root->children()) findEnums(e.get());
7177  }
7178 }
7179 
7180 //----------------------------------------------------------------------
7181 
7182 static void addEnumValuesToEnums(const Entry *root)
7183 {
7184  if (root->section==Entry::ENUM_SEC)
7185  // non anonymous enumeration
7186  {
7187  ClassDefMutable *cd=0;
7188  FileDef *fd=0;
7189  NamespaceDefMutable *nd=0;
7190  MemberNameLinkedMap *mnsd=0;
7191  bool isGlobal;
7192  bool isRelated=FALSE;
7193  //printf("Found enum with name '%s' relates=%s\n",qPrint(root->name),qPrint(root->relates));
7194  int i;
7195 
7196  QCString name;
7197  QCString scope;
7198 
7199  if ((i=root->name.findRev("::"))!=-1) // scope is specified
7200  {
7201  scope=root->name.left(i); // extract scope
7202  name=root->name.right(root->name.length()-i-2); // extract name
7203  if ((cd=getClassMutable(scope))==0) nd=getResolvedNamespaceMutable(scope);
7204  }
7205  else // no scope, check the scope in which the docs where found
7206  {
7207  if (( root->parent()->section & Entry::SCOPE_MASK )
7208  && !root->parent()->name.isEmpty()
7209  ) // found enum docs inside a compound
7210  {
7211  scope=root->parent()->name;
7212  if ((cd=getClassMutable(scope))==0) nd=getResolvedNamespaceMutable(scope);
7213  }
7214  name=root->name;
7215  }
7216 
7217  if (!root->relates.isEmpty())
7218  { // related member, prefix user specified scope
7219  isRelated=TRUE;
7220  if (getClassMutable(root->relates)==0 && !scope.isEmpty())
7221  scope=mergeScopes(scope,root->relates);
7222  else
7223  scope=root->relates;
7224  if ((cd=getClassMutable(scope))==0) nd=getResolvedNamespaceMutable(scope);
7225  }
7226 
7227  if (cd && !name.isEmpty()) // found a enum inside a compound
7228  {
7229  //printf("Enum in class '%s'::'%s'\n",qPrint(cd->name()),qPrint(name));
7230  fd=0;
7232  isGlobal=FALSE;
7233  }
7234  else if (nd && !nd->isAnonymous()) // found enum inside namespace
7235  {
7236  //printf("Enum in namespace '%s'::'%s'\n",qPrint(nd->name()),qPrint(name));
7238  isGlobal=TRUE;
7239  }
7240  else // found a global enum
7241  {
7242  fd=root->fileDef();
7243  //printf("Enum in file '%s': '%s'\n",qPrint(fd->name()),qPrint(name));
7245  isGlobal=TRUE;
7246  }
7247 
7248  if (!name.isEmpty())
7249  {
7250  //printf("** name=%s\n",qPrint(name));
7251  MemberName *mn = mnsd->find(name); // for all members with this name
7252  if (mn)
7253  {
7254  struct EnumValueInfo
7255  {
7256  EnumValueInfo(const QCString &n,std::unique_ptr<MemberDefMutable> &md) :
7257  name(n), member(std::move(md)) {}
7258  QCString name;
7259  std::unique_ptr<MemberDefMutable> member;
7260  };
7261  std::vector< EnumValueInfo > extraMembers;
7262  // for each enum in this list
7263  for (const auto &imd : *mn)
7264  {
7265  MemberDefMutable *md = toMemberDefMutable(imd.get());
7266  // use raw pointer in this loop, since we modify mn and can then invalidate mdp.
7267  if (md && md->isEnumerate() && !root->children().empty())
7268  {
7269  //printf(" enum with %d children\n",root->children()->count());
7270  for (const auto &e : root->children())
7271  {
7272  SrcLangExt sle;
7273  if (
7274  (sle=root->lang)==SrcLangExt_CSharp ||
7275  sle==SrcLangExt_Java ||
7276  sle==SrcLangExt_XML ||
7277  (root->spec&Entry::Strong)
7278  )
7279  {
7280  // Unlike classic C/C++ enums, for C++11, C# & Java enum
7281  // values are only visible inside the enum scope, so we must create
7282  // them here and only add them to the enum
7283  //printf("md->qualifiedName()=%s e->name=%s tagInfo=%p name=%s\n",
7284  // qPrint(md->qualifiedName()),qPrint(e->name),e->tagInfo,qPrint(e->name));
7285  QCString qualifiedName = substitute(root->name,"::",".");
7286  if (!scope.isEmpty() && root->tagInfo())
7287  {
7288  qualifiedName=substitute(scope,"::",".")+"."+qualifiedName;
7289  }
7290  if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7291  qualifiedName // enum value scope matches that of the enum
7292  )
7293  {
7294  QCString fileName = e->fileName;
7295  if (fileName.isEmpty() && e->tagInfo())
7296  {
7297  fileName = e->tagInfo()->tagName;
7298  }
7299  std::unique_ptr<MemberDefMutable> fmd { createMemberDef(
7300  fileName,e->startLine,e->startColumn,
7301  e->type,e->name,e->args,QCString(),
7302  e->protection, Normal,e->stat,Member,
7304  const NamespaceDef *mnd = md->getNamespaceDef();
7305  if (md->getClassDef())
7306  fmd->setMemberClass(md->getClassDef());
7307  else if (mnd && (mnd->isLinkable() || mnd->isAnonymous()))
7308  fmd->setNamespace(mnd);
7309  else if (md->getFileDef())
7310  fmd->setFileDef(md->getFileDef());
7311  fmd->setOuterScope(md->getOuterScope());
7312  fmd->setTagInfo(e->tagInfo());
7313  fmd->setLanguage(e->lang);
7314  fmd->setId(e->id);
7315  fmd->setDocumentation(e->doc,e->docFile,e->docLine);
7318  std::string init = e->initializer.str();
7319  fmd->setInitializer(init.c_str());
7320  fmd->setMaxInitLines(e->initLines);
7321  fmd->setMemberGroupId(e->mGrpId);
7323  fmd->setRefItems(e->sli);
7324  fmd->setAnchor();
7325  md->insertEnumField(fmd.get());
7326  fmd->setEnumScope(md,TRUE);
7327  extraMembers.push_back(EnumValueInfo(e->name,fmd));
7328  }
7329  }
7330  else
7331  {
7332  //printf("e->name=%s isRelated=%d\n",qPrint(e->name),isRelated);
7333  MemberName *fmn=0;
7334  MemberNameLinkedMap *emnsd = isRelated ? Doxygen::functionNameLinkedMap : mnsd;
7335  if (!e->name.isEmpty() && (fmn=emnsd->find(e->name)))
7336  // get list of members with the same name as the field
7337  {
7338  for (const auto &ifmd : *fmn)
7339  {
7340  MemberDefMutable *fmd = toMemberDefMutable(ifmd.get());
7341  if (fmd && fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7342  {
7343  //printf("found enum value with same name %s in scope %s\n",
7344  // qPrint(fmd->name()),qPrint(fmd->getOuterScope()->name()));
7345  if (nd && !nd->isAnonymous())
7346  {
7347  const NamespaceDef *fnd=fmd->getNamespaceDef();
7348  if (fnd==nd) // enum value is inside a namespace
7349  {
7350  md->insertEnumField(fmd);
7351  fmd->setEnumScope(md);
7352  }
7353  }
7354  else if (isGlobal)
7355  {
7356  const FileDef *ffd=fmd->getFileDef();
7357  if (ffd==fd) // enum value has file scope
7358  {
7359  md->insertEnumField(fmd);
7360  fmd->setEnumScope(md);
7361  }
7362  }
7363  else if (isRelated && cd) // reparent enum value to
7364  // match the enum's scope
7365  {
7366  md->insertEnumField(fmd); // add field def to list
7367  fmd->setEnumScope(md); // cross ref with enum name
7368  fmd->setEnumClassScope(cd); // cross ref with enum name
7369  fmd->setOuterScope(cd);
7370  fmd->makeRelated();
7371  cd->insertMember(fmd);
7372  }
7373  else
7374  {
7375  const ClassDef *fcd=fmd->getClassDef();
7376  if (fcd==cd) // enum value is inside a class
7377  {
7378  //printf("Inserting enum field %s in enum scope %s\n",
7379  // qPrint(fmd->name()),qPrint(md->name()));
7380  md->insertEnumField(fmd); // add field def to list
7381  fmd->setEnumScope(md); // cross ref with enum name
7382  }
7383  }
7384  }
7385  }
7386  }
7387  }
7388  }
7389  }
7390  }
7391  // move the newly added members into mn
7392  for (auto &e : extraMembers)
7393  {
7394  MemberName *emn=mnsd->add(e.name);
7395  emn->push_back(std::move(e.member));
7396  }
7397  }
7398  }
7399  }
7400  else
7401  {
7402  for (const auto &e : root->children()) addEnumValuesToEnums(e.get());
7403  }
7404 }
7405 
7406 //----------------------------------------------------------------------
7407 
7408 static void addEnumDocs(const Entry *root,MemberDefMutable *md)
7409 {
7410  // documentation outside a compound overrides the documentation inside it
7411  {
7412  md->setDocumentation(root->doc,root->docFile,root->docLine);
7413  md->setDocsForDefinition(!root->proto);
7414  }
7415 
7416  // brief descriptions inside a compound override the documentation
7417  // outside it
7418  {
7419  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7420  }
7421 
7422  if (md->inbodyDocumentation().isEmpty() || !root->parent()->name.isEmpty())
7423  {
7424  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7425  }
7426 
7427  if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7428  {
7429  md->setMemberGroupId(root->mGrpId);
7430  }
7431 
7432  md->addSectionsToDefinition(root->anchors);
7433  md->setRefItems(root->sli);
7434 
7435  const GroupDef *gd=md->getGroupDef();
7436  if (gd==0 && !root->groups.empty()) // member not grouped but out-of-line documentation is
7437  {
7438  addMemberToGroups(root,md);
7439  }
7440 }
7441 
7442 
7443 //----------------------------------------------------------------------
7444 // find the documentation blocks for the enumerations
7445 
7446 static void findEnumDocumentation(const Entry *root)
7447 {
7448  if (root->section==Entry::ENUMDOC_SEC
7449  && !root->name.isEmpty()
7450  && root->name.at(0)!='@' // skip anonymous enums
7451  )
7452  {
7453  int i;
7454  QCString name;
7455  QCString scope;
7456  if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7457  {
7458  name=root->name.right(root->name.length()-i-2); // extract name
7459  scope=root->name.left(i); // extract scope
7460  //printf("Scope='%s' Name='%s'\n",qPrint(scope),qPrint(name));
7461  }
7462  else // just the name
7463  {
7464  name=root->name;
7465  }
7466  if (( root->parent()->section & Entry::SCOPE_MASK )
7467  && !root->parent()->name.isEmpty()
7468  ) // found enum docs inside a compound
7469  {
7470  if (!scope.isEmpty()) scope.prepend("::");
7471  scope.prepend(root->parent()->name);
7472  }
7473  const ClassDef *cd = getClass(scope);
7474  const NamespaceDef *nd=Doxygen::namespaceLinkedMap->find(scope);
7475  const FileDef *fd = root->fileDef();
7476  Debug::print(Debug::FindMembers,0,"1. Found docs for enum with name '%s' and scope '%s' in context %s cd=%s, nd=%s fd=%s\n",
7477  qPrint(name),qPrint(scope),qPrint(root->parent()->name),
7478  cd?qPrint(cd->name()):"<none>",
7479  nd?qPrint(nd->name()):"<none>",
7480  fd?qPrint(fd->name()):"<none>");
7481 
7482  if (!name.isEmpty())
7483  {
7484  bool found=FALSE;
7485  MemberName *mn;
7486  if (cd)
7487  {
7488  mn = Doxygen::memberNameLinkedMap->find(name);
7489  }
7490  else
7491  {
7493  }
7494  if (mn)
7495  {
7496  for (const auto &imd : *mn)
7497  {
7498  MemberDefMutable *md = toMemberDefMutable(imd.get());
7499  if (md && md->isEnumerate())
7500  {
7501  const ClassDef *mcd = md->getClassDef();
7502  const NamespaceDef *mnd = md->getNamespaceDef();
7503  const FileDef *mfd = md->getFileDef();
7504  if (cd && mcd==cd)
7505  {
7506  Debug::print(Debug::FindMembers,0,"2. Match found for class scope\n");
7507  addEnumDocs(root,md);
7508  found=TRUE;
7509  break;
7510  }
7511  else if (cd==0 && mcd==0 && nd!=0 && mnd==nd)
7512  {
7513  Debug::print(Debug::FindMembers,0,"2. Match found for namespace scope\n");
7514  addEnumDocs(root,md);
7515  found=TRUE;
7516  break;
7517  }
7518  else if (cd==0 && nd==0 && mcd==0 && mnd==0 && fd==mfd)
7519  {
7520  Debug::print(Debug::FindMembers,0,"2. Match found for global scope\n");
7521  addEnumDocs(root,md);
7522  found=TRUE;
7523  break;
7524  }
7525  }
7526  }
7527  }
7528  if (!found)
7529  {
7530  warn(root->fileName,root->startLine,
7531  "Documentation for undefined enum '%s' found.",
7532  qPrint(name)
7533  );
7534  }
7535  }
7536  }
7537  for (const auto &e : root->children()) findEnumDocumentation(e.get());
7538 }
7539 
7540 // search for each enum (member or function) in mnl if it has documented
7541 // enum values.
7542 static void findDEV(const MemberNameLinkedMap &mnsd)
7543 {
7544  // for each member name
7545  for (const auto &mn : mnsd)
7546  {
7547  // for each member definition
7548  for (const auto &imd : *mn)
7549  {
7550  MemberDefMutable *md = toMemberDefMutable(imd.get());
7551  if (md && md->isEnumerate()) // member is an enum
7552  {
7553  int documentedEnumValues=0;
7554  // for each enum value
7555  for (const auto &fmd : md->enumFieldList())
7556  {
7557  if (fmd->isLinkableInProject()) documentedEnumValues++;
7558  }
7559  // at least one enum value is documented
7560  if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7561  }
7562  }
7563  }
7564 }
7565 
7566 // search for each enum (member or function) if it has documented enum
7567 // values.
7569 {
7572 }
7573 
7574 //----------------------------------------------------------------------
7575 
7576 static void addMembersToIndex()
7577 {
7578  // for each class member name
7579  for (const auto &mn : *Doxygen::memberNameLinkedMap)
7580  {
7581  // for each member definition
7582  for (const auto &md : *mn)
7583  {
7584  addClassMemberNameToIndex(md.get());
7585  }
7586  }
7587  // for each file/namespace function name
7588  for (const auto &mn : *Doxygen::functionNameLinkedMap)
7589  {
7590  // for each member definition
7591  for (const auto &md : *mn)
7592  {
7593  if (md->getNamespaceDef())
7594  {
7596  }
7597  else
7598  {
7599  addFileMemberNameToIndex(md.get());
7600  }
7601  }
7602  }
7604 }
7605 
7606 //----------------------------------------------------------------------
7607 
7608 static void addToIndices()
7609 {
7610  for (const auto &cd : *Doxygen::classLinkedMap)
7611  {
7612  if (cd->isLinkableInProject())
7613  {
7614  Doxygen::indexList->addIndexItem(cd.get(),0);
7616  {
7619  }
7620  }
7621  }
7622 
7623  for (const auto &cd : *Doxygen::conceptLinkedMap)
7624  {
7625  if (cd->isLinkableInProject())
7626  {
7627  Doxygen::indexList->addIndexItem(cd.get(),0);
7629  {
7632  }
7633  }
7634  }
7635 
7636  for (const auto &nd : *Doxygen::namespaceLinkedMap)
7637  {
7638  if (nd->isLinkableInProject())
7639  {
7640  Doxygen::indexList->addIndexItem(nd.get(),0);
7642  {
7645  }
7646  }
7647  }
7648 
7649  for (const auto &fn : *Doxygen::inputNameLinkedMap)
7650  {
7651  for (const auto &fd : *fn)
7652  {
7654  {
7657  }
7658  }
7659  }
7660 
7661  for (const auto &gd : *Doxygen::groupLinkedMap)
7662  {
7663  if (gd->isLinkableInProject())
7664  {
7665  Doxygen::indexList->addIndexItem(gd.get(),0,QCString(),gd->groupTitle());
7667  {
7669  std::string title = gd->groupTitle().str();
7670  static const reg::Ex re(R"(\a[\w-]*)");
7671  reg::Iterator it(title,re);
7673  for (; it!=end ; ++it)
7674  {
7675  const auto &match = *it;
7676  std::string matchStr = match.str();
7677  Doxygen::searchIndex->addWord(matchStr.c_str(),TRUE);
7678  }
7679  }
7680  }
7681  }
7682 
7683  for (const auto &pd : *Doxygen::pageLinkedMap)
7684  {
7685  if (pd->isLinkableInProject())
7686  {
7687  Doxygen::indexList->addIndexItem(pd.get(),0,QCString(),filterTitle(pd->title().str()));
7688  }
7689  }
7690 
7691  auto addMemberToSearchIndex = [](const MemberDef *md)
7692  {
7694  {
7696  QCString ln=md->localName();
7697  QCString qn=md->qualifiedName();
7699  if (ln!=qn)
7700  {
7702  if (md->getClassDef())
7703  {
7705  }
7706  if (md->getNamespaceDef())
7707  {
7709  }
7710  }
7711  }
7712  };
7713 
7714  auto getScope = [](const MemberDef *md)
7715  {
7716  const Definition *scope = 0;
7717  if (md->getGroupDef()) scope = md->getGroupDef();
7718  else if (md->getClassDef()) scope = md->getClassDef();
7719  else if (md->getNamespaceDef()) scope = md->getNamespaceDef();
7720  else if (md->getFileDef()) scope = md->getFileDef();
7721  return scope;
7722  };
7723 
7724  auto addMemberToIndices = [addMemberToSearchIndex,getScope](const MemberDef *md)
7725  {
7726  if (md->isLinkableInProject())
7727  {
7728  if (!(md->isEnumerate() && md->isAnonymous()))
7729  {
7730  Doxygen::indexList->addIndexItem(getScope(md),md);
7732  }
7733  if (md->isEnumerate())
7734  {
7735  for (const auto &fmd : md->enumFieldList())
7736  {
7737  Doxygen::indexList->addIndexItem(getScope(fmd),fmd);
7739  }
7740  }
7741  }
7742  };
7743 
7744  // for each class member name
7745  for (const auto &mn : *Doxygen::memberNameLinkedMap)
7746  {
7747  // for each member definition
7748  for (const auto &md : *mn)
7749  {
7750  addMemberToIndices(md.get());
7751  }
7752  }
7753  // for each file/namespace function name
7754  for (const auto &mn : *Doxygen::functionNameLinkedMap)
7755  {
7756  // for each member definition
7757  for (const auto &md : *mn)
7758  {
7759  addMemberToIndices(md.get());
7760  }
7761  }
7762 }
7763 
7764 //----------------------------------------------------------------------
7765 
7767 {
7768  // for each member name
7769  for (const auto &mn : *Doxygen::memberNameLinkedMap)
7770  {
7771  // for each member definition
7772  for (const auto &imd : *mn)
7773  {
7774  MemberDefMutable *md = toMemberDefMutable(imd.get());
7775  if (md)
7776  {
7778  }
7779  }
7780  }
7781  // for each member name
7782  for (const auto &mn : *Doxygen::functionNameLinkedMap)
7783  {
7784  // for each member definition
7785  for (const auto &imd : *mn)
7786  {
7787  MemberDefMutable *md = toMemberDefMutable(imd.get());
7788  if (md)
7789  {
7791  }
7792  }
7793  }
7794 }
7795 
7796 
7797 //----------------------------------------------------------------------
7798 // computes the relation between all members. For each member 'm'
7799 // the members that override the implementation of 'm' are searched and
7800 // the member that 'm' overrides is searched.
7801 
7803 {
7804  for (const auto &mn : *Doxygen::memberNameLinkedMap)
7805  {
7806  // for each member with a specific name
7807  for (const auto &imd : *mn)
7808  {
7809  MemberDefMutable *md = toMemberDefMutable(imd.get());
7810  if (md)
7811  {
7812  // for each other member with the same name
7813  for ( const auto &ibmd : *mn)
7814  {
7815  MemberDefMutable *bmd = toMemberDefMutable(ibmd.get());
7816  if (bmd && md!=bmd)
7817  {
7818  const ClassDef *mcd = md->getClassDef();
7819  if (mcd && !mcd->baseClasses().empty())
7820  {
7821  const ClassDef *bmcd = bmd->getClassDef();
7822  //printf("Check relation between '%s'::'%s' (%p) and '%s'::'%s' (%p)\n",
7823  // qPrint(mcd->name()),qPrint(md->name()),md.get(),
7824  // qPrint(bmcd->name()),qPrint(bmd->name()),bmd.get()
7825  // );
7826  if (bmcd && mcd && bmcd!=mcd &&
7827  (bmd->virtualness()!=Normal ||
7830  ) &&
7831  md->isFunction() &&
7832  mcd->isLinkable() &&
7833  bmcd->isLinkable() &&
7834  mcd->isBaseClass(bmcd,TRUE))
7835  {
7836  //printf(" derived scope\n");
7837  const ArgumentList &bmdAl = bmd->argumentList();
7838  const ArgumentList &mdAl = md->argumentList();
7839  //printf(" Base argList='%s'\n Super argList='%s'\n",
7840  // qPrint(argListToString(bmdAl)),
7841  // qPrint(argListToString(mdAl))
7842  // );
7843  if (
7844  bmd->getLanguage()==SrcLangExt_Python ||
7845  matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),&bmdAl,
7846  md->getOuterScope(), md->getFileDef(), &mdAl,
7847  TRUE
7848  )
7849  )
7850  {
7851  //printf("match!\n");
7852  const MemberDef *rmd = md->reimplements();
7853  if (rmd==0 || minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef()))
7854  {
7855  //printf("setting (new) reimplements member\n");
7856  md->setReimplements(bmd);
7857  }
7858  //printf("%s: add reimplementedBy member %s\n",qPrint(bmcd->name()),qPrint(mcd->name()));
7859  bmd->insertReimplementedBy(md);
7860  }
7861  else
7862  {
7863  //printf("no match!\n");
7864  }
7865  }
7866  }
7867  }
7868  }
7869  }
7870  }
7871  }
7872 }
7873 
7874 //----------------------------------------------------------------------------
7875 
7877 {
7878  // for each class
7879  for (const auto &cd : *Doxygen::classLinkedMap)
7880  {
7881  // that is a template
7882  for (const auto &ti : cd->getTemplateInstances())
7883  {
7884  ClassDefMutable *tcdm = toClassDefMutable(ti.classDef);
7885  if (tcdm)
7886  {
7887  tcdm->addMembersToTemplateInstance(cd.get(),cd->templateArguments(),ti.templSpec);
7888  }
7889  }
7890  }
7891 }
7892 
7893 //----------------------------------------------------------------------------
7894 
7895 static void mergeCategories()
7896 {
7897  // merge members of categories into the class they extend
7898  for (const auto &cd : *Doxygen::classLinkedMap)
7899  {
7900  int i=cd->name().find('(');
7901  if (i!=-1) // it is an Objective-C category
7902  {
7903  QCString baseName=cd->name().left(i);
7904  ClassDefMutable *baseClass=toClassDefMutable(Doxygen::classLinkedMap->find(baseName));
7905  if (baseClass)
7906  {
7907  //printf("*** merging members of category %s into %s\n",
7908  // qPrint(cd->name()),qPrint(baseClass->name()));
7909  baseClass->mergeCategory(cd.get());
7910  }
7911  }
7912  }
7913 }
7914 
7915 // builds the list of all members for each class
7916 
7918 {
7919  // merge the member list of base classes into the inherited classes.
7920  for (const auto &cd : *Doxygen::classLinkedMap)
7921  {
7922  if (// !cd->isReference() && // not an external class
7923  cd->subClasses().empty() && // is a root of the hierarchy
7924  !cd->baseClasses().empty()) // and has at least one base class
7925  {
7926  ClassDefMutable *cdm = toClassDefMutable(cd.get());
7927  if (cdm)
7928  {
7929  //printf("*** merging members for %s\n",qPrint(cd->name()));
7930  cdm->mergeMembers();
7931  }
7932  }
7933  }
7934  // now sort the member list of all members for all classes.
7935  for (const auto &cd : *Doxygen::classLinkedMap)
7936  {
7937  ClassDefMutable *cdm = toClassDefMutable(cd.get());
7938  if (cdm)
7939  {
7940  cdm->sortAllMembersList();
7941  }
7942  }
7943 }
7944 
7945 //----------------------------------------------------------------------------
7946 
7947 static void generateFileSources()
7948 {
7949  if (!Doxygen::inputNameLinkedMap->empty())
7950  {
7951 #if USE_LIBCLANG
7953  {
7954  StringUnorderedSet processedFiles;
7955 
7956  // create a dictionary with files to process
7957  StringUnorderedSet filesToProcess;
7958 
7959  for (const auto &fn : *Doxygen::inputNameLinkedMap)
7960  {
7961  for (const auto &fd : *fn)
7962  {
7963  filesToProcess.insert(fd->absFilePath().str());
7964  }
7965  }
7966  // process source files (and their include dependencies)
7967  for (const auto &fn : *Doxygen::inputNameLinkedMap)
7968  {
7969  for (const auto &fd : *fn)
7970  {
7971  if (fd->isSource() && !fd->isReference() &&
7972  ((fd->generateSourceFile() && !g_useOutputTemplate) ||
7974  )
7975  )
7976  {
7977  auto clangParser = ClangParser::instance()->createTUParser(fd.get());
7978  if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7979  {
7980  msg("Generating code for file %s...\n",qPrint(fd->docName()));
7981  clangParser->parse();
7983  fd->writeSourceBody(*g_outputList,clangParser.get());
7985  }
7986  else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7987  // we needed to parse the sources even if we do not show them
7988  {
7989  msg("Parsing code for file %s...\n",qPrint(fd->docName()));
7990  clangParser->parse();
7991  fd->parseSource(clangParser.get());
7992  }
7993 
7994  for (auto incFile : clangParser->filesInSameTU())
7995  {
7996  if (filesToProcess.find(incFile)!=filesToProcess.end() && // part of input
7997  fd->absFilePath()!=QCString(incFile) && // not same file
7998  processedFiles.find(incFile)==processedFiles.end()) // not yet marked as processed
7999  {
8000  StringVector moreFiles;
8001  bool ambig;
8002  FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile.c_str(),ambig);
8003  if (ifd && !ifd->isReference())
8004  {
8005  if (ifd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
8006  {
8007  msg(" Generating code for file %s...\n",qPrint(ifd->docName()));
8009  ifd->writeSourceBody(*g_outputList,clangParser.get());
8011  }
8012  else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
8013  // we needed to parse the sources even if we do not show them
8014  {
8015  msg(" Parsing code for file %s...\n",qPrint(ifd->docName()));
8016  ifd->parseSource(clangParser.get());
8017  }
8018  processedFiles.insert(incFile);
8019  }
8020  }
8021  }
8022  processedFiles.insert(fd->absFilePath().str());
8023  }
8024  }
8025  }
8026  // process remaining files
8027  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8028  {
8029  for (const auto &fd : *fn)
8030  {
8031  if (processedFiles.find(fd->absFilePath().str())==processedFiles.end()) // not yet processed
8032  {
8033  if (fd->generateSourceFile() && !Htags::useHtags && !g_useOutputTemplate) // sources need to be shown in the output
8034  {
8035  auto clangParser = ClangParser::instance()->createTUParser(fd.get());
8036  msg("Generating code for file %s...\n",qPrint(fd->docName()));
8037  clangParser->parse();
8039  fd->writeSourceBody(*g_outputList,clangParser.get());
8041  }
8042  else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
8043  // we needed to parse the sources even if we do not show them
8044  {
8045  auto clangParser = ClangParser::instance()->createTUParser(fd.get());
8046  msg("Parsing code for file %s...\n",qPrint(fd->docName()));
8047  clangParser->parse();
8049  fd->writeSourceBody(*g_outputList,clangParser.get());
8051  }
8052  }
8053  }
8054  }
8055  }
8056  else
8057 #endif
8058  {
8059  std::size_t numThreads = static_cast<std::size_t>(Config_getInt(NUM_PROC_THREADS));
8060  if (numThreads==0)
8061  {
8062  numThreads = std::thread::hardware_concurrency();
8063  }
8064  if (numThreads>1)
8065  {
8066  msg("Generating code files using %zu threads.\n",numThreads);
8067  struct SourceContext
8068  {
8069  SourceContext(FileDef *fd_,bool gen_,OutputList ol_)
8070  : fd(fd_), generateSourceFile(gen_), ol(ol_) {}
8071  FileDef *fd;
8072  bool generateSourceFile;
8073  OutputList ol;
8074  };
8075  ThreadPool threadPool(numThreads);
8076  std::vector< std::future< std::shared_ptr<SourceContext> > > results;
8077  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8078  {
8079  for (const auto &fd : *fn)
8080  {
8081  bool generateSourceFile = fd->generateSourceFile() && !Htags::useHtags && !g_useOutputTemplate;
8082  auto ctx = std::make_shared<SourceContext>(fd.get(),generateSourceFile,*g_outputList);
8083  if (generateSourceFile)
8084  {
8085  fd->writeSourceHeader(ctx->ol);
8086  }
8087  auto processFile = [ctx]() {
8088  if (ctx->generateSourceFile)
8089  {
8090  msg("Generating code for file %s...\n",qPrint(ctx->fd->docName()));
8091  }
8092  else
8093  {
8094  msg("Parsing code for file %s...\n",qPrint(ctx->fd->docName()));
8095  }
8096  StringVector filesInSameTu;
8097  ctx->fd->getAllIncludeFilesRecursively(filesInSameTu);
8098  if (ctx->generateSourceFile) // sources need to be shown in the output
8099  {
8100  ctx->fd->writeSourceBody(ctx->ol,nullptr);
8101  }
8102  else if (!ctx->fd->isReference() && Doxygen::parseSourcesNeeded)
8103  // we needed to parse the sources even if we do not show them
8104  {
8105  ctx->fd->parseSource(nullptr);
8106  }
8107  return ctx;
8108  };
8109  results.emplace_back(threadPool.queue(processFile));
8110  }
8111  }
8112  for (auto &f : results)
8113  {
8114  auto ctx = f.get();
8115  if (ctx->generateSourceFile)
8116  {
8117  ctx->fd->writeSourceFooter(ctx->ol);
8118  }
8119  }
8120  }
8121  else // single threaded version
8122  {
8123  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8124  {
8125  for (const auto &fd : *fn)
8126  {
8127  StringVector filesInSameTu;
8128  fd->getAllIncludeFilesRecursively(filesInSameTu);
8129  if (fd->generateSourceFile() && !Htags::useHtags && !g_useOutputTemplate) // sources need to be shown in the output
8130  {
8131  msg("Generating code for file %s...\n",qPrint(fd->docName()));
8133  fd->writeSourceBody(*g_outputList,nullptr);
8135  }
8136  else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
8137  // we needed to parse the sources even if we do not show them
8138  {
8139  msg("Parsing code for file %s...\n",qPrint(fd->docName()));
8140  fd->parseSource(nullptr);
8141  }
8142  }
8143  }
8144  }
8145  }
8146  }
8147 }
8148 
8149 //----------------------------------------------------------------------------
8150 
8151 static void generateFileDocs()
8152 {
8153  if (documentedFiles==0) return;
8154 
8155  if (!Doxygen::inputNameLinkedMap->empty())
8156  {
8157  std::size_t numThreads = static_cast<std::size_t>(Config_getInt(NUM_PROC_THREADS));
8158  if (numThreads==0)
8159  {
8160  numThreads = std::thread::hardware_concurrency();
8161  }
8162  if (numThreads>1) // multi threaded processing
8163  {
8164  struct DocContext
8165  {
8166  DocContext(FileDef *fd_,OutputList ol_)
8167  : fd(fd_), ol(ol_) {}
8168  FileDef *fd;
8169  OutputList ol;
8170  };
8171  ThreadPool threadPool(numThreads);
8172  std::vector< std::future< std::shared_ptr<DocContext> > > results;
8173  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8174  {
8175  for (const auto &fd : *fn)
8176  {
8177  bool doc = fd->isLinkableInProject();
8178  if (doc)
8179  {
8180  auto ctx = std::make_shared<DocContext>(fd.get(),*g_outputList);
8181  auto processFile = [ctx]() {
8182  msg("Generating docs for file %s...\n",qPrint(ctx->fd->docName()));
8183  ctx->fd->writeDocumentation(ctx->ol);
8184  return ctx;
8185  };
8186  results.emplace_back(threadPool.queue(processFile));
8187  }
8188  }
8189  }
8190  for (auto &f : results)
8191  {
8192  auto ctx = f.get();
8193  }
8194  }
8195  else // single threaded processing
8196  {
8197  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8198  {
8199  for (const auto &fd : *fn)
8200  {
8201  bool doc = fd->isLinkableInProject();
8202  if (doc)
8203  {
8204  msg("Generating docs for file %s...\n",qPrint(fd->docName()));
8206  }
8207  }
8208  }
8209  }
8210  }
8211 }
8212 
8213 //----------------------------------------------------------------------------
8214 
8215 static void addSourceReferences()
8216 {
8217  // add source references for class definitions
8218  for (const auto &cd : *Doxygen::classLinkedMap)
8219  {
8220  const FileDef *fd=cd->getBodyDef();
8221  if (fd && cd->isLinkableInProject() && cd->getStartDefLine()!=-1)
8222  {
8223  const_cast<FileDef*>(fd)->addSourceRef(cd->getStartDefLine(),cd.get(),0);
8224  }
8225  }
8226  // add source references for concept definitions
8227  for (const auto &cd : *Doxygen::conceptLinkedMap)
8228  {
8229  const FileDef *fd=cd->getBodyDef();
8230  if (fd && cd->isLinkableInProject() && cd->getStartDefLine()!=-1)
8231  {
8232  const_cast<FileDef*>(fd)->addSourceRef(cd->getStartDefLine(),cd.get(),0);
8233  }
8234  }
8235  // add source references for namespace definitions
8236  for (const auto &nd : *Doxygen::namespaceLinkedMap)
8237  {
8238  const FileDef *fd=nd->getBodyDef();
8239  if (fd && nd->isLinkableInProject() && nd->getStartDefLine()!=-1)
8240  {
8241  const_cast<FileDef*>(fd)->addSourceRef(nd->getStartDefLine(),nd.get(),0);
8242  }
8243  }
8244 
8245  // add source references for member names
8246  for (const auto &mn : *Doxygen::memberNameLinkedMap)
8247  {
8248  for (const auto &md : *mn)
8249  {
8250  //printf("class member %s: def=%s body=%d link?=%d\n",
8251  // qPrint(md->name()),
8252  // md->getBodyDef()?qPrint(md->getBodyDef()->name()):"<none>",
8253  // md->getStartBodyLine(),md->isLinkableInProject());
8254  const FileDef *fd=md->getBodyDef();
8255  if (fd &&
8256  md->getStartDefLine()!=-1 &&
8257  md->isLinkableInProject() &&
8259  )
8260  {
8261  //printf("Found member '%s' in file '%s' at line '%d' def=%s\n",
8262  // qPrint(md->name()),qPrint(fd->name()),md->getStartBodyLine(),qPrint(md->getOuterScope()->name()));
8263  const_cast<FileDef*>(fd)->addSourceRef(md->getStartDefLine(),md->getOuterScope(),md.get());
8264  }
8265  }
8266  }
8267  for (const auto &mn : *Doxygen::functionNameLinkedMap)
8268  {
8269  for (const auto &md : *mn)
8270  {
8271  const FileDef *fd=md->getBodyDef();
8272  //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
8273  // qPrint(md->name()),
8274  // md->getStartBodyLine(),md->getEndBodyLine(),fd,
8275  // md->isLinkableInProject(),
8276  // Doxygen::parseSourcesNeeded);
8277  if (fd &&
8278  md->getStartDefLine()!=-1 &&
8279  md->isLinkableInProject() &&
8281  )
8282  {
8283  //printf("Found member '%s' in file '%s' at line '%d' def=%s\n",
8284  // qPrint(md->name()),qPrint(fd->name()),md->getStartBodyLine(),qPrint(md->getOuterScope()->name()));
8285  const_cast<FileDef*>(fd)->addSourceRef(md->getStartDefLine(),md->getOuterScope(),md.get());
8286  }
8287  }
8288  }
8289 }
8290 
8291 //----------------------------------------------------------------------------
8292 
8293 // add the macro definitions found during preprocessing as file members
8294 static void buildDefineList()
8295 {
8296  for (const auto &s : g_inputFiles)
8297  {
8298  auto it = Doxygen::macroDefinitions.find(s);
8299  if (it!=Doxygen::macroDefinitions.end())
8300  {
8301  for (const auto &def : it->second)
8302  {
8303  std::unique_ptr<MemberDefMutable> md { createMemberDef(
8304  def.fileName,def.lineNr,def.columnNr,
8305  "#define",def.name,def.args,QCString(),
8307  ArgumentList(),ArgumentList(),"") };
8308 
8309  if (!def.args.isEmpty())
8310  {
8312  }
8313  md->setInitializer(def.definition);
8314  md->setFileDef(def.fileDef);
8315  md->setDefinition("#define "+def.name);
8316 
8318  if (def.fileDef)
8319  {
8320  def.fileDef->insertMember(md.get());
8321  }
8322  mn->push_back(std::move(md));
8323  }
8324  }
8325  }
8326 }
8327 
8328 //----------------------------------------------------------------------------
8329 
8330 static void sortMemberLists()
8331 {
8332  // sort class member lists
8333  for (const auto &cd : *Doxygen::classLinkedMap)
8334  {
8335  ClassDefMutable *cdm = toClassDefMutable(cd.get());
8336  if (cdm)
8337  {
8338  cdm->sortMemberLists();
8339  }
8340  }
8341 
8342  // sort namespace member lists
8343  for (const auto &nd : *Doxygen::namespaceLinkedMap)
8344  {
8345  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
8346  if (ndm)
8347  {
8348  ndm->sortMemberLists();
8349  }
8350  }
8351 
8352  // sort file member lists
8353  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8354  {
8355  for (const auto &fd : *fn)
8356  {
8357  fd->sortMemberLists();
8358  }
8359  }
8360 
8361  // sort group member lists
8362  for (const auto &gd : *Doxygen::groupLinkedMap)
8363  {
8364  gd->sortMemberLists();
8365  }
8366 }
8367 
8368 //----------------------------------------------------------------------------
8369 
8370 static bool isSymbolHidden(const Definition *d)
8371 {
8372  bool hidden = d->isHidden();
8373  const Definition *parent = d->getOuterScope();
8374  return parent ? hidden || isSymbolHidden(parent) : hidden;
8375 }
8376 
8377 static void computeTooltipTexts()
8378 {
8379  for (const auto &kv : *Doxygen::symbolMap)
8380  {
8381  DefinitionMutable *dm = toDefinitionMutable(kv.second);
8382  if (dm && !isSymbolHidden(toDefinition(dm)) && toDefinition(dm)->isLinkableInProject())
8383  {
8384  dm->computeTooltip();
8385  }
8386  }
8387 }
8388 
8389 //----------------------------------------------------------------------------
8390 
8392 {
8393  for (const auto &cd : *Doxygen::classLinkedMap)
8394  {
8395  ClassDefMutable *cdm = toClassDefMutable(cd.get());
8396  if (cdm)
8397  {
8398  cdm->setAnonymousEnumType();
8399  }
8400  }
8401 }
8402 
8403 //----------------------------------------------------------------------------
8404 
8405 static void countMembers()
8406 {
8407  for (const auto &cd : *Doxygen::classLinkedMap)
8408  {
8409  ClassDefMutable *cdm = toClassDefMutable(cd.get());
8410  if (cdm)
8411  {
8412  cdm->countMembers();
8413  }
8414  }
8415 
8416  for (const auto &nd : *Doxygen::namespaceLinkedMap)
8417  {
8418  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
8419  if (ndm)
8420  {
8421  ndm->countMembers();
8422  }
8423  }
8424 
8425  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8426  {
8427  for (const auto &fd : *fn)
8428  {
8429  fd->countMembers();
8430  }
8431  }
8432 
8433  for (const auto &gd : *Doxygen::groupLinkedMap)
8434  {
8435  gd->countMembers();
8436  }
8437 }
8438 
8439 
8440 //----------------------------------------------------------------------------
8441 // generate the documentation of all classes
8442 
8443 static void generateClassList(const ClassLinkedMap &classList)
8444 {
8445  std::size_t numThreads = static_cast<std::size_t>(Config_getInt(NUM_PROC_THREADS));
8446  if (numThreads==0)
8447  {
8448  numThreads = std::thread::hardware_concurrency();
8449  }
8450  if (numThreads>1) // multi threaded processing
8451  {
8452  struct DocContext
8453  {
8454  DocContext(ClassDefMutable *cd_,OutputList ol_)
8455  : cd(cd_), ol(ol_) {}
8456  ClassDefMutable *cd;
8457  OutputList ol;
8458  };
8459  ThreadPool threadPool(numThreads);
8460  std::vector< std::future< std::shared_ptr<DocContext> > > results;
8461  for (const auto &cdi : classList)
8462  {
8463  ClassDefMutable *cd=toClassDefMutable(cdi.get());
8464 
8465  //printf("cd=%s getOuterScope=%p global=%p\n",qPrint(cd->name()),cd->getOuterScope(),Doxygen::globalScope);
8466  if (cd &&
8467  (cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8468  cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8469  ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8470  )
8471  {
8472  auto ctx = std::make_shared<DocContext>(cd,*g_outputList);
8473  auto processFile = [ctx]()
8474  {
8475  msg("Generating docs for compound %s...\n",qPrint(ctx->cd->name()));
8476 
8477  // skip external references, anonymous compounds and
8478  // template instances
8479  if ( ctx->cd->isLinkableInProject() && ctx->cd->templateMaster()==0)
8480  {
8481  ctx->cd->writeDocumentation(ctx->ol);
8482  ctx->cd->writeMemberList(ctx->ol);
8483  }
8484 
8485  // even for undocumented classes, the inner classes can be documented.
8486  ctx->cd->writeDocumentationForInnerClasses(ctx->ol);
8487  return ctx;
8488  };
8489  results.emplace_back(threadPool.queue(processFile));
8490  }
8491  }
8492  for (auto &f : results)
8493  {
8494  auto ctx = f.get();
8495  }
8496  }
8497  else // single threaded processing
8498  {
8499  for (const auto &cdi : classList)
8500  {
8501  ClassDefMutable *cd=toClassDefMutable(cdi.get());
8502 
8503  //printf("cd=%s getOuterScope=%p global=%p\n",qPrint(cd->name()),cd->getOuterScope(),Doxygen::globalScope);
8504  if (cd &&
8505  (cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8506  cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8507  ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8508  )
8509  {
8510  // skip external references, anonymous compounds and
8511  // template instances
8512  if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8513  {
8514  msg("Generating docs for compound %s...\n",qPrint(cd->name()));
8515 
8518  }
8519  // even for undocumented classes, the inner classes can be documented.
8521  }
8522  }
8523  }
8524 }
8525 
8526 static void generateClassDocs()
8527 {
8530 }
8531 
8532 //----------------------------------------------------------------------------
8533 
8534 static void generateConceptDocs()
8535 {
8536  for (const auto &cdi : *Doxygen::conceptLinkedMap)
8537  {
8538  ConceptDefMutable *cd=toConceptDefMutable(cdi.get());
8539 
8540  //printf("cd=%s getOuterScope=%p global=%p\n",qPrint(cd->name()),cd->getOuterScope(),Doxygen::globalScope);
8541  if (cd &&
8542  (cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8543  cd->getOuterScope()==Doxygen::globalScope // only look at global concepts
8544  ) && !cd->isHidden() && cd->isLinkableInProject()
8545  )
8546  {
8547  msg("Generating docs for concept %s...\n",qPrint(cd->name()));
8549  }
8550  }
8551 }
8552 
8553 //----------------------------------------------------------------------------
8554 
8556 {
8557  for (const auto &mn : *Doxygen::memberNameLinkedMap)
8558  {
8559  for (const auto &imd : *mn)
8560  {
8561  MemberDefMutable *md = toMemberDefMutable(imd.get());
8562  //static int count=0;
8563  //printf("%04d Member '%s'\n",count++,qPrint(md->qualifiedName()));
8564  if (md && md->documentation().isEmpty() && md->briefDescription().isEmpty())
8565  { // no documentation yet
8566  const MemberDef *bmd = md->reimplements();
8567  while (bmd && bmd->documentation().isEmpty() &&
8568  bmd->briefDescription().isEmpty()
8569  )
8570  { // search up the inheritance tree for a documentation member
8571  //printf("bmd=%s class=%s\n",qPrint(bmd->name()),qPrint(bmd->getClassDef()->name()));
8572  bmd = bmd->reimplements();
8573  }
8574  if (bmd) // copy the documentation from the reimplemented member
8575  {
8576  md->setInheritsDocsFrom(bmd);
8577  md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8579  md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8580  md->copyArgumentNames(bmd);
8582  }
8583  }
8584  }
8585  }
8586 }
8587 
8588 //----------------------------------------------------------------------------
8589 
8591 {
8592  // for each file
8593  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8594  {
8595  for (const auto &fd : *fn)
8596  {
8597  fd->combineUsingRelations();
8598  }
8599  }
8600 
8601  // for each namespace
8602  NamespaceDefSet visitedNamespaces;
8603  for (const auto &nd : *Doxygen::namespaceLinkedMap)
8604  {
8605  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
8606  if (ndm)
8607  {
8608  ndm->combineUsingRelations(visitedNamespaces);
8609  }
8610  }
8611 }
8612 
8613 //----------------------------------------------------------------------------
8614 
8616 {
8617  // for each class
8618  for (const auto &cd : *Doxygen::classLinkedMap)
8619  {
8620  ClassDefMutable *cdm = toClassDefMutable(cd.get());
8621  if (cdm)
8622  {
8623  cdm->addMembersToMemberGroup();
8624  }
8625  }
8626  // for each file
8627  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8628  {
8629  for (const auto &fd : *fn)
8630  {
8632  }
8633  }
8634  // for each namespace
8635  for (const auto &nd : *Doxygen::namespaceLinkedMap)
8636  {
8637  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
8638  if (ndm)
8639  {
8640  ndm->addMembersToMemberGroup();
8641  }
8642  }
8643  // for each group
8644  for (const auto &gd : *Doxygen::groupLinkedMap)
8645  {
8647  }
8648 }
8649 
8650 //----------------------------------------------------------------------------
8651 
8653 {
8654  // for each class
8655  for (const auto &cd : *Doxygen::classLinkedMap)
8656  {
8657  ClassDefMutable *cdm = toClassDefMutable(cd.get());
8658  if (cdm)
8659  {
8661  }
8662  }
8663  // for each file
8664  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8665  {
8666  for (const auto &fd : *fn)
8667  {
8669  }
8670  }
8671  // for each namespace
8672  for (const auto &nd : *Doxygen::namespaceLinkedMap)
8673  {
8674  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
8675  if (ndm)
8676  {
8678  }
8679  }
8680  // for each group
8681  for (const auto &gd : *Doxygen::groupLinkedMap)
8682  {
8684  }
8685 }
8686 
8687 //----------------------------------------------------------------------------
8688 
8690 {
8691  // for each class
8692  for (const auto &cd : *Doxygen::classLinkedMap)
8693  {
8694  ClassDefMutable *cdm = toClassDefMutable(cd.get());
8695  if (cdm)
8696  {
8698  }
8699  }
8700  // for each concept
8701  for (const auto &cd : *Doxygen::conceptLinkedMap)
8702  {
8703  ConceptDefMutable *cdm = toConceptDefMutable(cd.get());
8704  if (cdm)
8705  {
8707  }
8708  }
8709  // for each file
8710  for (const auto &fn : *Doxygen::inputNameLinkedMap)
8711  {
8712  for (const auto &fd : *fn)
8713  {
8715  }
8716  }
8717  // for each namespace
8718  for (const auto &nd : *Doxygen::namespaceLinkedMap)
8719  {
8720  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
8721  if (ndm)
8722  {
8724  }
8725  }
8726  // for each group
8727  for (const auto &gd : *Doxygen::groupLinkedMap)
8728  {
8730  }
8731  // for each page
8732  for (const auto &pd : *Doxygen::pageLinkedMap)
8733  {
8734  pd->findSectionsInDocumentation();
8735  }
8736  if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8737 }
8738 
8739 //----------------------------------------------------------------------
8740 
8741 
8743 {
8744  // remove all references to classes from the cache
8745  // as there can be new template instances in the inheritance path
8746  // to this class. Optimization: only remove those classes that
8747  // have inheritance instances as direct or indirect sub classes.
8748  StringVector elementsToRemove;
8749  for (const auto &ci : *Doxygen::lookupCache)
8750  {
8751  const LookupInfo &li = ci.second;
8752  if (li.classDef)
8753  {
8754  elementsToRemove.push_back(ci.first);
8755  }
8756  }
8757  for (const auto &k : elementsToRemove)
8758  {
8760  }
8761 
8762  // remove all cached typedef resolutions whose target is a
8763  // template class as this may now be a template instance
8764  // for each global function name
8765  for (const auto &fn : *Doxygen::functionNameLinkedMap)
8766  {
8767  // for each function with that name
8768  for (const auto &ifmd : *fn)
8769  {
8770  MemberDefMutable *fmd = toMemberDefMutable(ifmd.get());
8771  if (fmd && fmd->isTypedefValCached())
8772  {
8773  const ClassDef *cd = fmd->getCachedTypedefVal();
8774  if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8775  }
8776  }
8777  }
8778  // for each class method name
8779  for (const auto &nm : *Doxygen::memberNameLinkedMap)
8780  {
8781  // for each function with that name
8782  for (const auto &imd : *nm)
8783  {
8784  MemberDefMutable *md = toMemberDefMutable(imd.get());
8785  if (md && md->isTypedefValCached())
8786  {
8787  const ClassDef *cd = md->getCachedTypedefVal();
8788  if (cd->isTemplate()) md->invalidateTypedefValCache();
8789  }
8790  }
8791  }
8792 }
8793 
8794 //----------------------------------------------------------------------------
8795 
8797 {
8798  // Remove all unresolved references to classes from the cache.
8799  // This is needed before resolving the inheritance relations, since
8800  // it would otherwise not find the inheritance relation
8801  // for C in the example below, as B::I was already found to be unresolvable
8802  // (which is correct if you ignore the inheritance relation between A and B).
8803  //
8804  // class A { class I {} };
8805  // class B : public A {};
8806  // class C : public B::I {};
8807 
8808  StringVector elementsToRemove;
8809  for (const auto &ci : *Doxygen::lookupCache)
8810  {
8811  const LookupInfo &li = ci.second;
8812  if (li.classDef==0 && li.typeDef==0)
8813  {
8814  elementsToRemove.push_back(ci.first);
8815  }
8816  }
8817  for (const auto &k : elementsToRemove)
8818  {
8820  }
8821 
8822  // for each global function name
8823  for (const auto &fn : *Doxygen::functionNameLinkedMap)
8824  {
8825  // for each function with that name
8826  for (const auto &ifmd : *fn)
8827  {
8828  MemberDefMutable *fmd = toMemberDefMutable(ifmd.get());
8829  if (fmd)
8830  {
8832  }
8833  }
8834  }
8835  // for each class method name
8836  for (const auto &nm : *Doxygen::memberNameLinkedMap)
8837  {
8838  // for each function with that name
8839  for (const auto &imd : *nm)
8840  {
8841  MemberDefMutable *md = toMemberDefMutable(imd.get());
8842  if (md)
8843  {
8845  }
8846  }
8847  }
8848 
8849 }
8850 
8851 //----------------------------------------------------------------------------
8852 
8853 static void findDefineDocumentation(Entry *root)
8854 {
8855  if ((root->section==Entry::DEFINEDOC_SEC ||
8856  root->section==Entry::DEFINE_SEC) && !root->name.isEmpty()
8857  )
8858  {
8859  //printf("found define '%s' '%s' brief='%s' doc='%s'\n",
8860  // qPrint(root->name),qPrint(root->args),qPrint(root->brief),qPrint(root->doc));
8861 
8862  if (root->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8863  {
8864  std::unique_ptr<MemberDefMutable> md { createMemberDef(root->tagInfo()->tagName,1,1,
8865  "#define",root->name,root->args,QCString(),
8867  ArgumentList(),ArgumentList(),"") };
8868  md->setTagInfo(root->tagInfo());
8869  md->setLanguage(root->lang);
8870  //printf("Searching for '%s' fd=%p\n",qPrint(filePathName),fd);
8871  md->setFileDef(root->parent()->fileDef());
8872  //printf("Adding member=%s\n",qPrint(md->name()));
8874  mn->push_back(std::move(md));
8875  }
8877  if (mn)
8878  {
8879  int count=0;
8880  for (const auto &md : *mn)
8881  {
8882  if (md->memberType()==MemberType_Define) count++;
8883  }
8884  if (count==1)
8885  {
8886  for (const auto &imd : *mn)
8887  {
8888  MemberDefMutable *md = toMemberDefMutable(imd.get());
8889  if (md && md->memberType()==MemberType_Define)
8890  {
8891  md->setDocumentation(root->doc,root->docFile,root->docLine);
8892  md->setDocsForDefinition(!root->proto);
8893  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8894  if (md->inbodyDocumentation().isEmpty())
8895  {
8896  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8897  }
8898  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
8899  md->setBodyDef(root->fileDef());
8900  md->addSectionsToDefinition(root->anchors);
8901  md->setMaxInitLines(root->initLines);
8902  md->setRefItems(root->sli);
8903  if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8904  addMemberToGroups(root,md);
8905  }
8906  }
8907  }
8908  else if (count>1 &&
8909  (!root->doc.isEmpty() ||
8910  !root->brief.isEmpty() ||
8911  root->bodyLine!=-1
8912  )
8913  )
8914  // multiple defines don't know where to add docs
8915  // but maybe they are in different files together with their documentation
8916  {
8917  for (const auto &imd : *mn)
8918  {
8919  MemberDefMutable *md = toMemberDefMutable(imd.get());
8920  if (md && md->memberType()==MemberType_Define)
8921  {
8922  const FileDef *fd=md->getFileDef();
8923  if (fd && fd->absFilePath()==root->fileName)
8924  // doc and define in the same file assume they belong together.
8925  {
8926  md->setDocumentation(root->doc,root->docFile,root->docLine);
8927  md->setDocsForDefinition(!root->proto);
8928  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8929  if (md->inbodyDocumentation().isEmpty())
8930  {
8931  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8932  }
8933  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
8934  md->setBodyDef(root->fileDef());
8935  md->addSectionsToDefinition(root->anchors);
8936  md->setRefItems(root->sli);
8937  md->setLanguage(root->lang);
8938  if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8939  addMemberToGroups(root,md);
8940  }
8941  }
8942  }
8943  //warn("define %s found in the following files:\n",qPrint(root->name));
8944  //warn("Cannot determine where to add the documentation found "
8945  // "at line %d of file %s. \n",
8946  // root->startLine,qPrint(root->fileName));
8947  }
8948  }
8949  else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8950  {
8951  static bool preEnabled = Config_getBool(ENABLE_PREPROCESSING);
8952  if (preEnabled)
8953  {
8954  warn(root->fileName,root->startLine,
8955  "documentation for unknown define %s found.\n",
8956  qPrint(root->name)
8957  );
8958  }
8959  else
8960  {
8961  warn(root->fileName,root->startLine,
8962  "found documented #define %s but ignoring it because "
8963  "ENABLE_PREPROCESSING is NO.\n",
8964  qPrint(root->name)
8965  );
8966  }
8967  }
8968  }
8969  for (const auto &e : root->children()) findDefineDocumentation(e.get());
8970 }
8971 
8972 //----------------------------------------------------------------------------
8973 
8974 static void findDirDocumentation(const Entry *root)
8975 {
8976  if (root->section == Entry::DIRDOC_SEC)
8977  {
8978  QCString normalizedName = root->name;
8979  normalizedName = substitute(normalizedName,"\\","/");
8980  //printf("root->docFile=%s normalizedName=%s\n",
8981  // qPrint(root->docFile),qPrint(normalizedName));
8982  if (root->docFile==normalizedName) // current dir?
8983  {
8984  int lastSlashPos=normalizedName.findRev('/');
8985  if (lastSlashPos!=-1) // strip file name
8986  {
8987  normalizedName=normalizedName.left(lastSlashPos);
8988  }
8989  }
8990  if (normalizedName.at(normalizedName.length()-1)!='/')
8991  {
8992  normalizedName+='/';
8993  }
8994  DirDef *matchingDir=0;
8995  for (const auto &dir : *Doxygen::dirLinkedMap)
8996  {
8997  //printf("Dir: %s<->%s\n",qPrint(dir->name()),qPrint(normalizedName));
8998  if (dir->name().right(normalizedName.length())==normalizedName)
8999  {
9000  if (matchingDir)
9001  {
9002  warn(root->fileName,root->startLine,
9003  "\\dir command matches multiple directories.\n"
9004  " Applying the command for directory %s\n"
9005  " Ignoring the command for directory %s\n",
9006  qPrint(matchingDir->name()),qPrint(dir->name())
9007  );
9008  }
9009  else
9010  {
9011  matchingDir=dir.get();
9012  }
9013  }
9014  }
9015  if (matchingDir)
9016  {
9017  //printf("Match for with dir %s\n",qPrint(matchingDir->name()));
9018  matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
9019  matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
9020  matchingDir->setRefItems(root->sli);
9021  addDirToGroups(root,matchingDir);
9022  }
9023  else
9024  {
9025  warn(root->fileName,root->startLine,"No matching "
9026  "directory found for command \\dir %s\n",qPrint(normalizedName));
9027  }
9028  }
9029  for (const auto &e : root->children()) findDirDocumentation(e.get());
9030 }
9031 
9032 
9033 //----------------------------------------------------------------------------
9034 // create a (sorted) list of separate documentation pages
9035 
9036 static void buildPageList(Entry *root)
9037 {
9038  if (root->section == Entry::PAGEDOC_SEC)
9039  {
9040  if (!root->name.isEmpty())
9041  {
9042  addRelatedPage(root);
9043  }
9044  }
9045  else if (root->section == Entry::MAINPAGEDOC_SEC)
9046  {
9047  QCString title=root->args.stripWhiteSpace();
9048  if (title.isEmpty()) title=theTranslator->trMainPage();
9049  //QCString name = Config_getBool(GENERATE_TREEVIEW)?"main":"index";
9050  QCString name = "index";
9051  addRefItem(root->sli,
9052  name,
9053  "page",
9054  name,
9055  title,
9056  QCString(),0
9057  );
9058  }
9059  for (const auto &e : root->children()) buildPageList(e.get());
9060 }
9061 
9062 // search for the main page defined in this project
9063 static void findMainPage(Entry *root)
9064 {
9065  if (root->section == Entry::MAINPAGEDOC_SEC)
9066  {
9067  if (Doxygen::mainPage==0 && root->tagInfo()==0)
9068  {
9069  //printf("mainpage: docLine=%d startLine=%d\n",root->docLine,root->startLine);
9070  //printf("Found main page! \n======\n%s\n=======\n",qPrint(root->doc));
9071  QCString title=root->args.stripWhiteSpace();
9072  if (title.isEmpty()) title = Config_getString(PROJECT_NAME);
9073  //QCString indexName=Config_getBool(GENERATE_TREEVIEW)?"main":"index";
9074  QCString indexName="index";
9075  Doxygen::mainPage.reset(createPageDef(root->docFile,root->docLine,
9076  indexName, root->brief+root->doc+root->inbodyDocs,title));
9077  //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
9078  Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
9079  Doxygen::mainPage->setBodySegment(root->startLine,root->startLine,-1);
9080  Doxygen::mainPage->setFileName(indexName);
9081  Doxygen::mainPage->setLocalToc(root->localToc);
9082  addPageToContext(Doxygen::mainPage.get(),root);
9083 
9085  if (si)
9086  {
9087  if (!si->ref().isEmpty()) // we are from a tag file
9088  {
9089  // a page name is a label as well! but should no be double either
9091  Doxygen::mainPage->name(),
9092  indexName,
9093  root->startLine,
9094  Doxygen::mainPage->title(),
9096  0); // level 0
9097  }
9098  else if (si->lineNr() != -1)
9099  {
9100  warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s, line %d)",
9101  qPrint(Doxygen::mainPage->name()),qPrint(si->fileName()),si->lineNr());
9102  }
9103  else
9104  {
9105  warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s)",
9106  qPrint(Doxygen::mainPage->name()),qPrint(si->fileName()));
9107  }
9108  }
9109  else
9110  {
9111  // a page name is a label as well! but should no be double either
9113  Doxygen::mainPage->name(),
9114  indexName,
9115  root->startLine,
9116  Doxygen::mainPage->title(),
9118  0); // level 0
9119  }
9120  Doxygen::mainPage->addSectionsToDefinition(root->anchors);
9121  }
9122  else if (root->tagInfo()==0)
9123  {
9124  warn(root->fileName,root->startLine,
9125  "found more than one \\mainpage comment block! (first occurrence: %s, line %d), Skipping current block!",
9126  qPrint(Doxygen::mainPage->docFile()),Doxygen::mainPage->getStartBodyLine());
9127  }
9128  }
9129  for (const auto &e : root->children()) findMainPage(e.get());
9130 }
9131 
9132 // search for the main page imported via tag files and add only the section labels
9133 static void findMainPageTagFiles(Entry *root)
9134 {
9135  if (root->section == Entry::MAINPAGEDOC_SEC)
9136  {
9137  if (Doxygen::mainPage && root->tagInfo())
9138  {
9139  Doxygen::mainPage->addSectionsToDefinition(root->anchors);
9140  }
9141  }
9142  for (const auto &e : root->children()) findMainPageTagFiles(e.get());
9143 }
9144 
9145 static void computePageRelations(Entry *root)
9146 {
9147  if ((root->section==Entry::PAGEDOC_SEC ||
9149  )
9150  && !root->name.isEmpty()
9151  )
9152  {
9153  PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
9154  Doxygen::pageLinkedMap->find(root->name) :
9155  Doxygen::mainPage.get();
9156  if (pd)
9157  {
9158  for (const BaseInfo &bi : root->extends)
9159  {
9160  PageDef *subPd = Doxygen::pageLinkedMap->find(bi.name);
9161  if (pd==subPd)
9162  {
9163  term("page defined at line %d of file %s with label %s is a direct "
9164  "subpage of itself! Please remove this cyclic dependency.\n",
9165  pd->docLine(),qPrint(pd->docFile()),qPrint(pd->name()));
9166  }
9167  else if (subPd)
9168  {
9169  pd->addInnerCompound(subPd);
9170  //printf("*** Added subpage relation: %s->%s\n",
9171  // qPrint(pd->name()),qPrint(subPd->name()));
9172  }
9173  }
9174  }
9175  }
9176  for (const auto &e : root->children()) computePageRelations(e.get());
9177 }
9178 
9179 static void checkPageRelations()
9180 {
9181  for (const auto &pd : *Doxygen::pageLinkedMap)
9182  {
9183  Definition *ppd = pd->getOuterScope();
9184  while (ppd)
9185  {
9186  if (ppd==pd.get())
9187  {
9188  term("page defined at line %d of file %s with label %s is a subpage "
9189  "of itself! Please remove this cyclic dependency.\n",
9190  pd->docLine(),qPrint(pd->docFile()),qPrint(pd->name()));
9191  }
9192  ppd=ppd->getOuterScope();
9193  }
9194  }
9195 }
9196 
9197 //----------------------------------------------------------------------------
9198 
9200 {
9201  for (const auto &si : SectionManager::instance())
9202  {
9203  //printf("si->label='%s' si->definition=%s si->fileName='%s'\n",
9204  // qPrint(si->label),si->definition?qPrint(si->definition->name()):"<none>",
9205  // qPrint(si->fileName));
9206  PageDef *pd=0;
9207 
9208  // hack: the items of a todo/test/bug/deprecated list are all fragments from
9209  // different files, so the resulting section's all have the wrong file
9210  // name (not from the todo/test/bug/deprecated list, but from the file in
9211  // which they are defined). We correct this here by looking at the
9212  // generated section labels!
9213  for (const RefListManager::Ptr &rl : RefListManager::instance())
9214  {
9215  QCString label="_"+rl->listName(); // "_todo", "_test", ...
9216  if (si->label().left(label.length())==label)
9217  {
9218  si->setFileName(rl->listName());
9219  si->setGenerated(TRUE);
9220  break;
9221  }
9222  }
9223 
9224  //printf("start: si->label=%s si->fileName=%s\n",qPrint(si->label),qPrint(si->fileName));
9225  if (!si->generated())
9226  {
9227  // if this section is in a page and the page is in a group, then we
9228  // have to adjust the link file name to point to the group.
9229  if (!si->fileName().isEmpty() &&
9230  (pd=Doxygen::pageLinkedMap->find(si->fileName())) &&
9231  pd->getGroupDef())
9232  {
9233  si->setFileName(pd->getGroupDef()->getOutputFileBase());
9234  }
9235 
9236  if (si->definition())
9237  {
9238  // TODO: there should be one function in Definition that returns
9239  // the file to link to, so we can avoid the following tests.
9240  const GroupDef *gd=0;
9241  if (si->definition()->definitionType()==Definition::TypeMember)
9242  {
9243  gd = (toMemberDef(si->definition()))->getGroupDef();
9244  }
9245 
9246  if (gd)
9247  {
9248  si->setFileName(gd->getOutputFileBase());
9249  }
9250  else
9251  {
9252  //si->fileName=si->definition->getOutputFileBase();
9253  //printf("Setting si->fileName to %s\n",qPrint(si->fileName));
9254  }
9255  }
9256  }
9257  //printf("end: si->label=%s si->fileName=%s\n",qPrint(si->label),qPrint(si->fileName));
9258  }
9259 }
9260 
9261 
9262 
9263 //----------------------------------------------------------------------------
9264 // generate all separate documentation pages
9265 
9266 
9267 static void generatePageDocs()
9268 {
9269  //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageLinkedMap->count());
9270  if (documentedPages==0) return;
9271  for (const auto &pd : *Doxygen::pageLinkedMap)
9272  {
9273  if (!pd->getGroupDef() && !pd->isReference())
9274  {
9275  msg("Generating docs for page %s...\n",qPrint(pd->name()));
9277  pd->writeDocumentation(*g_outputList);
9279  }
9280  }
9281 }
9282 
9283 //----------------------------------------------------------------------------
9284 // create a (sorted) list & dictionary of example pages
9285 
9286 static void buildExampleList(Entry *root)
9287 {
9288  if ((root->section==Entry::EXAMPLE_SEC || root->section==Entry::EXAMPLE_LINENO_SEC) && !root->name.isEmpty())
9289  {
9290  if (Doxygen::exampleLinkedMap->find(root->name))
9291  {
9292  warn(root->fileName,root->startLine,
9293  "Example %s was already documented. Ignoring "
9294  "documentation found here.",
9295  qPrint(root->name)
9296  );
9297  }
9298  else
9299  {
9301  std::unique_ptr<PageDef>(
9302  createPageDef(root->fileName,root->startLine,
9303  root->name,root->brief+root->doc+root->inbodyDocs,root->args)));
9304  pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
9305  pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
9306  pd->addSectionsToDefinition(root->anchors);
9307  pd->setLanguage(root->lang);
9309 
9310  //we don't add example to groups
9311  //addExampleToGroups(root,pd);
9312  }
9313  }
9314  for (const auto &e : root->children()) buildExampleList(e.get());
9315 }
9316 
9317 //----------------------------------------------------------------------------
9318 // prints the Entry tree (for debugging)
9319 
9320 void printNavTree(Entry *root,int indent)
9321 {
9322  QCString indentStr;
9323  indentStr.fill(' ',indent);
9324  msg("%s%s (sec=0x%x)\n",
9325  indentStr.isEmpty()?"":qPrint(indentStr),
9326  root->name.isEmpty()?"<empty>":qPrint(root->name),
9327  root->section);
9328  for (const auto &e : root->children())
9329  {
9330  printNavTree(e.get(),indent+2);
9331  }
9332 }
9333 
9334 
9335 //----------------------------------------------------------------------------
9336 // generate the example documentation
9337 
9338 static void generateExampleDocs()
9339 {
9341  for (const auto &pd : *Doxygen::exampleLinkedMap)
9342  {
9343  msg("Generating docs for example %s...\n",qPrint(pd->name()));
9344  auto intf = Doxygen::parserManager->getCodeParser(".c"); // TODO: do this on code type
9345  intf->resetCodeParserState();
9346  QCString n=pd->getOutputFileBase();
9347  startFile(*g_outputList,n,n,pd->name());
9349  g_outputList->docify(pd->name());
9352  QCString lineNoOptStr;
9353  if (pd->showLineNo())
9354  {
9355  lineNoOptStr="{lineno}";
9356  }
9357  g_outputList->generateDoc(pd->docFile(), // file
9358  pd->docLine(), // startLine
9359  pd.get(), // context
9360  0, // memberDef
9361  pd->documentation()+"\n\n\\include"+lineNoOptStr+" "+pd->name(), // docs
9362  TRUE, // index words
9363  TRUE, // is example
9364  pd->name(),
9365  FALSE,
9366  FALSE,
9367  Config_getBool(MARKDOWN_SUPPORT)
9368  );
9369  endFile(*g_outputList); // contains g_outputList->endContents()
9370  }
9372 }
9373 
9374 //----------------------------------------------------------------------------
9375 // generate module pages
9376 
9377 static void generateGroupDocs()
9378 {
9379  for (const auto &gd : *Doxygen::groupLinkedMap)
9380  {
9381  if (!gd->isReference())
9382  {
9384  }
9385  }
9386 }
9387 
9388 //----------------------------------------------------------------------------
9389 // generate module pages
9390 
9391 static void generateNamespaceClassDocs(const ClassLinkedRefMap &classList)
9392 {
9393  std::size_t numThreads = static_cast<std::size_t>(Config_getInt(NUM_PROC_THREADS));
9394  if (numThreads==0)
9395  {
9396  numThreads = std::thread::hardware_concurrency();
9397  }
9398  if (numThreads>1) // multi threaded processing
9399  {
9400  struct DocContext
9401  {
9402  DocContext(ClassDefMutable *cdm_,OutputList ol_)
9403  : cdm(cdm_), ol(ol_) {}
9404  ClassDefMutable *cdm;
9405  OutputList ol;
9406  };
9407  ThreadPool threadPool(numThreads);
9408  std::vector< std::future< std::shared_ptr<DocContext> > > results;
9409  // for each class in the namespace...
9410  for (const auto &cd : classList)
9411  {
9413  if (cdm)
9414  {
9415  auto ctx = std::make_shared<DocContext>(cdm,*g_outputList);
9416  auto processFile = [ctx]()
9417  {
9418  if ( ( ctx->cdm->isLinkableInProject() &&
9419  ctx->cdm->templateMaster()==0
9420  ) // skip external references, anonymous compounds and
9421  // template instances and nested classes
9422  && !ctx->cdm->isHidden() && !ctx->cdm->isEmbeddedInOuterScope()
9423  )
9424  {
9425  msg("Generating docs for compound %s...\n",qPrint(ctx->cdm->name()));
9426  ctx->cdm->writeDocumentation(ctx->ol);
9427  ctx->cdm->writeMemberList(ctx->ol);
9428  }
9429  ctx->cdm->writeDocumentationForInnerClasses(ctx->ol);
9430  return ctx;
9431  };
9432  results.emplace_back(threadPool.queue(processFile));
9433  }
9434  }
9435  // wait for the results
9436  for (auto &f : results)
9437  {
9438  auto ctx = f.get();
9439  }
9440  }
9441  else // single threaded processing
9442  {
9443  // for each class in the namespace...
9444  for (const auto &cd : classList)
9445  {
9447  if (cdm)
9448  {
9449  if ( ( cd->isLinkableInProject() &&
9450  cd->templateMaster()==0
9451  ) // skip external references, anonymous compounds and
9452  // template instances and nested classes
9453  && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
9454  )
9455  {
9456  msg("Generating docs for compound %s...\n",qPrint(cd->name()));
9457 
9460  }
9462  }
9463  }
9464  }
9465 }
9466 
9467 static void generateNamespaceConceptDocs(const ConceptLinkedRefMap &conceptList)
9468 {
9469  // for each concept in the namespace...
9470  for (const auto &cd : conceptList)
9471  {
9473  if ( cdm && cd->isLinkableInProject() && !cd->isHidden())
9474  {
9475  msg("Generating docs for concept %s...\n",qPrint(cd->name()));
9477  }
9478  }
9479 }
9480 
9482 {
9483  static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE);
9484 
9485  //writeNamespaceIndex(*g_outputList);
9486 
9487  // for each namespace...
9488  for (const auto &nd : *Doxygen::namespaceLinkedMap)
9489  {
9490  if (nd->isLinkableInProject())
9491  {
9492  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
9493  if (ndm)
9494  {
9495  msg("Generating docs for namespace %s\n",qPrint(nd->name()));
9497  }
9498  }
9499 
9501  if (sliceOpt)
9502  {
9506  }
9508  }
9509 }
9510 
9511 #if defined(_WIN32)
9512 static QCString fixSlashes(QCString &s)
9513 {
9514  QCString result;
9515  uint i;
9516  for (i=0;i<s.length();i++)
9517  {
9518  switch(s.at(i))
9519  {
9520  case '/':
9521  case '\\':
9522  result+="\\\\";
9523  break;
9524  default:
9525  result+=s.at(i);
9526  }
9527  }
9528  return result;
9529 }
9530 #endif
9531 
9532 
9533 //----------------------------------------------------------------------------
9534 
9535 /*! Generate a template version of the configuration file.
9536  * If the \a shortList parameter is TRUE a configuration file without
9537  * comments will be generated.
9538  */
9539 static void generateConfigFile(const QCString &configFile,bool shortList,
9540  bool updateOnly=FALSE)
9541 {
9542  std::ofstream f;
9543  bool fileOpened=openOutputFile(configFile,f);
9544  bool writeToStdout=configFile=="-";
9545  if (fileOpened)
9546  {
9547  TextStream t(&f);
9548  Config::writeTemplate(t,shortList,updateOnly);
9549  if (!writeToStdout)
9550  {
9551  if (!updateOnly)
9552  {
9553  msg("\n\nConfiguration file '%s' created.\n\n",qPrint(configFile));
9554  msg("Now edit the configuration file and enter\n\n");
9555  if (configFile!="Doxyfile" && configFile!="doxyfile")
9556  msg(" doxygen %s\n\n",qPrint(configFile));
9557  else
9558  msg(" doxygen\n\n");
9559  msg("to generate the documentation for your project\n\n");
9560  }
9561  else
9562  {
9563  msg("\n\nConfiguration file '%s' updated.\n\n",qPrint(configFile));
9564  }
9565  }
9566  }
9567  else
9568  {
9569  term("Cannot open file %s for writing\n",qPrint(configFile));
9570  }
9571 }
9572 
9573 static void compareDoxyfile()
9574 {
9575  std::ofstream f;
9576  bool fileOpened=openOutputFile("-",f);
9577  if (fileOpened)
9578  {
9579  TextStream t(&f);
9581  }
9582  else
9583  {
9584  term("Cannot open stdout for writing\n");
9585  }
9586 }
9587 
9588 //----------------------------------------------------------------------------
9589 // read and parse a tag file
9590 
9591 static void readTagFile(const std::shared_ptr<Entry> &root,const QCString &tagLine)
9592 {
9593  QCString fileName;
9594  QCString destName;
9595  int eqPos = tagLine.find('=');
9596  if (eqPos!=-1) // tag command contains a destination
9597  {
9598  fileName = tagLine.left(eqPos).stripWhiteSpace();
9599  destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9600  if (fileName.isEmpty() || destName.isEmpty()) return;
9601  FileInfo fi(fileName.str());
9603  std::make_pair(fi.absFilePath(), destName.str()));
9604  //printf("insert tagDestination %s->%s\n",qPrint(fi.fileName()),qPrint(destName));
9605  }
9606  else
9607  {
9608  fileName = tagLine;
9609  }
9610 
9611  FileInfo fi(fileName.str());
9612  if (!fi.exists() || !fi.isFile())
9613  {
9614  err("Tag file '%s' does not exist or is not a file. Skipping it...\n",
9615  qPrint(fileName));
9616  return;
9617  }
9618 
9619  if (!destName.isEmpty())
9620  msg("Reading tag file '%s', location '%s'...\n",qPrint(fileName),qPrint(destName));
9621  else
9622  msg("Reading tag file '%s'...\n",qPrint(fileName));
9623 
9624  parseTagFile(root,fi.absFilePath().c_str());
9625 }
9626 
9627 //----------------------------------------------------------------------------
9628 static void copyLatexStyleSheet()
9629 {
9630  const StringVector &latexExtraStyleSheet = Config_getList(LATEX_EXTRA_STYLESHEET);
9631  for (const auto &sheet : latexExtraStyleSheet)
9632  {
9633  std::string fileName = sheet;
9634  if (!fileName.empty())
9635  {
9636  FileInfo fi(fileName);
9637  if (!fi.exists())
9638  {
9639  err("Style sheet '%s' specified by LATEX_EXTRA_STYLESHEET does not exist!\n",qPrint(fileName));
9640  }
9641  else
9642  {
9643  QCString destFileName = Config_getString(LATEX_OUTPUT)+"/"+fi.fileName();
9644  if (!checkExtension(fi.fileName().c_str(), LATEX_STYLE_EXTENSION))
9645  {
9646  destFileName += LATEX_STYLE_EXTENSION;
9647  }
9648  copyFile(QCString(fileName), destFileName);
9649  }
9650  }
9651  }
9652 }
9653 
9654 //----------------------------------------------------------------------------
9655 static void copyStyleSheet()
9656 {
9657  QCString htmlStyleSheet = Config_getString(HTML_STYLESHEET);
9658  if (!htmlStyleSheet.isEmpty())
9659  {
9660  FileInfo fi(htmlStyleSheet.str());
9661  if (!fi.exists())
9662  {
9663  err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",qPrint(htmlStyleSheet));
9664  htmlStyleSheet = Config_updateString(HTML_STYLESHEET,""); // revert to the default
9665  }
9666  else
9667  {
9668  QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName();
9669  copyFile(htmlStyleSheet,destFileName);
9670  }
9671  }
9672  const StringVector &htmlExtraStyleSheet = Config_getList(HTML_EXTRA_STYLESHEET);
9673  for (const auto &sheet : htmlExtraStyleSheet)
9674  {
9675  std::string fileName = sheet;
9676  if (!fileName.empty())
9677  {
9678  FileInfo fi(fileName);
9679  if (!fi.exists())
9680  {
9681  err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",fileName.c_str());
9682  }
9683  else if (fi.fileName()=="doxygen.css" || fi.fileName()=="tabs.css" || fi.fileName()=="navtree.css")
9684  {
9685  err("Style sheet %s specified by HTML_EXTRA_STYLESHEET is already a built-in stylesheet. Please use a different name\n",qPrint(fi.fileName()));
9686  }
9687  else
9688  {
9689  QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName();
9690  copyFile(QCString(fileName), destFileName);
9691  }
9692  }
9693  }
9694 }
9695 
9696 static void copyLogo(const QCString &outputOption)
9697 {
9698  QCString projectLogo = Config_getString(PROJECT_LOGO);
9699  if (!projectLogo.isEmpty())
9700  {
9701  FileInfo fi(projectLogo.str());
9702  if (!fi.exists())
9703  {
9704  err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",qPrint(projectLogo));
9705  projectLogo = Config_updateString(PROJECT_LOGO,""); // revert to the default
9706  }
9707  else
9708  {
9709  QCString destFileName = outputOption+"/"+fi.fileName();
9710  copyFile(projectLogo,destFileName);
9711  Doxygen::indexList->addImageFile(fi.fileName().c_str());
9712  }
9713  }
9714 }
9715 
9716 static void copyExtraFiles(const StringVector &files,const QCString &filesOption,const QCString &outputOption)
9717 {
9718  for (const auto &fileName : files)
9719  {
9720  if (!fileName.empty())
9721  {
9722  FileInfo fi(fileName);
9723  if (!fi.exists())
9724  {
9725  err("Extra file '%s' specified in %s does not exist!\n", fileName.c_str(),qPrint(filesOption));
9726  }
9727  else
9728  {
9729  QCString destFileName = outputOption+"/"+fi.fileName();
9730  Doxygen::indexList->addImageFile(fi.fileName().c_str());
9731  copyFile(QCString(fileName), destFileName);
9732  }
9733  }
9734  }
9735 }
9736 
9737 //----------------------------------------------------------------------------
9738 
9739 static void generateDiskNames()
9740 {
9741  for (const auto &fn : *Doxygen::inputNameLinkedMap)
9742  {
9743  struct FileEntry
9744  {
9745  FileEntry(const QCString &p,FileDef *fd) : path(p), fileDef(fd) {}
9746  QCString path;
9747  FileDef *fileDef;
9748  };
9749 
9750  // collect the entry for which to compute the longest common prefix (LCP) of the path
9751  std::vector<FileEntry> fileEntries;
9752  for (const auto &fd : *fn)
9753  {
9754  if (!fd->isReference()) // skip external references
9755  {
9756  fileEntries.emplace_back(fd->getPath(),fd.get());
9757  }
9758  }
9759 
9760  size_t size = fileEntries.size();
9761 
9762  if (size==1) // name if unique, so diskname is simply the name
9763  {
9764  FileDef *fd = fileEntries[0].fileDef;
9765  fd->setDiskName(fn->fileName());
9766  }
9767  else if (size>1) // multiple occurrences of the same file name
9768  {
9769  // sort the array
9770  std::sort(fileEntries.begin(),
9771  fileEntries.end(),
9772  [](const FileEntry &fe1,const FileEntry &fe2)
9773  { return fe1.path < fe2.path; }
9774  );
9775 
9776  // since the entries are sorted, the common prefix of the whole array is same
9777  // as the common prefix between the first and last entry
9778  const FileEntry &first = fileEntries[0];
9779  const FileEntry &last = fileEntries[size-1];
9780  int first_path_size = static_cast<int>(first.path.size())-1; // -1 to skip trailing slash
9781  int last_path_size = static_cast<int>(last.path.size())-1; // -1 to skip trailing slash
9782  int j=0;
9783  int i=0;
9784  for (i=0;i<first_path_size && i<last_path_size;i++)
9785  {
9786  if (first.path[i]=='/') j=i;
9787  if (first.path[i]!=last.path[i]) break;
9788  }
9789  if (i==first_path_size && i<last_path_size && last.path[i]=='/')
9790  {
9791  // case first='some/path' and last='some/path/more' => match is 'some/path'
9792  j=first_path_size;
9793  }
9794  else if (i==last_path_size && i<first_path_size && first.path[i]=='/')
9795  {
9796  // case first='some/path/more' and last='some/path' => match is 'some/path'
9797  j=last_path_size;
9798  }
9799 
9800  // add non-common part of the path to the name
9801  for (auto &fileEntry : fileEntries)
9802  {
9803  QCString prefix = fileEntry.path.right(fileEntry.path.length()-j-1);
9804  fileEntry.fileDef->setName(prefix+fn->fileName());
9805  //printf("!!!!!!!! non unique disk name=%s:%s\n",qPrint(prefix),fn->fileName());
9806  fileEntry.fileDef->setDiskName(prefix+fn->fileName());
9807  }
9808  }
9809  }
9810 }
9811 
9812 
9813 
9814 //----------------------------------------------------------------------------
9815 
9816 static std::unique_ptr<OutlineParserInterface> getParserForFile(const QCString &fn)
9817 {
9818  QCString fileName=fn;
9819  QCString extension;
9820  int sep = fileName.findRev('/');
9821  int ei = fileName.findRev('.');
9822  if (ei!=-1 && (sep==-1 || ei>sep)) // matches dir/file.ext but not dir.1/file
9823  {
9824  extension=fileName.right(fileName.length()-ei);
9825  }
9826  else
9827  {
9828  extension = ".no_extension";
9829  }
9830 
9831  return Doxygen::parserManager->getOutlineParser(extension);
9832 }
9833 
9834 static std::shared_ptr<Entry> parseFile(OutlineParserInterface &parser,
9835  FileDef *fd,const QCString &fn,
9836  ClangTUParser *clangParser,bool newTU)
9837 {
9838  QCString fileName=fn;
9839  QCString extension;
9840  int ei = fileName.findRev('.');
9841  if (ei!=-1)
9842  {
9843  extension=fileName.right(fileName.length()-ei);
9844  }
9845  else
9846  {
9847  extension = ".no_extension";
9848  }
9849 
9850  FileInfo fi(fileName.str());
9851  BufStr preBuf((uint)fi.size()+4096);
9852 
9853  if (Config_getBool(ENABLE_PREPROCESSING) &&
9854  parser.needsPreprocessing(extension))
9855  {
9856  Preprocessor preprocessor;
9857  const StringVector &includePath = Config_getList(INCLUDE_PATH);
9858  for (const auto &s : includePath)
9859  {
9860  std::string absPath = FileInfo(s).absFilePath();
9861  preprocessor.addSearchDir(absPath.c_str());
9862  }
9863  BufStr inBuf((uint)fi.size()+4096);
9864  msg("Preprocessing %s...\n",qPrint(fn));
9865  readInputFile(fileName,inBuf);
9866  preprocessor.processFile(fileName,inBuf,preBuf);
9867  }
9868  else // no preprocessing
9869  {
9870  msg("Reading %s...\n",qPrint(fn));
9871  readInputFile(fileName,preBuf);
9872  }
9873  if (preBuf.data() && preBuf.curPos()>0 && *(preBuf.data()+preBuf.curPos()-1)!='\n')
9874  {
9875  preBuf.addChar('\n'); // add extra newline to help parser
9876  }
9877 
9878  BufStr convBuf(preBuf.curPos()+1024);
9879 
9880  // convert multi-line C++ comments to C style comments
9881  convertCppComments(&preBuf,&convBuf,fileName);
9882 
9883  convBuf.addChar('\0');
9884 
9885  std::shared_ptr<Entry> fileRoot = std::make_shared<Entry>();
9886  // use language parse to parse the file
9887  if (clangParser)
9888  {
9889  if (newTU) clangParser->parse();
9890  clangParser->switchToFile(fd);
9891  }
9892  parser.parseInput(fileName,convBuf.data(),fileRoot,clangParser);
9893  fileRoot->setFileDef(fd);
9894  return fileRoot;
9895 }
9896 
9897 //! parse the list of input files
9898 static void parseFilesMultiThreading(const std::shared_ptr<Entry> &root)
9899 {
9900 #if USE_LIBCLANG
9902  {
9903  StringUnorderedSet processedFiles;
9904 
9905  // create a dictionary with files to process
9906  StringUnorderedSet filesToProcess;
9907  for (const auto &s : g_inputFiles)
9908  {
9909  filesToProcess.insert(s);
9910  }
9911 
9912  std::mutex processedFilesLock;
9913  // process source files (and their include dependencies)
9914  std::size_t numThreads = static_cast<std::size_t>(Config_getInt(NUM_PROC_THREADS));
9915  if (numThreads==0)
9916  {
9917  numThreads = std::thread::hardware_concurrency();
9918  }
9919  msg("Processing input using %zu threads.\n",numThreads);
9920  ThreadPool threadPool(numThreads);
9921  using FutureType = std::vector< std::shared_ptr<Entry> >;
9922  std::vector< std::future< FutureType > > results;
9923  for (const auto &s : g_inputFiles)
9924  {
9925  bool ambig;
9926  FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig);
9927  ASSERT(fd!=0);
9928  if (fd->isSource() && !fd->isReference()) // this is a source file
9929  {
9930  // lambda representing the work to executed by a thread
9931  auto processFile = [s,&filesToProcess,&processedFilesLock,&processedFiles]() {
9932  bool ambig_l;
9933  std::vector< std::shared_ptr<Entry> > roots;
9934  FileDef *fd_l = findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig_l);
9935  auto clangParser = ClangParser::instance()->createTUParser(fd_l);
9936  auto parser = getParserForFile(s.c_str());
9937  auto fileRoot { parseFile(*parser.get(),fd_l,s.c_str(),clangParser.get(),true) };
9938  roots.push_back(fileRoot);
9939 
9940  // Now process any include files in the same translation unit
9941  // first. When libclang is used this is much more efficient.
9942  for (auto incFile : clangParser->filesInSameTU())
9943  {
9944  if (filesToProcess.find(incFile)!=filesToProcess.end())
9945  {
9946  bool needsToBeProcessed;
9947  {
9948  std::lock_guard<std::mutex> lock(processedFilesLock);
9949  needsToBeProcessed = processedFiles.find(incFile)==processedFiles.end();
9950  if (needsToBeProcessed) processedFiles.insert(incFile);
9951  }
9952  if (incFile!=s && needsToBeProcessed)
9953  {
9954  FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile.c_str(),ambig_l);
9955  if (ifd && !ifd->isReference())
9956  {
9957  //printf(" Processing %s in same translation unit as %s\n",incFile,s->c_str());
9958  fileRoot = parseFile(*parser.get(),ifd,incFile.c_str(),clangParser.get(),false);
9959  roots.push_back(fileRoot);
9960  }
9961  }
9962  }
9963  }
9964  return roots;
9965  };
9966  // dispatch the work and collect the future results
9967  results.emplace_back(threadPool.queue(processFile));
9968  }
9969  }
9970  // synchronise with the Entry result lists produced and add them to the root
9971  for (auto &f : results)
9972  {
9973  auto l = f.get();
9974  for (auto &e : l)
9975  {
9976  root->moveToSubEntryAndKeep(e);
9977  }
9978  }
9979  // process remaining files
9980  results.clear();
9981  for (const auto &s : g_inputFiles)
9982  {
9983  if (processedFiles.find(s)==processedFiles.end()) // not yet processed
9984  {
9985  // lambda representing the work to executed by a thread
9986  auto processFile = [s]() {
9987  bool ambig;
9988  std::vector< std::shared_ptr<Entry> > roots;
9989  FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig);
9990  auto clangParser = ClangParser::instance()->createTUParser(fd);
9991  auto parser { getParserForFile(s.c_str()) };
9992  auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true);
9993  roots.push_back(fileRoot);
9994  return roots;
9995  };
9996  // dispatch the work and collect the future results
9997  results.emplace_back(threadPool.queue(processFile));
9998  }
9999  }
10000  // synchronise with the Entry result lists produced and add them to the root
10001  for (auto &f : results)
10002  {
10003  auto l = f.get();
10004  for (auto &e : l)
10005  {
10006  root->moveToSubEntryAndKeep(e);
10007  }
10008  }
10009  }
10010  else // normal processing
10011 #endif
10012  {
10013  std::size_t numThreads = std::thread::hardware_concurrency();
10014  msg("Processing input using %zu threads.\n",numThreads);
10015  ThreadPool threadPool(numThreads);
10016  using FutureType = std::shared_ptr<Entry>;
10017  std::vector< std::future< FutureType > > results;
10018  for (const auto &s : g_inputFiles)
10019  {
10020  // lambda representing the work to executed by a thread
10021  auto processFile = [s]() {
10022  bool ambig;
10023  FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig);
10024  auto parser = getParserForFile(s.c_str());
10025  auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),nullptr,true);
10026  return fileRoot;
10027  };
10028  // dispatch the work and collect the future results
10029  results.emplace_back(threadPool.queue(processFile));
10030  }
10031  // synchronise with the Entry results produced and add them to the root
10032  for (auto &f : results)
10033  {
10034  root->moveToSubEntryAndKeep(f.get());
10035  }
10036  }
10037 }
10038 
10039 //! parse the list of input files
10040 static void parseFilesSingleThreading(const std::shared_ptr<Entry> &root)
10041 {
10042 #if USE_LIBCLANG
10044  {
10045  StringUnorderedSet processedFiles;
10046 
10047  // create a dictionary with files to process
10048  StringUnorderedSet filesToProcess;
10049  for (const auto &s : g_inputFiles)
10050  {
10051  filesToProcess.insert(s);
10052  }
10053 
10054  // process source files (and their include dependencies)
10055  for (const auto &s : g_inputFiles)
10056  {
10057  bool ambig;
10058  FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig);
10059  ASSERT(fd!=0);
10060  if (fd->isSource() && !fd->isReference()) // this is a source file
10061  {
10062  auto clangParser = ClangParser::instance()->createTUParser(fd);
10063  auto parser { getParserForFile(s.c_str()) };
10064  auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true);
10065  root->moveToSubEntryAndKeep(fileRoot);
10066  processedFiles.insert(s);
10067 
10068  // Now process any include files in the same translation unit
10069  // first. When libclang is used this is much more efficient.
10070  for (auto incFile : clangParser->filesInSameTU())
10071  {
10072  //printf(" file %s\n",incFile.c_str());
10073  if (filesToProcess.find(incFile)!=filesToProcess.end() && // file need to be processed
10074  processedFiles.find(incFile)==processedFiles.end()) // and is not processed already
10075  {
10076  FileDef *ifd=findFileDef(Doxygen::inputNameLinkedMap,incFile.c_str(),ambig);
10077  if (ifd && !ifd->isReference())
10078  {
10079  //printf(" Processing %s in same translation unit as %s\n",incFile.c_str(),s.c_str());
10080  fileRoot = parseFile(*parser.get(),ifd,incFile.c_str(),clangParser.get(),false);
10081  root->moveToSubEntryAndKeep(fileRoot);
10082  processedFiles.insert(incFile);
10083  }
10084  }
10085  }
10086  }
10087  }
10088  // process remaining files
10089  for (const auto &s : g_inputFiles)
10090  {
10091  if (processedFiles.find(s)==processedFiles.end()) // not yet processed
10092  {
10093  bool ambig;
10094  FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig);
10095  auto clangParser = ClangParser::instance()->createTUParser(fd);
10096  auto parser { getParserForFile(s.c_str()) };
10097  auto fileRoot = parseFile(*parser.get(),fd,s.c_str(),clangParser.get(),true);
10098  root->moveToSubEntryAndKeep(fileRoot);
10099  processedFiles.insert(s);
10100  }
10101  }
10102  }
10103  else // normal processing
10104 #endif
10105  {
10106  for (const auto &s : g_inputFiles)
10107  {
10108  bool ambig;
10109  FileDef *fd=findFileDef(Doxygen::inputNameLinkedMap,s.c_str(),ambig);
10110  ASSERT(fd!=0);
10111  std::unique_ptr<OutlineParserInterface> parser { getParserForFile(s.c_str()) };
10112  std::shared_ptr<Entry> fileRoot = parseFile(*parser.get(),fd,s.c_str(),nullptr,true);
10113  root->moveToSubEntryAndKeep(fileRoot);
10114  }
10115  }
10116 }
10117 
10118 // resolves a path that may include symlinks, if a recursive symlink is
10119 // found an empty string is returned.
10120 static std::string resolveSymlink(const std::string &path)
10121 {
10122  int sepPos=0;
10123  int oldPos=0;
10124  StringSet nonSymlinks;
10125  StringSet known;
10126  QCString result(path);
10127  QCString oldPrefix = "/";
10128  do
10129  {
10130 #ifdef WIN32
10131  // UNC path, skip server and share name
10132  if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
10133  sepPos = result.find('/',2);
10134  if (sepPos!=-1)
10135  sepPos = result.find('/',sepPos+1);
10136 #else
10137  sepPos = result.find('/',sepPos+1);
10138 #endif
10139  QCString prefix = sepPos==-1 ? result : result.left(sepPos);
10140  if (nonSymlinks.find(prefix.str())==nonSymlinks.end())
10141  {
10142  FileInfo fi(prefix.str());
10143  if (fi.isSymLink())
10144  {
10145  QCString target = fi.readLink();
10146  bool isRelative = FileInfo(target.str()).isRelative();
10147  if (isRelative)
10148  {
10149  target = Dir::cleanDirPath(oldPrefix.str()+"/"+target.str());
10150  }
10151  if (sepPos!=-1)
10152  {
10153  if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
10154  {
10155  target+='/';
10156  }
10157  target+=result.mid(sepPos);
10158  }
10159  result = Dir::cleanDirPath(target.str());
10160  sepPos = 0;
10161  if (known.find(result.str())!=known.end()) return std::string(); // recursive symlink!
10162  known.insert(result.str());
10163  if (isRelative)
10164  {
10165  sepPos = oldPos;
10166  }
10167  else // link to absolute path
10168  {
10169  sepPos = 0;
10170  oldPrefix = "/";
10171  }
10172  }
10173  else
10174  {
10175  nonSymlinks.insert(prefix.str());
10176  oldPrefix = prefix;
10177  }
10178  oldPos = sepPos;
10179  }
10180  }
10181  while (sepPos!=-1);
10182  return Dir::cleanDirPath(result.str());
10183 }
10184 
10185 static StringUnorderedSet g_pathsVisited(1009);
10186 
10187 //----------------------------------------------------------------------------
10188 // Read all files matching at least one pattern in 'patList' in the
10189 // directory represented by 'fi'.
10190 // The directory is read iff the recursiveFlag is set.
10191 // The contents of all files is append to the input string
10192 
10193 static void readDir(FileInfo *fi,
10194  FileNameLinkedMap *fnMap,
10195  StringUnorderedSet *exclSet,
10196  const StringVector *patList,
10197  const StringVector *exclPatList,
10198  StringVector *resultList,
10199  StringUnorderedSet *resultSet,
10200  bool errorIfNotExist,
10201  bool recursive,
10202  StringUnorderedSet *killSet,
10203  StringSet *paths
10204  )
10205 {
10206  std::string dirName = fi->absFilePath();
10207  if (paths && !dirName.empty())
10208  {
10209  paths->insert(dirName);
10210  }
10211  //printf("%s isSymLink()=%d\n",qPrint(dirName),fi->isSymLink());
10212  if (fi->isSymLink())
10213  {
10214  dirName = resolveSymlink(dirName);
10215  if (dirName.empty())
10216  {
10217  //printf("RECURSIVE SYMLINK: %s\n",qPrint(dirName));
10218  return; // recursive symlink
10219  }
10220  }
10221 
10222  if (g_pathsVisited.find(dirName)!=g_pathsVisited.end())
10223  {
10224  //printf("PATH ALREADY VISITED: %s\n",qPrint(dirName));
10225  return; // already visited path
10226  }
10227  g_pathsVisited.insert(dirName);
10228 
10229  Dir dir(dirName);
10230  msg("Searching for files in directory %s\n", qPrint(fi->absFilePath()));
10231  //printf("killSet=%p count=%d\n",killSet,killSet ? (int)killSet->count() : -1);
10232 
10233  StringVector dirResultList;
10234 
10235  for (const auto &dirEntry : dir.iterator())
10236  {
10237  FileInfo cfi(dirEntry.path());
10238  if (exclSet==0 || exclSet->find(cfi.absFilePath())==exclSet->end())
10239  { // file should not be excluded
10240  //printf("killSet->find(%s)\n",qPrint(cfi->absFilePath()));
10241  if (!cfi.exists() || !cfi.isReadable())
10242  {
10243  if (errorIfNotExist)
10244  {
10245  warn_uncond("source '%s' is not a readable file or directory... skipping.\n",cfi.absFilePath().c_str());
10246  }
10247  }
10248  else if (cfi.isFile() &&
10249  (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi.isSymLink()) &&
10250  (patList==0 || patternMatch(cfi,*patList)) &&
10251  (exclPatList==0 || !patternMatch(cfi,*exclPatList)) &&
10252  (killSet==0 || killSet->find(cfi.absFilePath())==killSet->end())
10253  )
10254  {
10255  std::string name=cfi.fileName();
10256  std::string path=cfi.dirPath()+"/";
10257  std::string fullName=path+name;
10258  if (fnMap)
10259  {
10260  std::unique_ptr<FileDef> fd { createFileDef(QCString(path),QCString(name)) };
10261  FileName *fn=0;
10262  if (!name.empty())
10263  {
10264  fn = fnMap->add(QCString(name),QCString(fullName));
10265  fn->push_back(std::move(fd));
10266  }
10267  }
10268  dirResultList.push_back(fullName);
10269  if (resultSet) resultSet->insert(fullName);
10270  if (killSet) killSet->insert(fullName);
10271  }
10272  else if (recursive &&
10273  (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi.isSymLink()) &&
10274  cfi.isDir() &&
10275  (exclPatList==0 || !patternMatch(cfi,*exclPatList)) &&
10276  cfi.fileName().at(0)!='.') // skip "." ".." and ".dir"
10277  {
10278  FileInfo acfi(cfi.absFilePath());
10279  readDir(&acfi,fnMap,exclSet,
10280  patList,exclPatList,&dirResultList,resultSet,errorIfNotExist,
10281  recursive,killSet,paths);
10282  }
10283  }
10284  }
10285  if (resultList && !dirResultList.empty())
10286  {
10287  // sort the resulting list to make the order platform independent.
10288  std::sort(dirResultList.begin(),
10289  dirResultList.end(),
10290  [](const auto &f1,const auto &f2) { return qstricmp(f1.c_str(),f2.c_str())<0; });
10291 
10292  // append the sorted results to resultList
10293  resultList->insert(resultList->end(), dirResultList.begin(), dirResultList.end());
10294  }
10295 }
10296 
10297 
10298 //----------------------------------------------------------------------------
10299 // read a file or all files in a directory and append their contents to the
10300 // input string. The names of the files are appended to the 'fiList' list.
10301 
10303  FileNameLinkedMap *fnMap,
10304  StringUnorderedSet *exclSet,
10305  const StringVector *patList,
10306  const StringVector *exclPatList,
10307  StringVector *resultList,
10308  StringUnorderedSet *resultSet,
10309  bool recursive,
10310  bool errorIfNotExist,
10311  StringUnorderedSet *killSet,
10312  StringSet *paths
10313  )
10314 {
10315  //printf("killSet count=%d\n",killSet ? (int)killSet->size() : -1);
10316  // strip trailing slashes
10317  if (s.isEmpty()) return;
10318 
10319  g_pathsVisited.clear();
10320 
10321  FileInfo fi(s.str());
10322  //printf("readFileOrDirectory(%s)\n",s);
10323  {
10324  if (exclSet==0 || exclSet->find(fi.absFilePath())==exclSet->end())
10325  {
10326  if (!fi.exists() || !fi.isReadable())
10327  {
10328  if (errorIfNotExist)
10329  {
10330  warn_uncond("source '%s' is not a readable file or directory... skipping.\n",qPrint(s));
10331  }
10332  }
10333  else if (!Config_getBool(EXCLUDE_SYMLINKS) || !fi.isSymLink())
10334  {
10335  if (fi.isFile())
10336  {
10337  std::string dirPath = fi.dirPath(true);
10338  std::string filePath = fi.absFilePath();
10339  if (paths && !dirPath.empty())
10340  {
10341  paths->insert(dirPath);
10342  }
10343  //printf("killSet.find(%s)=%d\n",qPrint(fi.absFilePath()),killSet.find(fi.absFilePath())!=killSet.end());
10344  if (killSet==0 || killSet->find(filePath)==killSet->end())
10345  {
10346  std::string name=fi.fileName();
10347  if (fnMap)
10348  {
10349  std::unique_ptr<FileDef> fd { createFileDef(QCString(dirPath+"/"),QCString(name)) };
10350  if (!name.empty())
10351  {
10352  FileName *fn = fnMap->add(QCString(name),QCString(filePath));
10353  fn->push_back(std::move(fd));
10354  }
10355  }
10356  if (resultList || resultSet)
10357  {
10358  if (resultList) resultList->push_back(filePath);
10359  if (resultSet) resultSet->insert(filePath);
10360  }
10361 
10362  if (killSet) killSet->insert(fi.absFilePath());
10363  }
10364  }
10365  else if (fi.isDir()) // readable dir
10366  {
10367  readDir(&fi,fnMap,exclSet,patList,
10368  exclPatList,resultList,resultSet,errorIfNotExist,
10369  recursive,killSet,paths);
10370  }
10371  }
10372  }
10373  }
10374 }
10375 
10376 //----------------------------------------------------------------------------
10377 
10378 static void expandAliases()
10379 {
10380  for (auto &kv : Doxygen::aliasMap)
10381  {
10382  kv.second = expandAlias(kv.first,kv.second);
10383  }
10384 }
10385 
10386 //----------------------------------------------------------------------------
10387 
10388 static void escapeAliases()
10389 {
10390  for (auto &kv : Doxygen::aliasMap)
10391  {
10392  QCString value(kv.second);
10393  QCString newValue;
10394  int in,p=0;
10395  // for each \n in the alias command value
10396  while ((in=value.find("\\n",p))!=-1)
10397  {
10398  newValue+=value.mid(p,in-p);
10399  // expand \n's except if \n is part of a built-in command.
10400  if (value.mid(in,5)!="\\note" &&
10401  value.mid(in,5)!="\\noop" &&
10402  value.mid(in,5)!="\\name" &&
10403  value.mid(in,10)!="\\namespace" &&
10404  value.mid(in,14)!="\\nosubgrouping"
10405  )
10406  {
10407  newValue+="\\ilinebr ";
10408  }
10409  else
10410  {
10411  newValue+="\\n";
10412  }
10413  p=in+2;
10414  }
10415  newValue+=value.mid(p,value.length()-p);
10416  p = 0;
10417  newValue = "";
10418  while ((in=value.find("^^",p))!=-1)
10419  {
10420  newValue+=value.mid(p,in-p);
10421  newValue+="\\ilinebr ";
10422  p=in+2;
10423  }
10424  newValue+=value.mid(p,value.length()-p);
10425  kv.second=newValue.str();
10426  //printf("Alias %s has value %s\n",kv.first.c_str(),qPrint(newValue));
10427  }
10428 }
10429 
10430 //----------------------------------------------------------------------------
10431 
10433 {
10434  // add aliases to a dictionary
10435  const StringVector &aliasList = Config_getList(ALIASES);
10436  for (const auto &al : aliasList)
10437  {
10438  QCString alias(al);
10439  int i=alias.find('=');
10440  if (i>0)
10441  {
10442  QCString name=alias.left(i).stripWhiteSpace();
10443  QCString value=alias.right(alias.length()-i-1);
10444  //printf("Alias: found name='%s' value='%s'\n",qPrint(name),qPrint(value));
10445  if (!name.isEmpty())
10446  {
10447  auto it = Doxygen::aliasMap.find(name.str());
10448  if (it==Doxygen::aliasMap.end()) // insert new alias
10449  {
10450  Doxygen::aliasMap.insert(std::make_pair(name.str(),value.str()));
10451  }
10452  else // overwrite previous alias
10453  {
10454  it->second=value.str();
10455  }
10456  }
10457  }
10458  }
10459  expandAliases();
10460  escapeAliases();
10461 }
10462 
10463 //----------------------------------------------------------------------------
10464 
10466 {
10467  QCString anchor;
10469  {
10470  MemberDef *md = toMemberDef(d);
10471  anchor=":"+md->anchor();
10472  }
10473  QCString scope;
10475  {
10477  }
10478  t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
10479  << addHtmlExtensionIfMissing(d->getOutputFileBase())+anchor << "','"
10480  << scope << "','"
10481  << d->name() << "','"
10482  << d->getDefFileName() << "','"
10483  << d->getDefLine()
10484  << "');\n";
10485 }
10486 
10487 static void dumpSymbolMap()
10488 {
10489  std::ofstream f("symbols.sql",std::ofstream::out | std::ofstream::binary);
10490  if (f.is_open())
10491  {
10492  TextStream t(&f);
10493  for (const auto &kv : *Doxygen::symbolMap)
10494  {
10495  dumpSymbol(t,kv.second);
10496  }
10497  }
10498 }
10499 
10500 // print developer options of doxygen
10501 static void devUsage()
10502 {
10503  msg("Developer parameters:\n");
10504  msg(" -m dump symbol map\n");
10505  msg(" -b making messages output unbuffered\n");
10506  msg(" -T activates output generation via Django like template\n");
10507  msg(" -d <level> enable a debug level, such as (multiple invocations of -d are possible):\n");
10509 }
10510 
10511 
10512 //----------------------------------------------------------------------------
10513 // print the version of doxygen
10514 
10515 static void version(const bool extended)
10516 {
10517  QCString versionString = getFullVersion();
10518  msg("%s\n",qPrint(versionString));
10519  if (extended)
10520  {
10521  QCString extVers;
10522 #if USE_SQLITE3
10523  if (!extVers.isEmpty()) extVers+= ", ";
10524  extVers += "sqlite3 ";
10525  extVers += sqlite3_libversion();
10526 #endif
10527 #if USE_LIBCLANG
10528  if (!extVers.isEmpty()) extVers+= ", ";
10529  extVers += "clang support ";
10530  extVers += CLANG_VERSION_STRING;
10531 #endif
10532  if (!extVers.isEmpty())
10533  {
10534  int lastComma = extVers.findRev(',');
10535  if (lastComma != -1) extVers = extVers.replace(lastComma,1," and");
10536  msg(" with %s.\n",qPrint(extVers));
10537  }
10538  }
10539 }
10540 
10541 //----------------------------------------------------------------------------
10542 // print the usage of doxygen
10543 
10544 static void usage(const QCString &name,const QCString &versionString)
10545 {
10546  msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2021\n\n",qPrint(versionString));
10547  msg("You can use doxygen in a number of ways:\n\n");
10548  msg("1) Use doxygen to generate a template configuration file:\n");
10549  msg(" %s [-s] -g [configName]\n\n",qPrint(name));
10550  msg("2) Use doxygen to update an old configuration file:\n");
10551  msg(" %s [-s] -u [configName]\n\n",qPrint(name));
10552  msg("3) Use doxygen to generate documentation using an existing ");
10553  msg("configuration file:\n");
10554  msg(" %s [configName]\n\n",qPrint(name));
10555  msg("4) Use doxygen to generate a template file controlling the layout of the\n");
10556  msg(" generated documentation:\n");
10557  msg(" %s -l [layoutFileName]\n\n",qPrint(name));
10558  msg(" In case layoutFileName is omitted layoutFileName.xml will be used as filename.\n");
10559  msg(" If - is used for layoutFileName doxygen will write to standard output.\n\n");
10560  msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
10561  msg(" RTF: %s -w rtf styleSheetFile\n",qPrint(name));
10562  msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",qPrint(name));
10563  msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",qPrint(name));
10564  msg("6) Use doxygen to generate a rtf extensions file\n");
10565  msg(" %s -e rtf extensionsFile\n\n",qPrint(name));
10566  msg(" If - is used for extensionsFile doxygen will write to standard output.\n\n");
10567  msg("7) Use doxygen to compare the used configuration file with the template configuration file\n");
10568  msg(" %s -x [configFile]\n\n",qPrint(name));
10569  msg("8) Use doxygen to show a list of built-in emojis.\n");
10570  msg(" %s -f emoji outputFileName\n\n",qPrint(name));
10571  msg(" If - is used for outputFileName doxygen will write to standard output.\n\n");
10572  msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
10573  msg("If configName is omitted 'Doxyfile' will be used as a default.\n");
10574  msg("If - is used for configFile doxygen will write / read the configuration to /from standard output / input.\n\n");
10575  msg("If -q is used for a doxygen documentation run, doxygen will see this as if QUIET=YES has been set.\n\n");
10576  msg("-v print version string, -V print extended version information\n");
10577 }
10578 
10579 //----------------------------------------------------------------------------
10580 // read the argument of option 'c' from the comment argument list and
10581 // update the option index 'optInd'.
10582 
10583 static const char *getArg(int argc,char **argv,int &optInd)
10584 {
10585  char *s=0;
10586  if (qstrlen(&argv[optInd][2])>0)
10587  s=&argv[optInd][2];
10588  else if (optInd+1<argc && argv[optInd+1][0]!='-')
10589  s=argv[++optInd];
10590  return s;
10591 }
10592 
10593 //----------------------------------------------------------------------------
10594 
10595 /** @brief /dev/null outline parser */
10597 {
10598  public:
10599  void parseInput(const QCString &file, const char *buf,const std::shared_ptr<Entry> &, ClangTUParser*) {}
10600  bool needsPreprocessing(const QCString &) const { return FALSE; }
10601  void parsePrototype(const QCString &) {}
10602 };
10603 
10604 
10605 template<class T> std::function< std::unique_ptr<T>() > make_parser_factory()
10606 {
10607  return []() { return std::make_unique<T>(); };
10608 }
10609 
10611 {
10612  initResources();
10613  QCString lang = Portable::getenv("LC_ALL");
10614  if (!lang.isEmpty()) Portable::setenv("LANG",lang);
10615  std::setlocale(LC_ALL,"");
10616  std::setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
10617  std::setlocale(LC_NUMERIC,"C");
10618 
10620 
10622 
10624  Doxygen::parserManager = new ParserManager( make_parser_factory<NullOutlineParser>(),
10625  make_parser_factory<FileCodeParser>());
10626  Doxygen::parserManager->registerParser("c", make_parser_factory<COutlineParser>(),
10627  make_parser_factory<CCodeParser>());
10628  Doxygen::parserManager->registerParser("python", make_parser_factory<PythonOutlineParser>(),
10629  make_parser_factory<PythonCodeParser>());
10630  Doxygen::parserManager->registerParser("fortran", make_parser_factory<FortranOutlineParser>(),
10631  make_parser_factory<FortranCodeParser>());
10632  Doxygen::parserManager->registerParser("fortranfree", make_parser_factory<FortranOutlineParserFree>(),
10633  make_parser_factory<FortranCodeParserFree>());
10634  Doxygen::parserManager->registerParser("fortranfixed", make_parser_factory<FortranOutlineParserFixed>(),
10635  make_parser_factory<FortranCodeParserFixed>());
10636  Doxygen::parserManager->registerParser("vhdl", make_parser_factory<VHDLOutlineParser>(),
10637  make_parser_factory<VHDLCodeParser>());
10638  Doxygen::parserManager->registerParser("xml", make_parser_factory<NullOutlineParser>(),
10639  make_parser_factory<XMLCodeParser>());
10640  Doxygen::parserManager->registerParser("sql", make_parser_factory<NullOutlineParser>(),
10641  make_parser_factory<SQLCodeParser>());
10642  Doxygen::parserManager->registerParser("md", make_parser_factory<MarkdownOutlineParser>(),
10643  make_parser_factory<FileCodeParser>());
10644  Doxygen::parserManager->registerParser("lex", make_parser_factory<LexOutlineParser>(),
10645  make_parser_factory<LexCodeParser>());
10646 
10647  // register any additional parsers here...
10648 
10653 
10654 #ifdef USE_LIBCLANG
10656 #endif
10665  Doxygen::pageLinkedMap = new PageLinkedMap; // all doc pages
10666  Doxygen::exampleLinkedMap = new PageLinkedMap; // all examples
10667  //Doxygen::tagDestinationDict.setAutoDelete(TRUE);
10669 
10670  // initialisation of these globals depends on
10671  // configuration switches so we need to postpone these
10680 
10681  /**************************************************************************
10682  * Initialize some global constants
10683  **************************************************************************/
10684 
10685  g_compoundKeywords.insert("template class");
10686  g_compoundKeywords.insert("template struct");
10687  g_compoundKeywords.insert("class");
10688  g_compoundKeywords.insert("struct");
10689  g_compoundKeywords.insert("union");
10690  g_compoundKeywords.insert("interface");
10691  g_compoundKeywords.insert("exception");
10692 }
10693 
10695 {
10698 
10699  delete Doxygen::indexList;
10707  Doxygen::mainPage.reset();
10708  delete Doxygen::pageLinkedMap;
10710  delete Doxygen::globalScope;
10711  delete Doxygen::parserManager;
10712  delete theTranslator;
10713  delete g_outputList;
10715 
10718  delete Doxygen::groupLinkedMap;
10720  delete Doxygen::dirLinkedMap;
10721  delete Doxygen::symbolMap;
10722 
10724 }
10725 
10726 static int computeIdealCacheParam(size_t v)
10727 {
10728  //printf("computeIdealCacheParam(v=%u)\n",v);
10729 
10730  int r=0;
10731  while (v!=0) v>>=1,r++;
10732  // r = log2(v)
10733 
10734  // convert to a valid cache size value
10735  return std::max(0,std::min(r-16,9));
10736 }
10737 
10738 void readConfiguration(int argc, char **argv)
10739 {
10740  QCString versionString = getFullVersion();
10741 
10742  /**************************************************************************
10743  * Handle arguments *
10744  **************************************************************************/
10745 
10746  int optInd=1;
10747  QCString configName;
10748  QCString layoutName;
10749  QCString debugLabel;
10750  QCString formatName;
10751  QCString listName;
10752  bool genConfig=FALSE;
10753  bool shortList=FALSE;
10754  bool diffList=FALSE;
10755  bool updateConfig=FALSE;
10756  int retVal;
10757  bool quiet = false;
10758  while (optInd<argc && argv[optInd][0]=='-' &&
10759  (isalpha(argv[optInd][1]) || argv[optInd][1]=='?' ||
10760  argv[optInd][1]=='-')
10761  )
10762  {
10763  switch(argv[optInd][1])
10764  {
10765  case 'g':
10766  genConfig=TRUE;
10767  break;
10768  case 'l':
10769  if (optInd+1>=argc)
10770  {
10771  layoutName="DoxygenLayout.xml";
10772  }
10773  else
10774  {
10775  layoutName=argv[optInd+1];
10776  }
10777  writeDefaultLayoutFile(layoutName);
10778  cleanUpDoxygen();
10779  exit(0);
10780  break;
10781  case 'd':
10782  debugLabel=getArg(argc,argv,optInd);
10783  if (debugLabel.isEmpty())
10784  {
10785  devUsage();
10786  cleanUpDoxygen();
10787  exit(0);
10788  }
10789  retVal = Debug::setFlag(debugLabel);
10790  if (!retVal)
10791  {
10792  err("option \"-d\" has unknown debug specifier: \"%s\".\n",qPrint(debugLabel));
10793  devUsage();
10794  cleanUpDoxygen();
10795  exit(1);
10796  }
10797  break;
10798  case 'x':
10799  diffList=TRUE;
10800  break;
10801  case 's':
10802  shortList=TRUE;
10803  break;
10804  case 'u':
10805  updateConfig=TRUE;
10806  break;
10807  case 'e':
10808  formatName=getArg(argc,argv,optInd);
10809  if (formatName.isEmpty())
10810  {
10811  err("option \"-e\" is missing format specifier rtf.\n");
10812  cleanUpDoxygen();
10813  exit(1);
10814  }
10815  if (qstricmp(formatName.data(),"rtf")==0)
10816  {
10817  if (optInd+1>=argc)
10818  {
10819  err("option \"-e rtf\" is missing an extensions file name\n");
10820  cleanUpDoxygen();
10821  exit(1);
10822  }
10823  std::ofstream f;
10824  if (openOutputFile(argv[optInd+1],f))
10825  {
10826  TextStream t(&f);
10828  }
10829  cleanUpDoxygen();
10830  exit(0);
10831  }
10832  err("option \"-e\" has invalid format specifier.\n");
10833  cleanUpDoxygen();
10834  exit(1);
10835  break;
10836  case 'f':
10837  listName=getArg(argc,argv,optInd);
10838  if (listName.isEmpty())
10839  {
10840  err("option \"-f\" is missing list specifier.\n");
10841  cleanUpDoxygen();
10842  exit(1);
10843  }
10844  if (qstricmp(listName.data(),"emoji")==0)
10845  {
10846  if (optInd+1>=argc)
10847  {
10848  err("option \"-f emoji\" is missing an output file name\n");
10849  cleanUpDoxygen();
10850  exit(1);
10851  }
10852  std::ofstream f;
10853  if (openOutputFile(argv[optInd+1],f))
10854  {
10855  TextStream t(&f);
10857  }
10858  cleanUpDoxygen();
10859  exit(0);
10860  }
10861  err("option \"-f\" has invalid list specifier.\n");
10862  cleanUpDoxygen();
10863  exit(1);
10864  break;
10865  case 'w':
10866  formatName=getArg(argc,argv,optInd);
10867  if (formatName.isEmpty())
10868  {
10869  err("option \"-w\" is missing format specifier rtf, html or latex\n");
10870  cleanUpDoxygen();
10871  exit(1);
10872  }
10873  if (qstricmp(formatName.data(),"rtf")==0)
10874  {
10875  if (optInd+1>=argc)
10876  {
10877  err("option \"-w rtf\" is missing a style sheet file name\n");
10878  cleanUpDoxygen();
10879  exit(1);
10880  }
10881  std::ofstream f;
10882  if (openOutputFile(argv[optInd+1],f))
10883  {
10884  TextStream t(&f);
10886  }
10887  cleanUpDoxygen();
10888  exit(1);
10889  }
10890  else if (qstricmp(formatName.data(),"html")==0)
10891  {
10892  Config::init();
10893  if (optInd+4<argc || FileInfo("Doxyfile").exists())
10894  // explicit config file mentioned or default found on disk
10895  {
10896  QCString df = optInd+4<argc ? argv[optInd+4] : QCString("Doxyfile");
10897  if (!Config::parse(df)) // parse the config file
10898  {
10899  err("error opening or reading configuration file %s!\n",argv[optInd+4]);
10900  cleanUpDoxygen();
10901  exit(1);
10902  }
10903  }
10904  if (optInd+3>=argc)
10905  {
10906  err("option \"-w html\" does not have enough arguments\n");
10907  cleanUpDoxygen();
10908  exit(1);
10909  }
10913 
10914  setTranslator(Config_getEnum(OUTPUT_LANGUAGE));
10915 
10916  std::ofstream f;
10917  if (openOutputFile(argv[optInd+1],f))
10918  {
10919  TextStream t(&f);
10920  HtmlGenerator::writeHeaderFile(t, argv[optInd+3]);
10921  }
10922  f.close();
10923  if (openOutputFile(argv[optInd+2],f))
10924  {
10925  TextStream t(&f);
10927  }
10928  f.close();
10929  if (openOutputFile(argv[optInd+3],f))
10930  {
10931  TextStream t(&f);
10933  }
10934  cleanUpDoxygen();
10935  exit(0);
10936  }
10937  else if (qstricmp(formatName.data(),"latex")==0)
10938  {
10939  Config::init();
10940  if (optInd+4<argc || FileInfo("Doxyfile").exists())
10941  {
10942  QCString df = optInd+4<argc ? argv[optInd+4] : QCString("Doxyfile");
10943  if (!Config::parse(df))
10944  {
10945  err("error opening or reading configuration file %s!\n",argv[optInd+4]);
10946  cleanUpDoxygen();
10947  exit(1);
10948  }
10949  }
10950  if (optInd+3>=argc)
10951  {
10952  err("option \"-w latex\" does not have enough arguments\n");
10953  cleanUpDoxygen();
10954  exit(1);
10955  }
10959 
10960  setTranslator(Config_getEnum(OUTPUT_LANGUAGE));
10961 
10962  std::ofstream f;
10963  if (openOutputFile(argv[optInd+1],f))
10964  {
10965  TextStream t(&f);
10967  }
10968  f.close();
10969  if (openOutputFile(argv[optInd+2],f))
10970  {
10971  TextStream t(&f);
10973  }
10974  f.close();
10975  if (openOutputFile(argv[optInd+3],f))
10976  {
10977  TextStream t(&f);
10979  }
10980  cleanUpDoxygen();
10981  exit(0);
10982  }
10983  else
10984  {
10985  err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",qPrint(formatName));
10986  cleanUpDoxygen();
10987  exit(1);
10988  }
10989  break;
10990  case 'm':
10992  break;
10993  case 'v':
10994  version(false);
10995  cleanUpDoxygen();
10996  exit(0);
10997  break;
10998  case 'V':
10999  version(true);
11000  cleanUpDoxygen();
11001  exit(0);
11002  break;
11003  case '-':
11004  if (qstrcmp(&argv[optInd][2],"help")==0)
11005  {
11006  usage(argv[0],versionString);
11007  exit(0);
11008  }
11009  else if (qstrcmp(&argv[optInd][2],"version")==0)
11010  {
11011  version(false);
11012  cleanUpDoxygen();
11013  exit(0);
11014  }
11015  else if ((qstrcmp(&argv[optInd][2],"Version")==0) ||
11016  (qstrcmp(&argv[optInd][2],"VERSION")==0))
11017  {
11018  version(true);
11019  cleanUpDoxygen();
11020  exit(0);
11021  }
11022  else
11023  {
11024  err("Unknown option \"-%s\"\n",&argv[optInd][1]);
11025  usage(argv[0],versionString);
11026  exit(1);
11027  }
11028  break;
11029  case 'b':
11030  setvbuf(stdout,NULL,_IONBF,0);
11031  break;
11032  case 'q':
11033  quiet = true;
11034  break;
11035  case 'T':
11036  msg("Warning: this option activates output generation via Django like template files. "
11037  "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
11038  "Only use if you are a doxygen developer\n");
11040  break;
11041  case 'h':
11042  case '?':
11043  usage(argv[0],versionString);
11044  exit(0);
11045  break;
11046  default:
11047  err("Unknown option \"-%c\"\n",argv[optInd][1]);
11048  usage(argv[0],versionString);
11049  exit(1);
11050  }
11051  optInd++;
11052  }
11053 
11054  /**************************************************************************
11055  * Parse or generate the config file *
11056  **************************************************************************/
11057 
11058  Config::init();
11059 
11060  FileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
11061  if (optInd>=argc)
11062  {
11063  if (configFileInfo1.exists())
11064  {
11065  configName="Doxyfile";
11066  }
11067  else if (configFileInfo2.exists())
11068  {
11069  configName="doxyfile";
11070  }
11071  else if (genConfig)
11072  {
11073  configName="Doxyfile";
11074  }
11075  else
11076  {
11077  err("Doxyfile not found and no input file specified!\n");
11078  usage(argv[0],versionString);
11079  exit(1);
11080  }
11081  }
11082  else
11083  {
11084  FileInfo fi(argv[optInd]);
11085  if (fi.exists() || qstrcmp(argv[optInd],"-")==0 || genConfig)
11086  {
11087  configName=argv[optInd];
11088  }
11089  else
11090  {
11091  err("configuration file %s not found!\n",argv[optInd]);
11092  usage(argv[0],versionString);
11093  exit(1);
11094  }
11095  }
11096 
11097  if (genConfig && g_useOutputTemplate)
11098  {
11099  generateTemplateFiles("templates");
11100  cleanUpDoxygen();
11101  exit(0);
11102  }
11103 
11104  if (genConfig)
11105  {
11106  generateConfigFile(configName,shortList);
11107  cleanUpDoxygen();
11108  exit(0);
11109  }
11110 
11111  if (!Config::parse(configName,updateConfig))
11112  {
11113  err("could not open or read configuration file %s!\n",qPrint(configName));
11114  cleanUpDoxygen();
11115  exit(1);
11116  }
11117 
11118  if (diffList)
11119  {
11121  compareDoxyfile();
11122  cleanUpDoxygen();
11123  exit(0);
11124  }
11125 
11126  if (updateConfig)
11127  {
11129  generateConfigFile(configName,shortList,TRUE);
11130  cleanUpDoxygen();
11131  exit(0);
11132  }
11133 
11134  /* Perlmod wants to know the path to the config file.*/
11135  FileInfo configFileInfo(configName.str());
11136  setPerlModDoxyfile(configFileInfo.absFilePath());
11137 
11138  /* handle -q option */
11139  if (quiet) Config_updateBool(QUIET,TRUE);
11140 }
11141 
11142 /** check and resolve config options */
11144 {
11145 
11150 }
11151 
11152 /** adjust globals that depend on configuration settings. */
11154 {
11155  Doxygen::globalScope = createNamespaceDef("<globalScope>",1,1,"<globalScope>");
11163 
11164  setTranslator(Config_getEnum(OUTPUT_LANGUAGE));
11165 
11166  /* Set the global html file extension. */
11167  Doxygen::htmlFileExtension = Config_getString(HTML_FILE_EXTENSION);
11168 
11169 
11171  Config_getBool(CALLER_GRAPH) ||
11172  Config_getBool(REFERENCES_RELATION) ||
11173  Config_getBool(REFERENCED_BY_RELATION);
11174 
11175  /**************************************************************************
11176  * Add custom extension mappings
11177  **************************************************************************/
11178 
11179  const StringVector &extMaps = Config_getList(EXTENSION_MAPPING);
11180  for (const auto &mapping : extMaps)
11181  {
11182  QCString mapStr = mapping.c_str();
11183  int i=mapStr.find('=');
11184  if (i==-1)
11185  {
11186  continue;
11187  }
11188  else
11189  {
11190  QCString ext = mapStr.left(i).stripWhiteSpace().lower();
11191  QCString language = mapStr.mid(i+1).stripWhiteSpace().lower();
11192  if (ext.isEmpty() || language.isEmpty())
11193  {
11194  continue;
11195  }
11196 
11197  if (!updateLanguageMapping(ext,language))
11198  {
11199  err("Failed to map file extension '%s' to unsupported language '%s'.\n"
11200  "Check the EXTENSION_MAPPING setting in the config file.\n",
11201  qPrint(ext),qPrint(language));
11202  }
11203  else
11204  {
11205  msg("Adding custom extension mapping: '%s' will be treated as language '%s'\n",
11206  qPrint(ext),qPrint(language));
11207  }
11208  }
11209  }
11210 
11211  // add predefined macro name to a dictionary
11212  const StringVector &expandAsDefinedList =Config_getList(EXPAND_AS_DEFINED);
11213  for (const auto &s : expandAsDefinedList)
11214  {
11215  Doxygen::expandAsDefinedSet.insert(s.c_str());
11216  }
11217 
11218  // read aliases and store them in a dictionary
11219  readAliases();
11220 
11221  // store number of spaces in a tab into Doxygen::spaces
11222  int tabSize = Config_getInt(TAB_SIZE);
11223  Doxygen::spaces.resize(tabSize+1);
11224  int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
11225  Doxygen::spaces.at(tabSize)='\0';
11226 }
11227 
11228 #ifdef HAS_SIGNALS
11229 static void stopDoxygen(int)
11230 {
11231  signal(SIGINT,SIG_DFL); // Re-register signal handler for default action
11232  Dir thisDir;
11233  msg("Cleaning up...\n");
11234  if (!Doxygen::filterDBFileName.isEmpty())
11235  {
11236  thisDir.remove(Doxygen::filterDBFileName.str());
11237  }
11238  killpg(0,SIGINT);
11239  cleanUpDoxygen();
11240  exit(1);
11241 }
11242 #endif
11243 
11244 static void writeTagFile()
11245 {
11246  QCString generateTagFile = Config_getString(GENERATE_TAGFILE);
11247  if (generateTagFile.isEmpty()) return;
11248 
11249  std::ofstream f(generateTagFile.str(),std::ofstream::out | std::ofstream::binary);
11250  if (!f.is_open())
11251  {
11252  err("cannot open tag file %s for writing\n",
11253  qPrint(generateTagFile)
11254  );
11255  return;
11256  }
11257  TextStream tagFile(&f);
11258  tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>\n";
11259  tagFile << "<tagfile doxygen_version=\"" << getDoxygenVersion() << "\"";
11260  if (strlen(getGitVersion())>0)
11261  {
11262  tagFile << " doxygen_gitid=\"" << getGitVersion() << "\"";
11263  }
11264  tagFile << ">\n";
11265 
11266  // for each file
11267  for (const auto &fn : *Doxygen::inputNameLinkedMap)
11268  {
11269  for (const auto &fd : *fn)
11270  {
11271  if (fd->isLinkableInProject()) fd->writeTagFile(tagFile);
11272  }
11273  }
11274  // for each class
11275  for (const auto &cd : *Doxygen::classLinkedMap)
11276  {
11277  ClassDefMutable *cdm = toClassDefMutable(cd.get());
11278  if (cdm && cdm->isLinkableInProject())
11279  {
11280  cdm->writeTagFile(tagFile);
11281  }
11282  }
11283  // for each concept
11284  for (const auto &cd : *Doxygen::conceptLinkedMap)
11285  {
11286  ConceptDefMutable *cdm = toConceptDefMutable(cd.get());
11287  if (cdm && cdm->isLinkableInProject())
11288  {
11289  cdm->writeTagFile(tagFile);
11290  }
11291  }
11292  // for each namespace
11293  for (const auto &nd : *Doxygen::namespaceLinkedMap)
11294  {
11295  NamespaceDefMutable *ndm = toNamespaceDefMutable(nd.get());
11296  if (ndm && nd->isLinkableInProject())
11297  {
11298  ndm->writeTagFile(tagFile);
11299  }
11300  }
11301  // for each group
11302  for (const auto &gd : *Doxygen::groupLinkedMap)
11303  {
11304  if (gd->isLinkableInProject()) gd->writeTagFile(tagFile);
11305  }
11306  // for each page
11307  for (const auto &pd : *Doxygen::pageLinkedMap)
11308  {
11309  if (pd->isLinkableInProject()) pd->writeTagFile(tagFile);
11310  }
11311  if (Doxygen::mainPage) Doxygen::mainPage->writeTagFile(tagFile);
11312 
11313  tagFile << "</tagfile>\n";
11314 }
11315 
11316 static void exitDoxygen()
11317 {
11318  if (!g_successfulRun) // premature exit
11319  {
11320  Dir thisDir;
11321  msg("Exiting...\n");
11322  if (!Doxygen::filterDBFileName.isEmpty())
11323  {
11324  thisDir.remove(Doxygen::filterDBFileName.str());
11325  }
11326  }
11327 }
11328 
11329 static QCString createOutputDirectory(const QCString &baseDirName,
11330  const QCString &formatDirName,
11331  const char *defaultDirName)
11332 {
11333  QCString result = formatDirName;
11334  if (result.isEmpty())
11335  {
11336  result = baseDirName + defaultDirName;
11337  }
11338  else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
11339  {
11340  result.prepend(baseDirName+"/");
11341  }
11342  Dir formatDir(result.str());
11343  if (!formatDir.exists() && !formatDir.mkdir(result.str()))
11344  {
11345  err("Could not create output directory %s\n", qPrint(result));
11346  cleanUpDoxygen();
11347  exit(1);
11348  }
11349  return result;
11350 }
11351 
11353 {
11354  QCString const & qchFile = Config_getString(QCH_FILE);
11355  if (!qchFile.isEmpty())
11356  {
11357  return qchFile;
11358  }
11359 
11360  QCString const & projectName = Config_getString(PROJECT_NAME);
11361  QCString const & versionText = Config_getString(PROJECT_NUMBER);
11362 
11363  return QCString("../qch/")
11364  + (projectName.isEmpty() ? QCString("index") : projectName)
11365  + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
11366  + QCString(".qch");
11367 }
11368 
11370 {
11371  StringUnorderedSet killSet;
11372 
11373  const StringVector &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
11374  bool alwaysRecursive = Config_getBool(RECURSIVE);
11375  StringUnorderedSet excludeNameSet;
11376 
11377  // gather names of all files in the include path
11378  g_s.begin("Searching for include files...\n");
11379  killSet.clear();
11380  const StringVector &includePathList = Config_getList(INCLUDE_PATH);
11381  for (const auto &s : includePathList)
11382  {
11383  size_t plSize = Config_getList(INCLUDE_FILE_PATTERNS).size();
11384  const StringVector &pl = plSize==0 ? Config_getList(FILE_PATTERNS) :
11385  Config_getList(INCLUDE_FILE_PATTERNS);
11386  readFileOrDirectory(s.c_str(), // s
11388  0, // exclSet
11389  &pl, // patList
11390  &exclPatterns, // exclPatList
11391  0, // resultList
11392  0, // resultSet
11393  alwaysRecursive, // recursive
11394  TRUE, // errorIfNotExist
11395  &killSet); // killSet
11396  }
11397  g_s.end();
11398 
11399  g_s.begin("Searching for example files...\n");
11400  killSet.clear();
11401  const StringVector &examplePathList = Config_getList(EXAMPLE_PATH);
11402  for (const auto &s : examplePathList)
11403  {
11404  readFileOrDirectory(s.c_str(), // s
11406  0, // exclSet
11407  &Config_getList(EXAMPLE_PATTERNS), // patList
11408  0, // exclPatList
11409  0, // resultList
11410  0, // resultSet
11411  (alwaysRecursive || Config_getBool(EXAMPLE_RECURSIVE)), // recursive
11412  TRUE, // errorIfNotExist
11413  &killSet); // killSet
11414  }
11415  g_s.end();
11416 
11417  g_s.begin("Searching for images...\n");
11418  killSet.clear();
11419  const StringVector &imagePathList=Config_getList(IMAGE_PATH);
11420  for (const auto &s : imagePathList)
11421  {
11422  readFileOrDirectory(s.c_str(), // s
11423  Doxygen::imageNameLinkedMap, // fnDict
11424  0, // exclSet
11425  0, // patList
11426  0, // exclPatList
11427  0, // resultList
11428  0, // resultSet
11429  alwaysRecursive, // recursive
11430  TRUE, // errorIfNotExist
11431  &killSet); // killSet
11432  }
11433  g_s.end();
11434 
11435  g_s.begin("Searching for dot files...\n");
11436  killSet.clear();
11437  const StringVector &dotFileList=Config_getList(DOTFILE_DIRS);
11438  for (const auto &s : dotFileList)
11439  {
11440  readFileOrDirectory(s.c_str(), // s
11442  0, // exclSet
11443  0, // patList
11444  0, // exclPatList
11445  0, // resultList
11446  0, // resultSet
11447  alwaysRecursive, // recursive
11448  TRUE, // errorIfNotExist
11449  &killSet); // killSet
11450  }
11451  g_s.end();
11452 
11453  g_s.begin("Searching for msc files...\n");
11454  killSet.clear();
11455  const StringVector &mscFileList=Config_getList(MSCFILE_DIRS);
11456  for (const auto &s : mscFileList)
11457  {
11458  readFileOrDirectory(s.c_str(), // s
11460  0, // exclSet
11461  0, // patList
11462  0, // exclPatList
11463  0, // resultList
11464  0, // resultSet
11465  alwaysRecursive, // recursive
11466  TRUE, // errorIfNotExist
11467  &killSet); // killSet
11468  }
11469  g_s.end();
11470 
11471  g_s.begin("Searching for dia files...\n");
11472  killSet.clear();
11473  const StringVector &diaFileList=Config_getList(DIAFILE_DIRS);
11474  for (const auto &s : diaFileList)
11475  {
11476  readFileOrDirectory(s.c_str(), // s
11478  0, // exclSet
11479  0, // patList
11480  0, // exclPatList
11481  0, // resultList
11482  0, // resultSet
11483  alwaysRecursive, // recursive
11484  TRUE, // errorIfNotExist
11485  &killSet); // killSet
11486  }
11487  g_s.end();
11488 
11489  g_s.begin("Searching for files to exclude\n");
11490  const StringVector &excludeList = Config_getList(EXCLUDE);
11491  for (const auto &s : excludeList)
11492  {
11493  readFileOrDirectory(s.c_str(), // s
11494  0, // fnDict
11495  0, // exclSet
11496  &Config_getList(FILE_PATTERNS), // patList
11497  0, // exclPatList
11498  0, // resultList
11499  &excludeNameSet, // resultSet
11500  alwaysRecursive, // recursive
11501  FALSE); // errorIfNotExist
11502  }
11503  g_s.end();
11504 
11505  /**************************************************************************
11506  * Determine Input Files *
11507  **************************************************************************/
11508 
11509  g_s.begin("Searching INPUT for files to process...\n");
11510  killSet.clear();
11511  Doxygen::inputPaths.clear();
11512  const StringVector &inputList=Config_getList(INPUT);
11513  for (const auto &s : inputList)
11514  {
11515  QCString path=s.c_str();
11516  uint l = path.length();
11517  if (l>0)
11518  {
11519  // strip trailing slashes
11520  if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
11521 
11523  path, // s
11524  Doxygen::inputNameLinkedMap, // fnDict
11525  &excludeNameSet, // exclSet
11526  &Config_getList(FILE_PATTERNS), // patList
11527  &exclPatterns, // exclPatList
11528  &g_inputFiles, // resultList
11529  0, // resultSet
11530  alwaysRecursive, // recursive
11531  TRUE, // errorIfNotExist
11532  &killSet, // killSet
11533  &Doxygen::inputPaths); // paths
11534  }
11535  }
11536 
11537  // Sort the FileDef objects by full path to get a predictable ordering over multiple runs
11538  std::sort(Doxygen::inputNameLinkedMap->begin(),
11540  [](const auto &f1,const auto &f2)
11541  {
11542  return qstricmp(f1->fullName(),f2->fullName())<0;
11543  });
11544  for (auto &fileName : *Doxygen::inputNameLinkedMap)
11545  {
11546  if (fileName->size()>1)
11547  {
11548  std::sort(fileName->begin(),fileName->end(),[](const auto &f1,const auto &f2)
11549  {
11550  return qstricmp(f1->absFilePath(),f2->absFilePath())<0;
11551  });
11552  }
11553  }
11554  g_s.end();
11555 }
11556 
11557 
11559 {
11560  atexit(exitDoxygen);
11561 
11562 #if USE_LIBCLANG
11563  Doxygen::clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
11564 #endif
11565 
11566  // we would like to show the versionString earlier, but we first have to handle the configuration file
11567  // to know the value of the QUIET setting.
11568  QCString versionString = getFullVersion();
11569  msg("Doxygen version used: %s\n",qPrint(versionString));
11570 
11571  /**************************************************************************
11572  * Make sure the output directory exists
11573  **************************************************************************/
11574  QCString outputDirectory = Config_getString(OUTPUT_DIRECTORY);
11575  if (outputDirectory.isEmpty())
11576  {
11577  outputDirectory = Config_updateString(OUTPUT_DIRECTORY,Dir::currentDirPath().c_str());
11578  }
11579  else
11580  {
11581  Dir dir(outputDirectory.str());
11582  if (!dir.exists())
11583  {
11585  if (!dir.mkdir(outputDirectory.str()))
11586  {
11587  err("tag OUTPUT_DIRECTORY: Output directory '%s' does not "
11588  "exist and cannot be created\n",qPrint(outputDirectory));
11589  cleanUpDoxygen();
11590  exit(1);
11591  }
11592  else
11593  {
11594  msg("Notice: Output directory '%s' does not exist. "
11595  "I have created it for you.\n", qPrint(outputDirectory));
11596  }
11597  dir.setPath(outputDirectory.str());
11598  }
11599  outputDirectory = Config_updateString(OUTPUT_DIRECTORY,dir.absPath().c_str());
11600  }
11601 
11602  /**************************************************************************
11603  * Initialize global lists and dictionaries
11604  **************************************************************************/
11605 
11606  // also scale lookup cache with SYMBOL_CACHE_SIZE
11607  int cacheSize = Config_getInt(LOOKUP_CACHE_SIZE);
11608  if (cacheSize<0) cacheSize=0;
11609  if (cacheSize>9) cacheSize=9;
11610  uint lookupSize = 65536 << cacheSize;
11612 
11613 #ifdef HAS_SIGNALS
11614  signal(SIGINT, stopDoxygen);
11615 #endif
11616 
11617  uint pid = Portable::pid();
11618  Doxygen::filterDBFileName.sprintf("doxygen_filterdb_%d.tmp",pid);
11619  Doxygen::filterDBFileName.prepend(outputDirectory+"/");
11620 
11621  /**************************************************************************
11622  * Check/create output directories *
11623  **************************************************************************/
11624 
11625  QCString htmlOutput;
11626  bool generateHtml = Config_getBool(GENERATE_HTML);
11627  if (generateHtml || g_useOutputTemplate /* TODO: temp hack */)
11628  {
11629  htmlOutput = createOutputDirectory(outputDirectory,Config_getString(HTML_OUTPUT),"/html");
11630  Config_updateString(HTML_OUTPUT,htmlOutput);
11631 
11632  // add HTML indexers that are enabled
11633  bool generateHtmlHelp = Config_getBool(GENERATE_HTMLHELP);
11634  bool generateEclipseHelp = Config_getBool(GENERATE_ECLIPSEHELP);
11635  bool generateQhp = Config_getBool(GENERATE_QHP);
11636  bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
11637  bool generateDocSet = Config_getBool(GENERATE_DOCSET);
11638  if (generateEclipseHelp) Doxygen::indexList->addIndex<EclipseHelp>();
11639  if (generateHtmlHelp) Doxygen::indexList->addIndex<HtmlHelp>();
11640  if (generateQhp) Doxygen::indexList->addIndex<Qhp>();
11641  if (generateTreeView) Doxygen::indexList->addIndex<FTVHelp>(TRUE);
11642  if (generateDocSet) Doxygen::indexList->addIndex<DocSets>();
11644  }
11645 
11646  QCString docbookOutput;
11647  bool generateDocbook = Config_getBool(GENERATE_DOCBOOK);
11648  if (generateDocbook)
11649  {
11650  docbookOutput = createOutputDirectory(outputDirectory,Config_getString(DOCBOOK_OUTPUT),"/docbook");
11651  Config_updateString(DOCBOOK_OUTPUT,docbookOutput);
11652  }
11653 
11654  QCString xmlOutput;
11655  bool generateXml = Config_getBool(GENERATE_XML);
11656  if (generateXml)
11657  {
11658  xmlOutput = createOutputDirectory(outputDirectory,Config_getString(XML_OUTPUT),"/xml");
11659  Config_updateString(XML_OUTPUT,xmlOutput);
11660  }
11661 
11662  QCString latexOutput;
11663  bool generateLatex = Config_getBool(GENERATE_LATEX);
11664  if (generateLatex)
11665  {
11666  latexOutput = createOutputDirectory(outputDirectory,Config_getString(LATEX_OUTPUT), "/latex");
11667  Config_updateString(LATEX_OUTPUT,latexOutput);
11668  }
11669 
11670  QCString rtfOutput;
11671  bool generateRtf = Config_getBool(GENERATE_RTF);
11672  if (generateRtf)
11673  {
11674  rtfOutput = createOutputDirectory(outputDirectory,Config_getString(RTF_OUTPUT),"/rtf");
11675  Config_updateString(RTF_OUTPUT,rtfOutput);
11676  }
11677 
11678  QCString manOutput;
11679  bool generateMan = Config_getBool(GENERATE_MAN);
11680  if (generateMan)
11681  {
11682  manOutput = createOutputDirectory(outputDirectory,Config_getString(MAN_OUTPUT),"/man");
11683  Config_updateString(MAN_OUTPUT,manOutput);
11684  }
11685 
11686 #if USE_SQLITE3
11687  QCString sqlOutput;
11688  bool generateSql = Config_getBool(GENERATE_SQLITE3);
11689  if (generateSql)
11690  {
11691  sqlOutput = createOutputDirectory(outputDirectory,Config_getString(SQLITE3_OUTPUT),"/sqlite3");
11692  Config_updateString(SQLITE3_OUTPUT,sqlOutput);
11693  }
11694 #endif
11695 
11696  if (Config_getBool(HAVE_DOT))
11697  {
11698  QCString curFontPath = Config_getString(DOT_FONTPATH);
11699  if (curFontPath.isEmpty())
11700  {
11701  Portable::getenv("DOTFONTPATH");
11702  QCString newFontPath = ".";
11703  if (!curFontPath.isEmpty())
11704  {
11705  newFontPath+=Portable::pathListSeparator();
11706  newFontPath+=curFontPath;
11707  }
11708  Portable::setenv("DOTFONTPATH",qPrint(newFontPath));
11709  }
11710  else
11711  {
11712  Portable::setenv("DOTFONTPATH",qPrint(curFontPath));
11713  }
11714  }
11715 
11716 
11717 
11718  /**************************************************************************
11719  * Handle layout file *
11720  **************************************************************************/
11721 
11723  QCString layoutFileName = Config_getString(LAYOUT_FILE);
11724  bool defaultLayoutUsed = FALSE;
11725  if (layoutFileName.isEmpty())
11726  {
11727  layoutFileName = Config_updateString(LAYOUT_FILE,"DoxygenLayout.xml");
11728  defaultLayoutUsed = TRUE;
11729  }
11730 
11731  FileInfo fi(layoutFileName.str());
11732  if (fi.exists())
11733  {
11734  msg("Parsing layout file %s...\n",qPrint(layoutFileName));
11735  LayoutDocManager::instance().parse(layoutFileName);
11736  }
11737  else if (!defaultLayoutUsed)
11738  {
11739  warn_uncond("failed to open layout file '%s' for reading!\n",qPrint(layoutFileName));
11740  }
11741 
11742  /**************************************************************************
11743  * Read and preprocess input *
11744  **************************************************************************/
11745 
11746  // prevent search in the output directories
11747  StringVector exclPatterns = Config_getList(EXCLUDE_PATTERNS);
11748  if (generateHtml) exclPatterns.push_back(htmlOutput.str());
11749  if (generateDocbook) exclPatterns.push_back(docbookOutput.str());
11750  if (generateXml) exclPatterns.push_back(xmlOutput.str());
11751  if (generateLatex) exclPatterns.push_back(latexOutput.str());
11752  if (generateRtf) exclPatterns.push_back(rtfOutput.str());
11753  if (generateMan) exclPatterns.push_back(manOutput.str());
11754  Config_updateList(EXCLUDE_PATTERNS,exclPatterns);
11755 
11756  searchInputFiles();
11757 
11758  // Notice: the order of the function calls below is very important!
11759 
11760  if (Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX))
11761  {
11763  }
11764  if (Config_getBool(GENERATE_RTF))
11765  {
11766  // in case GENERRATE_HTML is set we just have to compare, both repositories should be identical
11768  Config_getBool(GENERATE_HTML) &&
11769  !Config_getBool(USE_MATHJAX));
11770  }
11771  if (Config_getBool(GENERATE_DOCBOOK))
11772  {
11773  // in case GENERRATE_HTML is set we just have to compare, both repositories should be identical
11775  (Config_getBool(GENERATE_HTML) &&
11776  !Config_getBool(USE_MATHJAX)) ||
11777  Config_getBool(GENERATE_RTF));
11778  }
11779 
11780  /**************************************************************************
11781  * Handle Tag Files *
11782  **************************************************************************/
11783 
11784  std::shared_ptr<Entry> root = std::make_shared<Entry>();
11785  msg("Reading and parsing tag files\n");
11786 
11787  const StringVector &tagFileList = Config_getList(TAGFILES);
11788  for (const auto &s : tagFileList)
11789  {
11790  readTagFile(root,s.c_str());
11791  }
11792 
11793  /**************************************************************************
11794  * Parse source files *
11795  **************************************************************************/
11796 
11797  addSTLSupport(root);
11798 
11799  g_s.begin("Parsing files\n");
11800  if (Config_getInt(NUM_PROC_THREADS)==1)
11801  {
11803  }
11804  else
11805  {
11807  }
11808  g_s.end();
11809 
11810  /**************************************************************************
11811  * Gather information *
11812  **************************************************************************/
11813 
11814  g_s.begin("Building macro definition list...\n");
11815  buildDefineList();
11816  g_s.end();
11817 
11818  g_s.begin("Building group list...\n");
11819  buildGroupList(root.get());
11820  organizeSubGroups(root.get());
11821  g_s.end();
11822 
11823  g_s.begin("Building directory list...\n");
11824  buildDirectories();
11825  findDirDocumentation(root.get());
11826  g_s.end();
11827 
11828  g_s.begin("Building namespace list...\n");
11829  buildNamespaceList(root.get());
11830  findUsingDirectives(root.get());
11831  g_s.end();
11832 
11833  g_s.begin("Building file list...\n");
11834  buildFileList(root.get());
11835  g_s.end();
11836 
11837  g_s.begin("Building class list...\n");
11838  buildClassList(root.get());
11839  g_s.end();
11840 
11841  g_s.begin("Building concept list...\n");
11842  buildConceptList(root.get());
11843  g_s.end();
11844 
11845  // build list of using declarations here (global list)
11846  buildListOfUsingDecls(root.get());
11847  g_s.end();
11848 
11849  g_s.begin("Computing nesting relations for classes...\n");
11851  g_s.end();
11852  // 1.8.2-20121111: no longer add nested classes to the group as well
11853  //distributeClassGroupRelations();
11854 
11855  // calling buildClassList may result in cached relations that
11856  // become invalid after resolveClassNestingRelations(), that's why
11857  // we need to clear the cache here
11859  // we don't need the list of using declaration anymore
11860  g_usingDeclarations.clear();
11861 
11862  g_s.begin("Associating documentation with classes...\n");
11863  buildClassDocList(root.get());
11864  g_s.end();
11865 
11866  g_s.begin("Associating documentation with concepts...\n");
11867  buildConceptDocList(root.get());
11868  g_s.end();
11869 
11870  g_s.begin("Building example list...\n");
11871  buildExampleList(root.get());
11872  g_s.end();
11873 
11874  g_s.begin("Searching for enumerations...\n");
11875  findEnums(root.get());
11876  g_s.end();
11877 
11878  // Since buildVarList calls isVarWithConstructor
11879  // and this calls getResolvedClass we need to process
11880  // typedefs first so the relations between classes via typedefs
11881  // are properly resolved. See bug 536385 for an example.
11882  g_s.begin("Searching for documented typedefs...\n");
11883  buildTypedefList(root.get());
11884  g_s.end();
11885 
11886  if (Config_getBool(OPTIMIZE_OUTPUT_SLICE))
11887  {
11888  g_s.begin("Searching for documented sequences...\n");
11889  buildSequenceList(root.get());
11890  g_s.end();
11891 
11892  g_s.begin("Searching for documented dictionaries...\n");
11893  buildDictionaryList(root.get());
11894  g_s.end();
11895  }
11896 
11897  g_s.begin("Searching for members imported via using declarations...\n");
11898  // this should be after buildTypedefList in order to properly import
11899  // used typedefs
11900  findUsingDeclarations(root.get(),TRUE); // do for python packages first
11901  findUsingDeclarations(root.get(),FALSE); // then the rest
11902  g_s.end();
11903 
11904  g_s.begin("Searching for included using directives...\n");
11906  g_s.end();
11907 
11908  g_s.begin("Searching for documented variables...\n");
11909  buildVarList(root.get());
11910  g_s.end();
11911 
11912  g_s.begin("Building interface member list...\n");
11913  buildInterfaceAndServiceList(root.get()); // UNO IDL
11914 
11915  g_s.begin("Building member list...\n"); // using class info only !
11916  buildFunctionList(root.get());
11917  g_s.end();
11918 
11919  g_s.begin("Searching for friends...\n");
11920  findFriends();
11921  g_s.end();
11922 
11923  g_s.begin("Searching for documented defines...\n");
11924  findDefineDocumentation(root.get());
11925  g_s.end();
11926 
11927  g_s.begin("Computing class inheritance relations...\n");
11928  findClassEntries(root.get());
11930  g_s.end();
11931 
11932  g_s.begin("Computing class usage relations...\n");
11934  g_s.end();
11935 
11936  if (Config_getBool(INLINE_SIMPLE_STRUCTS))
11937  {
11938  g_s.begin("Searching for tag less structs...\n");
11940  g_s.end();
11941  }
11942 
11943  g_s.begin("Flushing cached template relations that have become invalid...\n");
11945  g_s.end();
11946 
11947  g_s.begin("Computing class relations...\n");
11950  if (Config_getBool(OPTIMIZE_OUTPUT_VHDL))
11951  {
11953  }
11955  g_classEntries.clear();
11956  g_s.end();
11957 
11958  g_s.begin("Add enum values to enums...\n");
11959  addEnumValuesToEnums(root.get());
11960  findEnumDocumentation(root.get());
11961  g_s.end();
11962 
11963  g_s.begin("Searching for member function documentation...\n");
11964  findObjCMethodDefinitions(root.get());
11965  findMemberDocumentation(root.get()); // may introduce new members !
11966  findUsingDeclImports(root.get()); // may introduce new members !
11967 
11970  g_s.end();
11971 
11972  // moved to after finding and copying documentation,
11973  // as this introduces new members see bug 722654
11974  g_s.begin("Creating members for template instances...\n");
11976  g_s.end();
11977 
11978  g_s.begin("Building page list...\n");
11979  buildPageList(root.get());
11980  g_s.end();
11981 
11982  g_s.begin("Search for main page...\n");
11983  findMainPage(root.get());
11984  findMainPageTagFiles(root.get());
11985  g_s.end();
11986 
11987  g_s.begin("Computing page relations...\n");
11988  computePageRelations(root.get());
11990  g_s.end();
11991 
11992  g_s.begin("Determining the scope of groups...\n");
11993  findGroupScope(root.get());
11994  g_s.end();
11995 
11996  auto memberNameComp = [](const MemberNameLinkedMap::Ptr &n1,const MemberNameLinkedMap::Ptr &n2)
11997  {
11998  return qstricmp(n1->memberName().data()+getPrefixIndex(n1->memberName()),
11999  n2->memberName().data()+getPrefixIndex(n2->memberName())
12000  )<0;
12001  };
12002 
12003  auto classComp = [](const ClassLinkedMap::Ptr &c1,const ClassLinkedMap::Ptr &c2)
12004  {
12005  if (Config_getBool(SORT_BY_SCOPE_NAME))
12006  {
12007  return qstricmp(c1->name(), c2->name())<0;
12008  }
12009  else
12010  {
12011  int i = qstricmp(c1->className(), c2->className());
12012  return i==0 ? qstricmp(c1->name(), c2->name())<0 : i<0;
12013  }
12014  };
12015 
12016  auto namespaceComp = [](const NamespaceLinkedMap::Ptr &n1,const NamespaceLinkedMap::Ptr &n2)
12017  {
12018  return qstricmp(n1->name(),n2->name())<0;
12019  };
12020 
12021  auto conceptComp = [](const ConceptLinkedMap::Ptr &c1,const ConceptLinkedMap::Ptr &c2)
12022  {
12023  return qstricmp(c1->name(),c2->name())<0;
12024  };
12025 
12026  g_s.begin("Sorting lists...\n");
12027  std::sort(Doxygen::memberNameLinkedMap->begin(),
12029  memberNameComp);
12032  memberNameComp);
12033  std::sort(Doxygen::hiddenClassLinkedMap->begin(),
12035  classComp);
12036  std::sort(Doxygen::classLinkedMap->begin(),
12038  classComp);
12039  std::sort(Doxygen::conceptLinkedMap->begin(),
12041  conceptComp);
12042  std::sort(Doxygen::namespaceLinkedMap->begin(),
12044  namespaceComp);
12045  g_s.end();
12046 
12047  g_s.begin("Determining which enums are documented\n");
12049  g_s.end();
12050 
12051  g_s.begin("Computing member relations...\n");
12052  mergeCategories();
12054  g_s.end();
12055 
12056  g_s.begin("Building full member lists recursively...\n");
12058  g_s.end();
12059 
12060  g_s.begin("Adding members to member groups.\n");
12062  g_s.end();
12063 
12064  if (Config_getBool(DISTRIBUTE_GROUP_DOC))
12065  {
12066  g_s.begin("Distributing member group documentation.\n");
12068  g_s.end();
12069  }
12070 
12071  g_s.begin("Computing member references...\n");
12073  g_s.end();
12074 
12075  if (Config_getBool(INHERIT_DOCS))
12076  {
12077  g_s.begin("Inheriting documentation...\n");
12079  g_s.end();
12080  }
12081 
12082  // compute the shortest possible names of all files
12083  // without losing the uniqueness of the file names.
12084  g_s.begin("Generating disk names...\n");
12086  g_s.end();
12087 
12088  g_s.begin("Adding source references...\n");
12090  g_s.end();
12091 
12092  g_s.begin("Adding xrefitems...\n");
12095  g_s.end();
12096 
12097  g_s.begin("Sorting member lists...\n");
12098  sortMemberLists();
12099  g_s.end();
12100 
12101  g_s.begin("Setting anonymous enum type...\n");
12103  g_s.end();
12104 
12105  if (Config_getBool(DIRECTORY_GRAPH))
12106  {
12107  g_s.begin("Computing dependencies between directories...\n");
12109  g_s.end();
12110  }
12111 
12112  g_s.begin("Generating citations page...\n");
12114  g_s.end();
12115 
12116  g_s.begin("Counting members...\n");
12117  countMembers();
12118  g_s.end();
12119 
12120  g_s.begin("Counting data structures...\n");
12122  g_s.end();
12123 
12124  g_s.begin("Resolving user defined references...\n");
12126  g_s.end();
12127 
12128  g_s.begin("Finding anchors and sections in the documentation...\n");
12130  g_s.end();
12131 
12132  g_s.begin("Transferring function references...\n");
12134  g_s.end();
12135 
12136  g_s.begin("Combining using relations...\n");
12138  g_s.end();
12139 
12140  g_s.begin("Adding members to index pages...\n");
12142  addToIndices();
12143  g_s.end();
12144 
12145  g_s.begin("Correcting members for VHDL...\n");
12147  g_s.end();
12148 
12149  g_s.begin("Computing tooltip texts...\n");
12151  g_s.end();
12152 
12153  if (Config_getBool(SORT_GROUP_NAMES))
12154  {
12155  std::sort(Doxygen::groupLinkedMap->begin(),
12157  [](const auto &g1,const auto &g2)
12158  { return g1->groupTitle() < g2->groupTitle(); });
12159 
12160  for (const auto &gd : *Doxygen::groupLinkedMap)
12161  {
12162  gd->sortSubGroups();
12163  }
12164  }
12165 
12166 }
12167 
12169 {
12170  /**************************************************************************
12171  * Initialize output generators *
12172  **************************************************************************/
12173 
12174  /// add extra languages for which we can only produce syntax highlighted code
12176 
12177  //// dump all symbols
12178  if (g_dumpSymbolMap)
12179  {
12180  dumpSymbolMap();
12181  exit(0);
12182  }
12183 
12185 
12186  bool generateHtml = Config_getBool(GENERATE_HTML);
12187  bool generateLatex = Config_getBool(GENERATE_LATEX);
12188  bool generateMan = Config_getBool(GENERATE_MAN);
12189  bool generateRtf = Config_getBool(GENERATE_RTF);
12190  bool generateDocbook = Config_getBool(GENERATE_DOCBOOK);
12191 
12192 
12193  g_outputList = new OutputList;
12194  if (generateHtml)
12195  {
12199  }
12200  if (generateLatex)
12201  {
12204  }
12205  if (generateDocbook)
12206  {
12209  }
12210  if (generateMan)
12211  {
12214  }
12215  if (generateRtf)
12216  {
12219  }
12220  if (Config_getBool(USE_HTAGS))
12221  {
12223  QCString htmldir = Config_getString(HTML_OUTPUT);
12224  if (!Htags::execute(htmldir))
12225  err("USE_HTAGS is YES but htags(1) failed. \n");
12226  else if (!Htags::loadFilemap(htmldir))
12227  err("htags(1) ended normally but failed to load the filemap. \n");
12228  }
12229 
12230  /**************************************************************************
12231  * Generate documentation *
12232  **************************************************************************/
12233 
12234  g_s.begin("Generating style sheet...\n");
12235  //printf("writing style info\n");
12236  g_outputList->writeStyleInfo(0); // write first part
12237  g_s.end();
12238 
12239  static bool searchEngine = Config_getBool(SEARCHENGINE);
12240  static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
12241 
12242  g_s.begin("Generating search indices...\n");
12243  if (searchEngine && !serverBasedSearch && (generateHtml || g_useOutputTemplate))
12244  {
12246  }
12247 
12248  // generate search indices (need to do this before writing other HTML
12249  // pages as these contain a drop down menu with options depending on
12250  // what categories we find in this function.
12251  if (generateHtml && searchEngine)
12252  {
12253  QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search";
12254  Dir searchDir(searchDirName.str());
12255  if (!searchDir.exists() && !searchDir.mkdir(searchDirName.str()))
12256  {
12257  term("Could not create search results directory '%s' $PWD='%s'\n",
12258  qPrint(searchDirName),Dir::currentDirPath().c_str());
12259  }
12260  HtmlGenerator::writeSearchData(searchDirName);
12261  if (!serverBasedSearch) // client side search index
12262  {
12264  }
12265  }
12266  g_s.end();
12267 
12268  // copy static stuff
12269  if (generateHtml)
12270  {
12272  copyStyleSheet();
12273  copyLogo(Config_getString(HTML_OUTPUT));
12274  copyExtraFiles(Config_getList(HTML_EXTRA_FILES),"HTML_EXTRA_FILES",Config_getString(HTML_OUTPUT));
12275  }
12276  if (generateLatex)
12277  {
12279  copyLogo(Config_getString(LATEX_OUTPUT));
12280  copyExtraFiles(Config_getList(LATEX_EXTRA_FILES),"LATEX_EXTRA_FILES",Config_getString(LATEX_OUTPUT));
12281  }
12282  if (generateDocbook)
12283  {
12284  copyLogo(Config_getString(DOCBOOK_OUTPUT));
12285  }
12286  if (generateRtf)
12287  {
12288  copyLogo(Config_getString(RTF_OUTPUT));
12289  }
12290 
12292  if (fm.hasFormulas() && generateHtml
12293  && !Config_getBool(USE_MATHJAX))
12294  {
12295  g_s.begin("Generating images for formulas in HTML...\n");
12296  fm.generateImages(Config_getString(HTML_OUTPUT), Config_getEnum(HTML_FORMULA_FORMAT)==HTML_FORMULA_FORMAT_t::svg ?
12298  g_s.end();
12299  }
12300  if (fm.hasFormulas() && generateRtf)
12301  {
12302  g_s.begin("Generating images for formulas in RTF...\n");
12304  g_s.end();
12305  }
12306 
12307  if (fm.hasFormulas() && generateDocbook)
12308  {
12309  g_s.begin("Generating images for formulas in Docbook...\n");
12311  g_s.end();
12312  }
12313 
12314  g_s.begin("Generating example documentation...\n");
12316  g_s.end();
12317 
12318  warn_flush();
12319 
12320  g_s.begin("Generating file sources...\n");
12322  g_s.end();
12323 
12324  g_s.begin("Generating file documentation...\n");
12325  generateFileDocs();
12326  g_s.end();
12327 
12328  g_s.begin("Generating page documentation...\n");
12329  generatePageDocs();
12330  g_s.end();
12331 
12332  g_s.begin("Generating group documentation...\n");
12334  g_s.end();
12335 
12336  g_s.begin("Generating class documentation...\n");
12338  g_s.end();
12339 
12340  g_s.begin("Generating concept documentation...\n");
12342  g_s.end();
12343 
12344  g_s.begin("Generating namespace index...\n");
12346  g_s.end();
12347 
12348  if (Config_getBool(GENERATE_LEGEND))
12349  {
12350  g_s.begin("Generating graph info page...\n");
12352  g_s.end();
12353  }
12354 
12355  g_s.begin("Generating directory documentation...\n");
12357  g_s.end();
12358 
12359  if (g_outputList->size()>0)
12360  {
12362  }
12363 
12364  g_s.begin("finalizing index lists...\n");
12366  g_s.end();
12367 
12368  g_s.begin("writing tag file...\n");
12369  writeTagFile();
12370  g_s.end();
12371 
12372  if (Config_getBool(GENERATE_XML))
12373  {
12374  g_s.begin("Generating XML output...\n");
12376  generateXML();
12378  g_s.end();
12379  }
12380 #if USE_SQLITE3
12381  if (Config_getBool(GENERATE_SQLITE3))
12382  {
12383  g_s.begin("Generating SQLITE3 output...\n");
12384  generateSqlite3();
12385  g_s.end();
12386  }
12387 #endif
12388 
12389  if (Config_getBool(GENERATE_AUTOGEN_DEF))
12390  {
12391  g_s.begin("Generating AutoGen DEF output...\n");
12392  generateDEF();
12393  g_s.end();
12394  }
12395  if (Config_getBool(GENERATE_PERLMOD))
12396  {
12397  g_s.begin("Generating Perl module output...\n");
12398  generatePerlMod();
12399  g_s.end();
12400  }
12401  if (generateHtml && searchEngine && serverBasedSearch)
12402  {
12403  g_s.begin("Generating search index\n");
12404  if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
12405  {
12407  Doxygen::searchIndex->write(Config_getString(HTML_OUTPUT)+"/search/search.idx");
12408  }
12409  else // write data for external search index
12410  {
12412  QCString searchDataFile = Config_getString(SEARCHDATA_FILE);
12413  if (searchDataFile.isEmpty())
12414  {
12415  searchDataFile="searchdata.xml";
12416  }
12417  if (!Portable::isAbsolutePath(searchDataFile.data()))
12418  {
12419  searchDataFile.prepend(Config_getString(OUTPUT_DIRECTORY)+"/");
12420  }
12421  Doxygen::searchIndex->write(searchDataFile);
12422  }
12423  g_s.end();
12424  }
12425 
12426  if (g_useOutputTemplate)
12427  {
12428  g_s.begin("Generating output via template engine...\n");
12430  g_s.end();
12431  }
12432 
12433  warn_flush();
12434 
12435  if (generateRtf)
12436  {
12437  g_s.begin("Combining RTF output...\n");
12438  if (!RTFGenerator::preProcessFileInplace(Config_getString(RTF_OUTPUT),"refman.rtf"))
12439  {
12440  err("An error occurred during post-processing the RTF files!\n");
12441  }
12442  g_s.end();
12443  }
12444 
12445  warn_flush();
12446 
12447  g_s.begin("Running plantuml with JAVA...\n");
12449  g_s.end();
12450 
12451  warn_flush();
12452 
12453  if (Config_getBool(HAVE_DOT))
12454  {
12455  g_s.begin("Running dot...\n");
12457  g_s.end();
12458  }
12459 
12460  if (generateHtml &&
12461  Config_getBool(GENERATE_HTMLHELP) &&
12462  !Config_getString(HHC_LOCATION).isEmpty())
12463  {
12464  g_s.begin("Running html help compiler...\n");
12465  std::string oldDir = Dir::currentDirPath();
12466  Dir::setCurrent(Config_getString(HTML_OUTPUT).str());
12469  if (Portable::system(Config_getString(HHC_LOCATION).data(), "index.hhp", Debug::isFlagSet(Debug::ExtCmd))!=1)
12470  {
12471  err("failed to run html help compiler on index.hhp\n");
12472  }
12474  Dir::setCurrent(oldDir);
12475  g_s.end();
12476  }
12477 
12478  warn_flush();
12479 
12480  if ( generateHtml &&
12481  Config_getBool(GENERATE_QHP) &&
12482  !Config_getString(QHG_LOCATION).isEmpty())
12483  {
12484  g_s.begin("Running qhelpgenerator...\n");
12485  QCString qhpFileName = Qhp::getQhpFileName();
12486  QCString qchFileName = getQchFileName();
12487 
12488  QCString args = QCString().sprintf("%s -o \"%s\"", qPrint(qhpFileName), qPrint(qchFileName));
12489  std::string oldDir = Dir::currentDirPath();
12490  Dir::setCurrent(Config_getString(HTML_OUTPUT).str());
12492  if (Portable::system(Config_getString(QHG_LOCATION).data(), args.data(), FALSE))
12493  {
12494  err("failed to run qhelpgenerator on index.qhp\n");
12495  }
12497  Dir::setCurrent(oldDir);
12498  g_s.end();
12499  }
12500 
12501  g_outputList->cleanup();
12502 
12503  int cacheParam;
12504  msg("lookup cache used %zu/%zu hits=%" PRIu64 " misses=%" PRIu64 "\n",
12505  Doxygen::lookupCache->size(),
12506  Doxygen::lookupCache->capacity(),
12507  Doxygen::lookupCache->hits(),
12508  Doxygen::lookupCache->misses());
12509  cacheParam = computeIdealCacheParam(static_cast<size_t>(Doxygen::lookupCache->misses()*2/3)); // part of the cache is flushed, hence the 2/3 correction factor
12510  if (cacheParam>Config_getInt(LOOKUP_CACHE_SIZE))
12511  {
12512  msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
12513  }
12514 
12516  {
12517  msg("Total elapsed time: %.6f seconds\n(of which %.6f seconds waiting for external tools to finish)\n",
12518  ((double)Debug::elapsedTime()),
12520  );
12521  g_s.print();
12522  }
12523  else
12524  {
12525  msg("finished...\n");
12526  }
12527 
12528 
12529  /**************************************************************************
12530  * Start cleaning up *
12531  **************************************************************************/
12532 
12533  cleanUpDoxygen();
12534 
12536  Dir thisDir;
12537  thisDir.remove(Doxygen::filterDBFileName.str());
12538  finishWarnExit();
12539  Config::deinit();
12540  delete Doxygen::clangUsrMap;
12542 }
ClassDef::requiresClause
virtual QCString requiresClause() const =0
ArgumentList::setVolatileSpecifier
void setVolatileSpecifier(bool b)
Definition: arguments.h:113
clangparser.h
ClassDef::Service
@ Service
Definition: classdef.h:114
createNamespaceDef
NamespaceDefMutable * createNamespaceDef(const QCString &defFileName, int defLine, int defColumn, const QCString &name, const QCString &ref, const QCString &refFile, const QCString &type, bool isPublished)
Factory method to create new NamespaceDef instance
Definition: namespacedef.cpp:163
toDefinition
Definition * toDefinition(DefinitionMutable *dm)
Definition: definition.cpp:1950
formula.h
DefinitionMutable::setInbodyDocumentation
virtual void setInbodyDocumentation(const QCString &d, const QCString &docFile, int docLine)=0
Debug::ExtCmd
@ ExtCmd
Definition: debug.h:36
combineDeclarationAndDefinition
void combineDeclarationAndDefinition(MemberDefMutable *mdec, MemberDefMutable *mdef)
Definition: memberdef.cpp:5818
StringVector
std::vector< std::string > StringVector
Definition: containers.h:32
ConceptDefMutable
Definition: conceptdef.h:42
flushUnresolvedRelations
static void flushUnresolvedRelations()
Definition: doxygen.cpp:8796
buildClassDocList
static void buildClassDocList(const Entry *root)
Definition: doxygen.cpp:1159
Config::init
void init()
lexcode.h
FileDefSet
std::set< const FileDef * > FileDefSet
Definition: filedef.h:45
DotManager::instance
static DotManager * instance()
Definition: dot.cpp:77
MemberDefMutable::setTemplateSpecialization
virtual void setTemplateSpecialization(bool b)=0
addIncludeFile
static void addIncludeFile(DefMutable *cd, FileDef *ifd, const Entry *root)
Definition: doxygen.cpp:543
ClassDefMutable::sortMemberLists
virtual void sortMemberLists()=0
MemberDefMutable::setTagInfo
virtual void setTagInfo(const TagInfo *i)=0
SrcLangExt_Unknown
@ SrcLangExt_Unknown
Definition: types.h:43
ThreadPool::queue
std::future< R > queue(F &&f)
Queue the callable function f for the threads to execute.
Definition: threadpool.h:86
reg::isalpha
static bool isalpha(char c)
Definition: regex.cpp:38
Dir::currentDirPath
static std::string currentDirPath()
Definition: dir.cpp:282
startTitle
void startTitle(OutputList &ol, const QCString &fileName, const DefinitionMutable *def)
Definition: index.cpp:219
DefinitionMutable::setDocumentation
virtual void setDocumentation(const QCString &d, const QCString &docFile, int docLine, bool stripWhiteSpace=TRUE)=0
Entry::args
QCString args
member argument string
Definition: entry.h:259
outputlist.h
VhdlDocGen::correctMemberProperties
static void correctMemberProperties(MemberDefMutable *md)
Definition: vhdldocgen.cpp:1570
MemberDefMutable::setEnumScope
virtual void setEnumScope(const MemberDef *md, bool livesInsideEnum=FALSE)=0
FileDef::getAllIncludeFilesRecursively
virtual void getAllIncludeFilesRecursively(StringVector &incFiles) const =0
LinkedRefMap::empty
bool empty() const
Definition: linkedmap.h:374
FileDef::setDiskName
virtual void setDiskName(const QCString &name)=0
Entry::SERVICEDOC_SEC
@ SERVICEDOC_SEC
Definition: entry.h:81
MemberDef::isTypedef
virtual bool isTypedef() const =0
ClassDef::hasDocumentation
virtual bool hasDocumentation() const =0
returns TRUE if this class has documentation
xmlgen.h
Entry::tArgLists
ArgumentLists tArgLists
template argument declarations
Definition: entry.h:262
FormulaManager::readFormulas
void readFormulas(const QCString &dir, bool doCompare=false)
Definition: formula.cpp:71
TagInfo
This struct is used to capture the tag file information for an Entry.
Definition: entry.h:48
FileDef::insertNamespace
virtual void insertNamespace(const NamespaceDef *nd)=0
stripAnonymousNamespaceScope
QCString stripAnonymousNamespaceScope(const QCString &s)
Definition: util.cpp:235
OutlineParserInterface::parseInput
virtual void parseInput(const QCString &fileName, const char *fileBuf, const std::shared_ptr< Entry > &root, ClangTUParser *clangParser)=0
Parses a single input file with the goal to build an Entry tree.
ThreadPool
Class managing a pool of worker threads.
Definition: threadpool.h:47
fileinfo.h
HtmlGenerator
Generator for HTML output
Definition: htmlgen.h:66
latexgen.h
MemberDefMutable::setHidden
virtual void setHidden(bool b)=0
findFileDef
FileDef * findFileDef(const FileNameLinkedMap *fnMap, const QCString &n, bool &ambig)
Definition: util.cpp:3222
ArgumentList::setTrailingReturnType
void setTrailingReturnType(const QCString &s)
Definition: arguments.h:115
Entry::GROUPDOC_NORMAL
@ GROUPDOC_NORMAL
defgroup
Definition: entry.h:190
Entry::OVERLOADDOC_SEC
@ OVERLOADDOC_SEC
Definition: entry.h:100
Entry::virt
Specifier virt
virtualness of the entry
Definition: entry.h:258
DefinitionMutable::addSectionsToDefinition
virtual void addSectionsToDefinition(const std::vector< const SectionInfo * > &anchorList)=0
LinkedRefMap< const NamespaceDef >
Definition::docLine
virtual int docLine() const =0
MemberType_Variable
@ MemberType_Variable
Definition: types.h:278
threadpool.h
copyExtraFiles
static void copyExtraFiles(const StringVector &files, const QCString &filesOption, const QCString &outputOption)
Definition: doxygen.cpp:9716
SymbolResolver::getTemplateSpec
QCString getTemplateSpec() const
In case a call to resolveClass() points to a template specialization, the template part is return via...
Definition: symbolresolver.cpp:1108
MemberDefMutable::mergeMemberSpecifiers
virtual void mergeMemberSpecifiers(uint64 s)=0
ClassDefMutable::setSubGrouping
virtual void setSubGrouping(bool enabled)=0
RefListManager::instance
static RefListManager & instance()
Definition: reflist.h:120
transferRelatedFunctionDocumentation
static void transferRelatedFunctionDocumentation()
Definition: doxygen.cpp:3934
findAndRemoveWord
bool findAndRemoveWord(QCString &sentence, const char *word)
removes occurrences of whole word from sentence, while keeps internal spaces and reducing multiple se...
Definition: util.cpp:5351
ClassDefMutable
Definition: classdef.h:384
ClassDefMutable::addUsedClass
virtual void addUsedClass(ClassDef *cd, const QCString &accessName, Protection prot)=0
cite.h
leftScopeMatch
bool leftScopeMatch(const QCString &scope, const QCString &name)
Definition: util.cpp:874
GroupDef::addListReferences
virtual void addListReferences()=0
htmlhelp.h
NamespaceDef::getUsedNamespaces
virtual LinkedRefMap< const NamespaceDef > getUsedNamespaces() const =0
endTitle
void endTitle(OutputList &ol, const QCString &fileName, const QCString &name)
Definition: index.cpp:228
Cache< std::string, LookupInfo >
toMemberDefMutable
MemberDefMutable * toMemberDefMutable(Definition *d)
Definition: memberdef.cpp:6125
Entry::EXAMPLE_SEC
@ EXAMPLE_SEC
Definition: entry.h:101
FileDef::anchor
virtual QCString anchor() const =0
ArgumentList::push_back
void push_back(const Argument &a)
Definition: arguments.h:95
Normal
@ Normal
Definition: types.h:29
createClassDefAlias
ClassDef * createClassDefAlias(const Definition *newScope, const ClassDef *cd)
Definition: classdef.cpp:559
generateConfigFile
static void generateConfigFile(const QCString &configFile, bool shortList, bool updateOnly=FALSE)
Definition: doxygen.cpp:9539
Entry::INTERFACEDOC_SEC
@ INTERFACEDOC_SEC
Definition: entry.h:78
MemberDef::hasReferencedByRelation
virtual bool hasReferencedByRelation() const =0
ClangTUParser::switchToFile
void switchToFile(const FileDef *fd)
Switches to another file within the translation unit started with start().
Definition: clangparser.cpp:912
QCString::replace
QCString & replace(size_t index, size_t len, const char *s)
Definition: qcstring.cpp:207
g_usingDeclarations
static StringSet g_usingDeclarations
Definition: doxygen.cpp:174
Doxygen::mainPage
static std::unique_ptr< PageDef > mainPage
Definition: doxygen.h:83
Protection
Protection
Protection level of members
Definition: types.h:26
FileName
Class representing all files with a certain base name
Definition: filename.h:28
Config_getEnum
#define Config_getEnum(name)
Definition: config.h:35
MemberDefMutable::setInitializer
virtual void setInitializer(const QCString &i)=0
membergroup.h
Entry::initializer
TextStream initializer
initial value (for variables)
Definition: entry.h:264
MemberDef::argsString
virtual QCString argsString() const =0
FileDef::addListReferences
virtual void addListReferences()=0
Statistics::stat::stat
stat(const char *n, double el)
Definition: doxygen.cpp:242
expandAliases
static void expandAliases()
Definition: doxygen.cpp:10378
FileDef::addMembersToMemberGroup
virtual void addMembersToMemberGroup()=0
printNavTree
void printNavTree(Entry *root, int indent)
Definition: doxygen.cpp:9320
FileDef::generateSourceFile
virtual bool generateSourceFile() const =0
FileDef::addUsingDirective
virtual void addUsingDirective(const NamespaceDef *nd)=0
ClassDef::Union
@ Union
Definition: classdef.h:109
Definition::TypeMember
@ TypeMember
Definition: definition.h:90
generateXML
void generateXML()
Definition: xmlgen.cpp:1888
g_pathsVisited
static StringUnorderedSet g_pathsVisited(1009)
buildFileList
static void buildFileList(const Entry *root)
Definition: doxygen.cpp:470
MemberDefMutable::setTypeConstraints
virtual void setTypeConstraints(const ArgumentList &al)=0
setTranslator
void setTranslator(OUTPUT_LANGUAGE_t langName)
Definition: language.cpp:158
finishWarnExit
void finishWarnExit()
Definition: message.cpp:271
stripFromIncludePath
QCString stripFromIncludePath(const QCString &path)
Definition: util.cpp:322
MemberDef::briefDescription
virtual QCString briefDescription(bool abbr=FALSE) const =0
Definition::getDefColumn
virtual int getDefColumn() const =0
Entry::startLine
int startLine
start line of entry in the source
Definition: entry.h:291
Doxygen::namespaceAliasMap
static StringUnorderedMap namespaceAliasMap
Definition: doxygen.h:95
Definition
The common base class of all entity definitions found in the sources.
Definition: definition.h:76
Entry::callGraph
bool callGraph
do we need to draw the call graph?
Definition: entry.h:254
MemberDef::documentation
virtual QCString documentation() const =0
ClassDefMutable::setCompoundType
virtual void setCompoundType(CompoundType t)=0
DotManager::run
bool run() const
Definition: dot.cpp:154
MemberDef::isObjCProperty
virtual bool isObjCProperty() const =0
Doxygen::imageNameLinkedMap
static FileNameLinkedMap * imageNameLinkedMap
Definition: doxygen.h:89
Dir::remove
bool remove(const std::string &path, bool acceptsAbsPath=true) const
Definition: dir.cpp:256
pre.h
NamespaceDef::localName
virtual QCString localName() const =0
MemberDef::isStatic
virtual bool isStatic() const =0
ClassDef::isEmbeddedInOuterScope
virtual bool isEmbeddedInOuterScope() const =0
NamespaceDef
An abstract interface of a namespace symbol.
Definition: namespacedef.h:54
MemberType_EnumValue
@ MemberType_EnumValue
Definition: types.h:281
Dir
Class representing a directory in the file system
Definition: dir.h:68
ClassDefMutable::sortAllMembersList
virtual void sortAllMembersList()=0
Private
@ Private
Definition: types.h:26
mangen.h
generatePerlMod
void generatePerlMod()
Definition: perlmodgen.cpp:2958
MemberDefMutable::setAccessorType
virtual void setAccessorType(ClassDef *cd, const QCString &t)=0
findMemberDocumentation
static void findMemberDocumentation(const Entry *root)
Definition: doxygen.cpp:6959
isRecursiveBaseClass
static bool isRecursiveBaseClass(const QCString &scope, const QCString &name)
Definition: doxygen.cpp:4326
DefinitionMutable::setDefFile
virtual void setDefFile(const QCString &df, int defLine, int defColumn)=0
Doxygen::diaFileNameLinkedMap
static FileNameLinkedMap * diaFileNameLinkedMap
Definition: doxygen.h:92
MemberType_Signal
@ MemberType_Signal
Definition: types.h:282
NamespaceDefMutable::writeDocumentation
virtual void writeDocumentation(OutputList &ol)=0
DotManager::deleteInstance
static void deleteInstance()
Definition: dot.cpp:86
OutputList::docify
void docify(const QCString &s)
Definition: outputlist.h:137
addClassMemberNameToIndex
void addClassMemberNameToIndex(const MemberDef *md)
Definition: index.cpp:2659
pagedef.h
MemberDef::getMemberGroupId
virtual int getMemberGroupId() const =0
getParserForFile
static std::unique_ptr< OutlineParserInterface > getParserForFile(const QCString &fn)
Definition: doxygen.cpp:9816
Entry::STRUCTDOC_SEC
@ STRUCTDOC_SEC
Definition: entry.h:74
CitationManager::clear
void clear()
clears the database
Definition: cite.cpp:85
NamespaceDefMutable::setInline
virtual void setInline(bool isInline)=0
substituteTemplateArgumentsInString
QCString substituteTemplateArgumentsInString(const QCString &nm, const ArgumentList &formalArgs, const std::unique_ptr< ArgumentList > &actualArgs)
Definition: util.cpp:4477
cmdmapper.h
writeJavaScriptSearchIndex
void writeJavaScriptSearchIndex()
Definition: searchindex.cpp:905
buildGroupList
static void buildGroupList(const Entry *root)
Definition: doxygen.cpp:400
MemberDefMutable::makeRelated
virtual void makeRelated()=0
SrcLangExt_XML
@ SrcLangExt_XML
Definition: types.h:55
findClassEntries
static void findClassEntries(const Entry *root)
Definition: doxygen.cpp:4824
Doxygen::hiddenClassLinkedMap
static ClassLinkedMap * hiddenClassLinkedMap
Definition: doxygen.h:79
BufStr
Buffer used to store strings
Definition: bufstr.h:29
QCString::length
uint length() const
Returns the length of the string, not counting the 0-terminator.
Definition: qcstring.h:147
Htags::loadFilemap
static bool loadFilemap(const QCString &htmldir)
Definition: htags.cpp:109
NullOutlineParser::parsePrototype
void parsePrototype(const QCString &)
Callback function called by the comment block scanner.
Definition: doxygen.cpp:10601
Doxygen::tagDestinationMap
static StringMap tagDestinationMap
Definition: doxygen.h:98
GroupDef::distributeMemberGroupDocumentation
virtual void distributeMemberGroupDocumentation()=0
NamespaceDef::getExceptions
virtual ClassLinkedRefMap getExceptions() const =0
Entry::SINGLETONDOC_SEC
@ SINGLETONDOC_SEC
Definition: entry.h:82
ArgumentList
This class represents an function or template argument list.
Definition: arguments.h:59
Entry::ForwardDecl
static const uint64 ForwardDecl
Definition: entry.h:137
Doxygen::conceptLinkedMap
static ConceptLinkedMap * conceptLinkedMap
Definition: doxygen.h:80
MemberType_Interface
@ MemberType_Interface
Definition: types.h:288
ConceptDef::isLinkableInProject
virtual bool isLinkableInProject() const =0
Htags::useHtags
static bool useHtags
Definition: htags.h:23
DirDef
A model of a directory symbol.
Definition: dirdef.h:110
Definition::getDefLine
virtual int getDefLine() const =0
QCString::findRev
int findRev(char c, int index=-1, bool cs=TRUE) const
Definition: qcstring.cpp:86
countMembers
static void countMembers()
Definition: doxygen.cpp:8405
SrcLangExt_PHP
@ SrcLangExt_PHP
Definition: types.h:48
MemberName::push_back
void push_back(Ptr &&p)
Definition: membername.h:68
Entry::spec
uint64 spec
class/member specifiers
Definition: entry.h:248
filterTitle
QCString filterTitle(const QCString &title)
Definition: util.cpp:6254
generateDiskNames
static void generateDiskNames()
Definition: doxygen.cpp:9739
DefinitionMutable::setName
virtual void setName(const QCString &name)=0
Statistics::startTime
std::chrono::steady_clock::time_point startTime
Definition: doxygen.cpp:245
Doxygen::dotFileNameLinkedMap
static FileNameLinkedMap * dotFileNameLinkedMap
Definition: doxygen.h:90
transferFunctionDocumentation
static void transferFunctionDocumentation()
Definition: doxygen.cpp:3855
QCString::isEmpty
bool isEmpty() const
Returns TRUE iff the string is empty
Definition: qcstring.h:144
BufStr::data
char * data() const
Definition: bufstr.h:96
ClassDefMutable::writeMemberList
virtual void writeMemberList(OutputList &ol) const =0
RTFGenerator
Generator for RTF output.
Definition: rtfgen.h:25
ClassDef::insertTemplateInstance
virtual ClassDef * insertTemplateInstance(const QCString &fileName, int startLine, int startColumn, const QCString &templSpec, bool &freshInstance) const =0
reg::match
bool match(const std::string &str, Match &match, const Ex &re)
Matches a given string str for a match against regular expression re.
Definition: regex.cpp:729
index.h
initFileMemberIndices
void initFileMemberIndices()
Definition: index.cpp:2801
stlsupport.h
TagInfo::tagName
QCString tagName
Definition: entry.h:50
DefinitionMutable::setReference
virtual void setReference(const QCString &r)=0
createOutputDirectory
static QCString createOutputDirectory(const QCString &baseDirName, const QCString &formatDirName, const char *defaultDirName)
Definition: doxygen.cpp:11329
transferFunctionReferences
static void transferFunctionReferences()
Definition: doxygen.cpp:3888
Definition::findInnerCompound
virtual const Definition * findInnerCompound(const QCString &name) const =0
PageDef::getGroupDef
virtual const GroupDef * getGroupDef() const =0
Entry::mtype
MethodTypes mtype
signal, slot, (dcop) method, or property?
Definition: entry.h:247
Preprocessor
Definition: pre.h:26
Doxygen::pageLinkedMap
static PageLinkedMap * pageLinkedMap
Definition: doxygen.h:82
sortMemberLists
static void sortMemberLists()
Definition: doxygen.cpp:8330
RTFGenerator::writeStyleSheetFile
static void writeStyleSheetFile(TextStream &t)
Definition: rtfgen.cpp:102
NamespaceDefMutable::addUsingDeclaration
virtual void addUsingDeclaration(const ClassDef *cd)=0
addPageToContext
static void addPageToContext(PageDef *pd, Entry *root)
Definition: doxygen.cpp:284
FileInfo::isFile
bool isFile() const
Definition: fileinfo.cpp:63
Entry::extends
std::vector< BaseInfo > extends
list of base classes
Definition: entry.h:287
namespacedef.h
Doxygen::indexList
static IndexList * indexList
Definition: doxygen.h:114
addRelatedPage
static void addRelatedPage(Entry *root)
Definition: doxygen.cpp:303
GroupDef::groupTitle
virtual QCString groupTitle() const =0
MemberDefMutable::setBitfields
virtual void setBitfields(const QCString &s)=0
ClassDef::CompoundType
CompoundType
The various compound types
Definition: classdef.h:107
findGroupScope
static void findGroupScope(const Entry *root)
Definition: doxygen.cpp:415
createPageDef
PageDef * createPageDef(const QCString &f, int l, const QCString &n, const QCString &d, const QCString &t)
Definition: pagedef.cpp:76
Statistics::Statistics
Statistics()
Definition: doxygen.cpp:208
dumpSymbol
static void dumpSymbol(TextStream &t, Definition *d)
Definition: doxygen.cpp:10465
isSymbolHidden
static bool isSymbolHidden(const Definition *d)
Definition: doxygen.cpp:8370
copyFile
bool copyFile(const QCString &src, const QCString &dest)
Copies the contents of file with name src to the newly created file with name dest.
Definition: util.cpp:6439
QCString::size
uint size() const
Returns the length of the string, not counting the 0-terminator.
Definition: qcstring.h:150
flushCachedTemplateRelations
static void flushCachedTemplateRelations()
Definition: doxygen.cpp:8742
SymbolResolver
Helper class to find a class definition or check if A symbol is accessible in a given scope.
Definition: symbolresolver.h:30
Entry::ENUM_SEC
@ ENUM_SEC
Definition: entry.h:93
FindBaseClassRelation_Mode
FindBaseClassRelation_Mode
Definition: doxygen.cpp:260
msc.h
computeTooltipTexts
static void computeTooltipTexts()
Definition: doxygen.cpp:8377
membername.h
warn_flush
void warn_flush()
Definition: message.cpp:237
Entry::startColumn
int startColumn
start column of entry in the source
Definition: entry.h:292
Entry::name
QCString name
member name
Definition: entry.h:240
checkConfiguration
void checkConfiguration()
check and resolve config options
Definition: doxygen.cpp:11143
ClassDef::Interface
@ Interface
Definition: classdef.h:110
organizeSubGroupsFiltered
static void organizeSubGroupsFiltered(const Entry *root, bool additional)
Definition: doxygen.cpp:440
generateGroupDocs
static void generateGroupDocs()
Definition: doxygen.cpp:9377
toMemberDef
MemberDef * toMemberDef(Definition *d)
Definition: memberdef.cpp:6088
MemberDef::bitfieldString
virtual QCString bitfieldString() const =0
extractClassName
static QCString extractClassName(const Entry *root)
Definition: doxygen.cpp:4833
GroupDef::addNamespace
virtual bool addNamespace(const NamespaceDef *def)=0
NamespaceDef::getInterfaces
virtual ClassLinkedRefMap getInterfaces() const =0
Entry::hidden
bool hidden
does this represent an entity that is hidden from the output
Definition: entry.h:295
FormulaManager::Format::Vector
@ Vector
findTemplateInstanceRelation
static void findTemplateInstanceRelation(const Entry *root, Definition *context, ClassDefMutable *templateClass, const QCString &templSpec, const TemplateNameMap &templateNames, bool isArtificial)
Definition: doxygen.cpp:4265
Entry::COMPOUND_MASK
@ COMPOUND_MASK
Definition: entry.h:70
generateExampleDocs
static void generateExampleDocs()
Definition: doxygen.cpp:9338
BaseInfo::prot
Protection prot
inheritance type
Definition: entry.h:41
Undocumented
@ Undocumented
Definition: doxygen.cpp:264
FileDef::countMembers
virtual void countMembers()=0
MemberDefMutable::setArgsString
virtual void setArgsString(const QCString &as)=0
SrcLangExt
SrcLangExt
Language as given by extension
Definition: types.h:41
devUsage
static void devUsage()
Definition: doxygen.cpp:10501
Entry::USINGDIR_SEC
@ USINGDIR_SEC
Definition: entry.h:108
MemberType_Friend
@ MemberType_Friend
Definition: types.h:284
Entry::anchors
std::vector< const SectionInfo * > anchors
list of anchors defined in this entry
Definition: entry.h:289
LinkedMap::add
T * add(const char *k, Args &&... args)
Adds a new object to the ordered vector if it was not added already.
Definition: linkedmap.h:103
setPerlModDoxyfile
void setPerlModDoxyfile(const QCString &qs)
Definition: perlmodgen.cpp:1508
Debug::printFlags
static void printFlags()
Definition: debug.cpp:104
FormulaManager::instance
static FormulaManager & instance()
Definition: formula.cpp:65
buildDefineList
static void buildDefineList()
Definition: doxygen.cpp:8294
findTemplateSpecializationPosition
static int findTemplateSpecializationPosition(const QCString &name)
Definition: doxygen.cpp:4417
MemberDef::isPrototype
virtual bool isPrototype() const =0
IndexList::addIndexItem
void addIndexItem(const Definition *context, const MemberDef *md, const QCString &sectionAnchor=QCString(), const QCString &title=QCString())
Definition: index.h:101
Doxygen::globalScope
static NamespaceDefMutable * globalScope
Definition: doxygen.h:102
inheritDocumentation
static void inheritDocumentation()
Definition: doxygen.cpp:8555
Entry::CONCEPT_SEC
@ CONCEPT_SEC
Definition: entry.h:69
StringUnorderedMap
std::unordered_map< std::string, std::string > StringUnorderedMap
Definition: containers.h:27
GroupDef::countMembers
virtual void countMembers()=0
MemberType_Enumeration
@ MemberType_Enumeration
Definition: types.h:280
findUsedClassesForClass
static void findUsedClassesForClass(const Entry *root, Definition *context, ClassDefMutable *masterCd, ClassDefMutable *instanceCd, bool isArtificial, const std::unique_ptr< ArgumentList > &actualArgs=std::unique_ptr< ArgumentList >(), const TemplateNameMap &templateNames=TemplateNameMap())
Definition: doxygen.cpp:4050
Entry::referencedByRelation
bool referencedByRelation
do we need to show the referenced by relation?
Definition: entry.h:256
addNamespaceToGroups
void addNamespaceToGroups(const Entry *root, NamespaceDef *nd)
Definition: groupdef.cpp:1357
Grouping
Grouping info
Definition: types.h:64
StringSet
std::set< std::string > StringSet
Definition: containers.h:30
Doxygen::macroDefinitions
static DefinesPerFileList macroDefinitions
Definition: doxygen.h:118
Entry::mGrpId
int mGrpId
member group id
Definition: entry.h:286
stripTemplateSpecifiersFromScope
QCString stripTemplateSpecifiersFromScope(const QCString &fullName, bool parentOnly, QCString *pLastScopeStripped)
Definition: util.cpp:4605
HtmlGenerator::writeStyleSheetFile
static void writeStyleSheetFile(TextStream &t)
Definition: htmlgen.cpp:1101
MemberDefMutable::setMemberClass
virtual void setMemberClass(const ClassDef *cd)=0
GroupDef::writeDocumentation
virtual void writeDocumentation(OutputList &ol)=0
markdown.h
Entry::DEFINE_SEC
@ DEFINE_SEC
Definition: entry.h:106
generateNamespaceDocs
static void generateNamespaceDocs()
Definition: doxygen.cpp:9481
SymbolResolver::resolveClassMutable
ClassDefMutable * resolveClassMutable(const Definition *scope, const QCString &name, bool mayBeUnlinkable=false, bool mayBeHidden=false)
Wrapper around resolveClass that returns a mutable interface to the class object or a nullptr if the ...
Definition: symbolresolver.h:55
QCString::str
std::string str() const
Definition: qcstring.h:442
Entry::protection
Protection protection
class protection
Definition: entry.h:246
LinkedMap< RefList >::Ptr
std::unique_ptr< RefList > Ptr
Definition: linkedmap.h:51
MemberType_Typedef
@ MemberType_Typedef
Definition: types.h:279
addConceptToGroups
void addConceptToGroups(const Entry *root, ConceptDef *cd)
Definition: groupdef.cpp:1339
HtmlGenerator::writeSearchData
static void writeSearchData(const QCString &dir)
Definition: htmlgen.cpp:1044
IndexList::addIndex
void addIndex(As &&... args)
Add an index generator to the list, using a syntax similar to std::make_unique<T>()
Definition: index.h:78
ClassDefMutable::insertBaseClass
virtual void insertBaseClass(ClassDef *, const QCString &name, Protection p, Specifier s, const QCString &t=QCString())=0
NamespaceDef::isInline
virtual bool isInline() const =0
Specifier
Specifier
Virtualness of a member.
Definition: types.h:29
Definition::isHidden
virtual bool isHidden() const =0
Doxygen::aliasMap
static StringMap aliasMap
Definition: doxygen.h:99
FileDef::insertClass
virtual void insertClass(const ClassDef *cd)=0
ClassDef::isLinkableInProject
virtual bool isLinkableInProject() const =0
returns TRUE iff a link is possible to this item within this project.
MemberDefMutable::setRequiresClause
virtual void setRequiresClause(const QCString &req)=0
fortrancode.h
DefinitionMutable::mergeReferences
virtual void mergeReferences(const Definition *other)=0
Entry::VARIABLEDOC_SEC
@ VARIABLEDOC_SEC
Definition: entry.h:102
PlantumlManager::instance
static PlantumlManager & instance()
Definition: plantuml.cpp:124
Public
@ Public
Definition: types.h:26
Entry::id
QCString id
libclang id
Definition: entry.h:298
Entry::briefFile
QCString briefFile
file in which the brief desc. was found
Definition: entry.h:272
Entry::MAINPAGEDOC_SEC
@ MAINPAGEDOC_SEC
Definition: entry.h:109
NamespaceDef::anchor
virtual QCString anchor() const =0
MemberDefMutable::insertEnumField
virtual void insertEnumField(const MemberDef *md)=0
Entry::DIRDOC_SEC
@ DIRDOC_SEC
Definition: entry.h:115
MemberDefMutable::makeImplementationDetail
virtual void makeImplementationDetail()=0
g_s
class Statistics g_s
dumpSymbolMap
static void dumpSymbolMap()
Definition: doxygen.cpp:10487
Entry::CONCEPTDOC_SEC
@ CONCEPTDOC_SEC
Definition: entry.h:83
findClassDefinition
static const ClassDef * findClassDefinition(FileDef *fd, NamespaceDef *nd, const QCString &scopeName)
Definition: doxygen.cpp:5259
addLocalObjCMethod
static void addLocalObjCMethod(const Entry *root, const QCString &scopeName, const QCString &funcType, const QCString &funcName, const QCString &funcArgs, const QCString &exceptions, const QCString &funcDecl, uint64 spec)
Definition: doxygen.cpp:5626
Entry::includeName
QCString includeName
include name (3 arg of \class)
Definition: entry.h:266
Doxygen::parseSourcesNeeded
static bool parseSourcesNeeded
Definition: doxygen.h:104
ClassDef::getTemplateBaseClassNames
virtual const TemplateNameMap & getTemplateBaseClassNames() const =0
addMemberDocs
static void addMemberDocs(const Entry *root, MemberDefMutable *md, const QCString &funcDecl, const ArgumentList *al, bool over_load, uint64 spec)
Definition: doxygen.cpp:5108
FileDef::isLinkableInProject
virtual bool isLinkableInProject() const =0
err
void err(const char *fmt,...)
Definition: message.cpp:203
MemberType
MemberType
Definition: types.h:274
Definition::inbodyLine
virtual int inbodyLine() const =0
MemberDefMutable::setDocsForDefinition
virtual void setDocsForDefinition(bool b)=0
SrcLangExt_Java
@ SrcLangExt_Java
Definition: types.h:45
Event
@ Event
Definition: types.h:32
OutputList::size
size_t size() const
Definition: outputlist.h:51
QCString::at
char & at(size_t i)
Returns a reference to the character at index i.
Definition: qcstring.h:477
ClassDefMutable::setTemplateBaseClassNames
virtual void setTemplateBaseClassNames(const TemplateNameMap &templateNames)=0
TextStream
Text streaming class that buffers data.
Definition: textstream.h:33
Doxygen::dirLinkedMap
static DirLinkedMap * dirLinkedMap
Definition: doxygen.h:109
warn_simple
void warn_simple(const QCString &file, int line, const char *text)
Definition: message.cpp:164
Entry::docLine
int docLine
line number at which the documentation was found
Definition: entry.h:268
distributeClassGroupRelations
void distributeClassGroupRelations()
Definition: doxygen.cpp:1428
SearchIndexIntf::Internal
@ Internal
Definition: searchindex.h:70
SectionInfo::lineNr
int lineNr() const
Definition: section.h:69
createMemberDef
MemberDefMutable * createMemberDef(const QCString &defFileName, int defLine, int defColumn, const QCString &type, const QCString &name, const QCString &args, const QCString &excp, Protection prot, Specifier virt, bool stat, Relationship related, MemberType t, const ArgumentList &tal, const ArgumentList &al, const QCString &metaData)
Factory method to create a new instance of a MemberDef
Definition: memberdef.cpp:373
Entry::includeFile
QCString includeFile
include file (2 arg of \class, must be unique)
Definition: entry.h:265
QCString::find
int find(char c, int index=0, bool cs=TRUE) const
Definition: qcstring.cpp:38
Entry::fileDef
FileDef * fileDef() const
Definition: entry.h:235
MemberDefMutable::insertReimplementedBy
virtual void insertReimplementedBy(const MemberDef *md)=0
addOverloaded
static void addOverloaded(const Entry *root, MemberName *mn, const QCString &funcType, const QCString &funcName, const QCString &funcArgs, const QCString &funcDecl, const QCString &exceptions, uint64 spec)
Definition: doxygen.cpp:6089
Statistics::stat::elapsed
double elapsed
Definition: doxygen.cpp:240
CitationManager::instance
static CitationManager & instance()
Definition: cite.cpp:56
sqlite3gen.h
Definition::briefLine
virtual int briefLine() const =0
MemberDefMutable::setBriefDescription
virtual void setBriefDescription(const QCString &b, const QCString &briefFile, int briefLine)=0
ClassDefMutable::writeTagFile
virtual void writeTagFile(TextStream &)=0
MemberDefMutable
Definition: memberdef.h:296
findEnums
static void findEnums(const Entry *root)
Definition: doxygen.cpp:7015
ClangUsrMap
std::unordered_map< std::string, const Definition * > ClangUsrMap
Definition: doxygen.h:69
Entry::EXCEPTIONDOC_SEC
@ EXCEPTIONDOC_SEC
Definition: entry.h:76
getResolvedNamespace
NamespaceDef * getResolvedNamespace(const QCString &name)
Definition: namespacedef.cpp:1606
generateConceptDocs
static void generateConceptDocs()
Definition: doxygen.cpp:8534
getClass
ClassDef * getClass(const QCString &n)
Definition: classdef.cpp:4974
filename.h
declinfo.h
computeClassRelations
static void computeClassRelations()
Definition: doxygen.cpp:4895
FormulaManager::clear
void clear()
Definition: formula.cpp:461
Config::deinit
void deinit()
readConfiguration
void readConfiguration(int argc, char **argv)
Definition: doxygen.cpp:10738
MemberName::front
Ptr & front()
Definition: membername.h:66
MemberName::begin
iterator begin()
Definition: membername.h:52
ClassDef::getFileDef
virtual FileDef * getFileDef() const =0
Returns the namespace this compound is in, or 0 if it has a global scope.
code.h
pycode.h
parseFilesMultiThreading
static void parseFilesMultiThreading(const std::shared_ptr< Entry > &root)
parse the list of input files
Definition: doxygen.cpp:9898
OutputList::writeStyleInfo
void writeStyleInfo(int part)
Definition: outputlist.h:86
initDoxygen
void initDoxygen()
Definition: doxygen.cpp:10610
ClassDefMutable::distributeMemberGroupDocumentation
virtual void distributeMemberGroupDocumentation()=0
patternMatch
bool patternMatch(const FileInfo &fi, const StringVector &patList)
Definition: util.cpp:6279
ArgumentList::end
iterator end()
Definition: arguments.h:87
Doxygen::exampleNameLinkedMap
static FileNameLinkedMap * exampleNameLinkedMap
Definition: doxygen.h:86
isSpecialization
static bool isSpecialization(const ArgumentLists &srcTempArgLists, const ArgumentLists &dstTempArgLists)
Definition: doxygen.cpp:5474
GroupDef::isLinkableInProject
virtual bool isLinkableInProject() const =0
PageDef::setLocalToc
virtual void setLocalToc(const LocalToc &tl)=0
FileDef::docName
virtual const QCString & docName() const =0
findScopeFromQualifiedName
static Definition * findScopeFromQualifiedName(NamespaceDefMutable *startScope, const QCString &n, FileDef *fileScope, const TagInfo *tagInfo)
Definition: doxygen.cpp:793
ClassDef::Class
@ Class
Definition: classdef.h:107
Definition::docFile
virtual QCString docFile() const =0
stripTemplateSpecifiers
QCString stripTemplateSpecifiers(const QCString &s)
Definition: doxygen.cpp:697
Entry::PROTOCOLDOC_SEC
@ PROTOCOLDOC_SEC
Definition: entry.h:79
createJavaScriptSearchIndex
void createJavaScriptSearchIndex()
Definition: searchindex.cpp:751
rightScopeMatch
bool rightScopeMatch(const QCString &scope, const QCString &name)
Definition: util.cpp:863
HtmlGenerator::writeExternalSearchPage
static void writeExternalSearchPage()
Definition: htmlgen.cpp:2725
protectionLevelVisible
bool protectionLevelVisible(Protection prot)
Definition: util.cpp:6585
resolveClassNestingRelations
static void resolveClassNestingRelations()
Definition: doxygen.cpp:1312
addToIndices
static void addToIndices()
Definition: doxygen.cpp:7608
warn
void warn(const QCString &file, int line, const char *fmt,...)
Definition: message.cpp:151
LayoutDocManager::init
void init()
Definition: layout.cpp:1556
SectionManager::replace
SectionInfo * replace(const QCString &label, const QCString &fileName, int lineNr, const QCString &title, SectionType type, int level, const QCString &ref=QCString())
Replace an existing section with a new one Return a non-owning pointer to the newly added section
Definition: section.h:151
SectionInfo::ref
QCString ref() const
Definition: section.h:68
begin
DirIterator begin(DirIterator it) noexcept
Definition: dir.cpp:123
Definition::getLanguage
virtual SrcLangExt getLanguage() const =0
Returns the programming language this definition was written in.
isVarWithConstructor
static bool isVarWithConstructor(const Entry *root)
Definition: doxygen.cpp:2641
FileNameLinkedMap
Ordered dictionary of FileName objects.
Definition: filename.h:72
Entry::relates
QCString relates
related class (doc block)
Definition: entry.h:276
addVariableToClass
static MemberDef * addVariableToClass(const Entry *root, ClassDefMutable *cd, MemberType mtype, const QCString &type, const QCString &name, const QCString &args, bool fromAnnScope, MemberDef *fromAnnMemb, Protection prot, Relationship related)
Definition: doxygen.cpp:2186
ClassDefMutable::setIsStatic
virtual void setIsStatic(bool b)=0
Entry::Alias
static const uint64 Alias
Definition: entry.h:172
Entry::doc
QCString doc
documentation block (partly parsed)
Definition: entry.h:267
getOverloadDocs
QCString getOverloadDocs()
Definition: util.cpp:4212
Debug::isFlagSet
static bool isFlagSet(DebugMask mask)
Definition: debug.cpp:99
ArgumentList::begin
iterator begin()
Definition: arguments.h:86
Entry::UNIONDOC_SEC
@ UNIONDOC_SEC
Definition: entry.h:75
buildConceptDocList
static void buildConceptDocList(const Entry *root)
Definition: doxygen.cpp:1301
reg::Iterator
Iterator class to iterator through matches.
Definition: regex.h:242
ArgumentList::hasParameters
bool hasParameters() const
Definition: arguments.h:69
Doxygen::symbolMap
static SymbolMap< Definition > * symbolMap
Definition: doxygen.h:106
Portable::getenv
QCString getenv(const QCString &variable)
Definition: portable.cpp:279
Entry::markAsProcessed
void markAsProcessed() const
Definition: entry.h:233
Debug::FindMembers
@ FindMembers
Definition: debug.h:26
FileInfo::isRelative
bool isRelative() const
Definition: fileinfo.cpp:58
DirLinkedMap
A linked map of directories
Definition: dirdef.h:176
FileDef::getUsedNamespaces
virtual LinkedRefMap< const NamespaceDef > getUsedNamespaces() const =0
organizeSubGroups
static void organizeSubGroups(const Entry *root)
Definition: doxygen.cpp:458
end
DirIterator end(const DirIterator &) noexcept
Definition: dir.cpp:128
Doxygen::generatingXmlOutput
static bool generatingXmlOutput
Definition: doxygen.h:117
MemberName
Definition: membername.h:24
Entry::groupDocType
GroupDocType groupDocType
Definition: entry.h:297
initResources
void initResources()
QCString::contains
int contains(char c, bool cs=TRUE) const
Definition: qcstring.cpp:138
LatexGenerator::writeStyleSheetFile
static void writeStyleSheetFile(TextStream &t)
Definition: latexgen.cpp:523
StringUnorderedSet
std::unordered_set< std::string > StringUnorderedSet
Definition: containers.h:28
g_outputList
static OutputList * g_outputList
Definition: doxygen.cpp:173
ClassDef::templateMaster
virtual const ClassDef * templateMaster() const =0
Returns the template master of which this class is an instance.
NamespaceDefMutable::writeTagFile
virtual void writeTagFile(TextStream &)=0
Entry::FILEDOC_SEC
@ FILEDOC_SEC
Definition: entry.h:103
PageDef
A model of a page symbol.
Definition: pagedef.h:25
GroupDef
A model of a group of symbols.
Definition: groupdef.h:49
DefinitionMutable::setBodyDef
virtual void setBodyDef(const FileDef *fd)=0
Portable::setShortDir
void setShortDir()
Definition: portable.cpp:534
addClassToGroups
void addClassToGroups(const Entry *root, ClassDef *cd)
Definition: groupdef.cpp:1322
version
static void version(const bool extended)
Definition: doxygen.cpp:10515
HtmlGenerator::writeFooterFile
static void writeFooterFile(TextStream &t)
Definition: htmlgen.cpp:1112
MemberType_Service
@ MemberType_Service
Definition: types.h:289
Doxygen::inputNameLinkedMap
static FileNameLinkedMap * inputNameLinkedMap
Definition: doxygen.h:88
Entry::CATEGORYDOC_SEC
@ CATEGORYDOC_SEC
Definition: entry.h:80
commentcnv.h
NamespaceDefMutable::computeAnchors
virtual void computeAnchors()=0
MemberDefMutable::setMemberGroupId
virtual void setMemberGroupId(int id)=0
BaseInfo::name
QCString name
the name of the base class
Definition: entry.h:40
Argument::type
QCString type
Definition: arguments.h:50
buildConceptList
static void buildConceptList(const Entry *root)
Definition: doxygen.cpp:1292
Entry::SCOPE_MASK
@ SCOPE_MASK
Definition: entry.h:71
copyLatexStyleSheet
static void copyLatexStyleSheet()
Definition: doxygen.cpp:9628
MemberDef::isTypedefValCached
virtual bool isTypedefValCached() const =0
Entry::inbodyDocs
QCString inbodyDocs
documentation inside the body of a function
Definition: entry.h:273
MemberDefMutable::setMaxInitLines
virtual void setMaxInitLines(int lines)=0
Entry::NAMESPACE_SEC
@ NAMESPACE_SEC
Definition: entry.h:68
Entry::Union
static const uint64 Union
Definition: entry.h:128
Entry::metaData
QCString metaData
Slice metadata
Definition: entry.h:300
toNamespaceDefMutable
NamespaceDefMutable * toNamespaceDefMutable(Definition *d)
Definition: namespacedef.cpp:1579
findInheritedTemplateInstances
static void findInheritedTemplateInstances()
Definition: doxygen.cpp:4854
ConceptDefMutable::setFileDef
virtual void setFileDef(FileDef *fd)=0
NamespaceDefMutable::combineUsingRelations
virtual void combineUsingRelations(NamespaceDefSet &visitedNamespace)=0
findIncludedUsingDirectives
static void findIncludedUsingDirectives()
Definition: doxygen.cpp:2169
Config_updateList
#define Config_updateList(name,...)
Definition: config.h:42
Entry::Optional
static const uint64 Optional
Definition: entry.h:163
Entry::INCLUDED_SERVICE_SEC
@ INCLUDED_SERVICE_SEC
Definition: entry.h:117
NamespaceDef::isLinkableInProject
virtual bool isLinkableInProject() const =0
uint
unsigned uint
Definition: qcstring.h:40
toDefinitionMutable
DefinitionMutable * toDefinitionMutable(Definition *d)
Definition: definition.cpp:1956
ClangParser::instance
static ClangParser * instance()
Returns the one and only instance of the class
Definition: clangparser.cpp:29
Config_updateString
#define Config_updateString(name, value)
Definition: config.h:38
MemberDef::anchor
virtual QCString anchor() const =0
Entry::Struct
static const uint64 Struct
Definition: entry.h:127
SrcLangExt_ObjC
@ SrcLangExt_ObjC
Definition: types.h:49
findBaseClassesForClass
static void findBaseClassesForClass(const Entry *root, Definition *context, ClassDefMutable *masterCd, ClassDefMutable *instanceCd, FindBaseClassRelation_Mode mode, bool isArtificial, const std::unique_ptr< ArgumentList > &actualArgs=std::unique_ptr< ArgumentList >(), const TemplateNameMap &templateNames=TemplateNameMap())
Definition: doxygen.cpp:4215
Definition::getBodyDef
virtual const FileDef * getBodyDef() const =0
ClassDefMutable::setMetaData
virtual void setMetaData(const QCString &md)=0
GroupDef::writeTagFile
virtual void writeTagFile(TextStream &)=0
Preprocessor::addSearchDir
void addSearchDir(const QCString &dir)
Member
@ Member
Definition: types.h:38
OutputList
Class representing a list of output generators that are written to in parallel.
Definition: outputlist.h:37
ClassDefMutable::setClassName
virtual void setClassName(const QCString &name)=0
addDirToGroups
void addDirToGroups(const Entry *root, DirDef *dd)
Definition: groupdef.cpp:1376
Entry::Interface
static const uint64 Interface
Definition: entry.h:126
Definition::qualifiedName
virtual QCString qualifiedName() const =0
DefinitionMutable::setBriefDescription
virtual void setBriefDescription(const QCString &b, const QCString &briefFile, int briefLine)=0
MemberDefMutable::setProtection
virtual void setProtection(Protection p)=0
ClassDefMutable::reclassifyMember
virtual void reclassifyMember(MemberDefMutable *md, MemberType t)=0
FileDef::isSource
virtual bool isSource() const =0
Config::postProcess
void postProcess(bool clearHeaderAndFooter, bool compare=FALSE)
processTagLessClasses
static void processTagLessClasses(const ClassDef *rootCd, const ClassDef *cd, ClassDefMutable *tagParentCd, const QCString &prefix, int count)
Look through the members of class cd and its public members.
Definition: doxygen.cpp:1544
dot.h
entry.h
isClassSection
static bool isClassSection(const Entry *root)
Definition: doxygen.cpp:4802
addHtmlExtensionIfMissing
QCString addHtmlExtensionIfMissing(const QCString &fName)
Definition: util.cpp:5275
ArgumentList::setPureSpecifier
void setPureSpecifier(bool b)
Definition: arguments.h:114
MemberType_Function
@ MemberType_Function
Definition: types.h:277
MemberNameInfoLinkedMap
Definition: membername.h:126
findDocumentedEnumValues
static void findDocumentedEnumValues()
Definition: doxygen.cpp:7568
MemberDef
A model of a class/file/namespace member symbol.
Definition: memberdef.h:45
warn_uncond
void warn_uncond(const char *fmt,...)
Definition: message.cpp:194
findUsedTemplateInstances
static void findUsedTemplateInstances()
Definition: doxygen.cpp:4875
addGroupToGroups
void addGroupToGroups(const Entry *root, GroupDef *subGroup)
Definition: groupdef.cpp:1392
addConceptToContext
static void addConceptToContext(const Entry *root)
Definition: doxygen.cpp:1174
tagreader.h
MemberDef::hasCallerGraph
virtual bool hasCallerGraph() const =0
findEndOfTemplate
static int findEndOfTemplate(const QCString &s, int startPos)
Definition: doxygen.cpp:4351
Statistics::begin
void begin(const char *name)
Definition: doxygen.cpp:209
createFileDef
FileDef * createFileDef(const QCString &p, const QCString &n, const QCString &ref, const QCString &dn)
Definition: filedef.cpp:190
MemberDefMutable::setMemberSpecifiers
virtual void setMemberSpecifiers(uint64 s)=0
argListToString
QCString argListToString(const ArgumentList &al, bool useCanonicalType, bool showDefVals)
Definition: util.cpp:1149
GroupDef::findSectionsInDocumentation
virtual void findSectionsInDocumentation()=0
ConceptDefMutable::findSectionsInDocumentation
virtual void findSectionsInDocumentation()=0
Preprocessor::processFile
void processFile(const QCString &fileName, BufStr &input, BufStr &output)
findClassRelation
static bool findClassRelation(const Entry *root, Definition *context, ClassDefMutable *cd, const BaseInfo *bi, const TemplateNameMap &templateNames, FindBaseClassRelation_Mode mode, bool isArtificial)
Definition: doxygen.cpp:4447
NamespaceDefMutable::distributeMemberGroupDocumentation
virtual void distributeMemberGroupDocumentation()=0
Doxygen::subpageNestingLevel
static int subpageNestingLevel
Definition: doxygen.h:115
g_compoundKeywords
static StringSet g_compoundKeywords
Definition: doxygen.cpp:172
Definition::TypeNamespace
@ TypeNamespace
Definition: definition.h:89
ClassDef
A abstract class representing of a compound symbol.
Definition: classdef.h:103
MemberDef::getCachedTypedefVal
virtual const ClassDef * getCachedTypedefVal() const =0
DefinitionMutable::setArtificial
virtual void setArtificial(bool b)=0
classlist.h
MemberType_Slot
@ MemberType_Slot
Definition: types.h:283
findDefineDocumentation
static void findDefineDocumentation(Entry *root)
Definition: doxygen.cpp:8853
ClassDefMutable::mergeCategory
virtual void mergeCategory(ClassDef *category)=0
Argument::array
QCString array
Definition: arguments.h:53
Doxygen::clangAssistedParsing
static bool clangAssistedParsing
Definition: doxygen.h:119
QCString::stripWhiteSpace
QCString stripWhiteSpace() const
returns a copy of this string with leading and trailing whitespace removed
Definition: qcstring.h:243
Debug::Functions
@ Functions
Definition: debug.h:27
Config_getInt
#define Config_getInt(name)
Definition: config.h:34
FileInfo::size
size_t size() const
Definition: fileinfo.cpp:23
MemberDef::isFriend
virtual bool isFriend() const =0
generateXRefPages
static void generateXRefPages()
Definition: doxygen.cpp:5095
Doxygen::functionNameLinkedMap
static MemberNameLinkedMap * functionNameLinkedMap
Definition: doxygen.h:94
FileDef::computeAnchors
virtual void computeAnchors()=0
OutputList::disable
void disable(OutputGenerator::OutputType o)
Definition: outputlist.cpp:100
FileInfo::exists
bool exists() const
Definition: fileinfo.cpp:30
g_useOutputTemplate
static bool g_useOutputTemplate
Definition: doxygen.cpp:177
addNamespaceMemberNameToIndex
void addNamespaceMemberNameToIndex(const MemberDef *md)
Definition: index.cpp:2743
ClassDefMutable::makeTemplateArgument
virtual void makeTemplateArgument(bool b=TRUE)=0
addMemberToGroups
void addMemberToGroups(const Entry *root, MemberDef *md)
Definition: groupdef.cpp:1420
MemberDef::relatedAlso
virtual ClassDef * relatedAlso() const =0
stopDoxygen
static void stopDoxygen(int)
Definition: doxygen.cpp:11229
QCString::left
QCString left(size_t len) const
Definition: qcstring.h:212
LatexGenerator::writeHeaderFile
static void writeHeaderFile(TextStream &t)
Definition: latexgen.cpp:511
Entry::Inline
static const uint64 Inline
Definition: entry.h:147
MemberNameInfo
Definition: membername.h:98
findObjCMethodDefinitions
static void findObjCMethodDefinitions(const Entry *root)
Definition: doxygen.cpp:6988
Debug::startTimer
static void startTimer()
Definition: debug.cpp:133
eclipsehelp.h
message.h
MemberDef::excpString
virtual QCString excpString() const =0
findGlobalMember
static bool findGlobalMember(const Entry *root, const QCString &namespaceName, const QCString &type, const QCString &name, const QCString &tempArg, const QCString &, const QCString &decl, uint64 spec)
Definition: doxygen.cpp:5273
parseFile
static std::shared_ptr< Entry > parseFile(OutlineParserInterface &parser, FileDef *fd, const QCString &fn, ClangTUParser *clangParser, bool newTU)
Definition: doxygen.cpp:9834
FileDef::name
virtual QCString name() const =0
MemberDefMutable::setEnumBaseType
virtual void setEnumBaseType(const QCString &type)=0
MemberDef::isDefine
virtual bool isDefine() const =0
usage
static void usage(const QCString &name, const QCString &versionString)
Definition: doxygen.cpp:10544
ClassDef::memberNameInfoLinkedMap
virtual const MemberNameInfoLinkedMap & memberNameInfoLinkedMap() const =0
Returns a dictionary of all members.
MemberDef::virtualness
virtual Specifier virtualness(int count=0) const =0
substituteTemplatesInArgList
static void substituteTemplatesInArgList(const ArgumentLists &srcTempArgLists, const ArgumentLists &dstTempArgLists, const ArgumentList &src, ArgumentList &dst)
Definition: doxygen.cpp:5585
GroupLinkedMap
Definition: groupdef.h:123
Portable::sysTimerStart
void sysTimerStart()
Definition: portable.cpp:470
MemberDefMutable::setDefinitionTemplateParameterLists
virtual void setDefinitionTemplateParameterLists(const ArgumentLists &lists)=0
Definition::isAlias
virtual bool isAlias() const =0
DefinitionMutable::makePartOfGroup
virtual void makePartOfGroup(const GroupDef *gd)=0
MemberDef::isVariable
virtual bool isVariable() const =0
MemberDef::enumFieldList
virtual const MemberVector & enumFieldList() const =0
IndexList::addImageFile
void addImageFile(const QCString &name)
Definition: index.h:105
Doxygen::parserManager
static ParserManager * parserManager
Definition: doxygen.h:111
QCString::insert
QCString & insert(size_t index, const QCString &s)
Definition: qcstring.h:274
getConceptMutable
ConceptDefMutable * getConceptMutable(const QCString &key)
Definition: conceptdef.h:86
Definition::isAnonymous
virtual bool isAnonymous() const =0
ArgumentList::empty
bool empty() const
Definition: arguments.h:92
ParserManager::getOutlineParser
std::unique_ptr< OutlineParserInterface > getOutlineParser(const QCString &extension)
Gets the interface to the parser associated with a given extension.
Definition: parserintf.h:208
Entry::briefLine
int briefLine
line number at which the brief desc. was found
Definition: entry.h:271
buildGroupListFiltered
static void buildGroupListFiltered(const Entry *root, bool additional, bool includeExternal)
Definition: doxygen.cpp:339
addMemberSpecialization
static void addMemberSpecialization(const Entry *root, MemberName *mn, ClassDefMutable *cd, const QCString &funcType, const QCString &funcName, const QCString &funcArgs, const QCString &funcDecl, const QCString &exceptions, uint64 spec)
Definition: doxygen.cpp:6028
ClassDef::getTemplateInstances
virtual const TemplateInstanceList & getTemplateInstances() const =0
Returns a sorted dictionary with all template instances found for this template class.
convertCppComments
void convertCppComments(BufStr *inBuf, BufStr *outBuf, const QCString &fileName)
ClassDefMutable::findSectionsInDocumentation
virtual void findSectionsInDocumentation()=0
FileDef::addUsingDeclaration
virtual void addUsingDeclaration(const ClassDef *cd)=0
DefinitionMutable
Definition: definition.h:308
GroupDef::sortMemberLists
virtual void sortMemberLists()=0
ClassDefMutable::setFileDef
virtual void setFileDef(FileDef *fd)=0
LatexGenerator::init
static void init()
Definition: latexgen.cpp:465
lexscanner.h
ClassDef::baseClasses
virtual const BaseClassList & baseClasses() const =0
Returns the list of base classes from which this class directly inherits.
FileDef::writeSourceHeader
virtual void writeSourceHeader(OutputList &ol)=0
initSearchIndexer
void initSearchIndexer()
Definition: searchindex.cpp:1242
FileDef::combineUsingRelations
virtual void combineUsingRelations()=0
Statistics
Definition: doxygen.cpp:205
MemberDef::initializerLines
virtual int initializerLines() const =0
Debug::print
static void print(DebugMask mask, int prio, const char *fmt,...)
Definition: debug.cpp:57
findUsingDeclarations
static void findUsingDeclarations(const Entry *root, bool filterPythonPackages)
Definition: doxygen.cpp:1986
updateLanguageMapping
bool updateLanguageMapping(const QCString &extension, const QCString &language)
Definition: util.cpp:5469
MemberGroupInfoMap
std::unordered_map< int, std::unique_ptr< MemberGroupInfo > > MemberGroupInfoMap
Definition: membergroup.h:125
Doxygen::inputPaths
static StringSet inputPaths
Definition: doxygen.h:87
ConceptDefMutable::setInitializer
virtual void setInitializer(const QCString &init)=0
ClassDefMutable::writeDocumentationForInnerClasses
virtual void writeDocumentationForInnerClasses(OutputList &ol) const =0
htags.h
OutlineParserInterface::needsPreprocessing
virtual bool needsPreprocessing(const QCString &extension) const =0
Returns TRUE if the language identified by extension needs the C preprocessor to be run before feed t...
Entry::OBJCIMPL_SEC
@ OBJCIMPL_SEC
Definition: entry.h:114
generateTemplateFiles
void generateTemplateFiles(const QCString &templateDir)
Definition: context.cpp:9137
Entry::section
int section
entry type (see Sections);
Definition: entry.h:238
removeRedundantWhiteSpace
QCString removeRedundantWhiteSpace(const QCString &s)
Definition: util.cpp:544
NamespaceDef::getClasses
virtual ClassLinkedRefMap getClasses() const =0
arguments.h
ClassDefMutable::setClassSpecifier
virtual void setClassSpecifier(uint64 spec)=0
MemberDefMutable::setPrototype
virtual void setPrototype(bool p, const QCString &df, int line, int column)=0
NamespaceDef::displayName
virtual QCString displayName(bool=TRUE) const =0
generateFileSources
static void generateFileSources()
Definition: doxygen.cpp:7947
LatexGenerator::writeFooterFile
static void writeFooterFile(TextStream &t)
Definition: latexgen.cpp:517
sortMemberIndexLists
void sortMemberIndexLists()
Definition: index.cpp:2887
g_inputFiles
static StringVector g_inputFiles
Definition: doxygen.cpp:171
qstricmp
int qstricmp(const char *str1, const char *str2)
Definition: qcstring.cpp:433
initDefaultExtensionMapping
void initDefaultExtensionMapping()
Definition: util.cpp:5505
ArgumentList::setConstSpecifier
void setConstSpecifier(bool b)
Definition: arguments.h:112
Entry::ENUMDOC_SEC
@ ENUMDOC_SEC
Definition: entry.h:92
theTranslator
Translator * theTranslator
Definition: language.cpp:156
IndexList::finalize
void finalize()
Definition: index.h:91
Dir::absPath
std::string absPath() const
Definition: dir.cpp:305
Definition::isReference
virtual bool isReference() const =0
docbookgen.h
MemberNameLinkedMap
Ordered dictionary of MemberName objects.
Definition: membername.h:61
HtmlHelp
A class that generated the HTML Help specific files.
Definition: htmlhelp.h:32
Definition::inbodyDocumentation
virtual QCString inbodyDocumentation() const =0
IndexList
A list of index interfaces.
Definition: index.h:55
initWarningFormat
void initWarningFormat()
Definition: message.cpp:34
readTagFile
static void readTagFile(const std::shared_ptr< Entry > &root, const QCString &tagLine)
Definition: doxygen.cpp:9591
Definition::name
virtual QCString name() const =0
MemberDef::getClassDefMutable
ClassDefMutable * getClassDefMutable() const
Definition: memberdef.h:432
findEnumDocumentation
static void findEnumDocumentation(const Entry *root)
Definition: doxygen.cpp:7446
Doxygen::groupLinkedMap
static GroupLinkedMap * groupLinkedMap
Definition: doxygen.h:96
g_successfulRun
static bool g_successfulRun
Definition: doxygen.cpp:175
GroupDef::addFile
virtual void addFile(const FileDef *def)=0
ClassDef::getClasses
virtual ClassLinkedRefMap getClasses() const =0
returns the classes nested into this class
SrcLangExt_Cpp
@ SrcLangExt_Cpp
Definition: types.h:50
doxygen.h
SearchIndexIntf::addWord
virtual void addWord(const QCString &word, bool hiPriority)=0
qhp.h
MemberType_DCOP
@ MemberType_DCOP
Definition: types.h:285
writeDefaultLayoutFile
void writeDefaultLayoutFile(const QCString &fileName)
Definition: layout.cpp:1614
parserintf.h
resolveTypeDef
QCString resolveTypeDef(const Definition *context, const QCString &qualifiedName, const Definition **typedefContext)
Definition: util.cpp:364
Entry::endBodyLine
int endBodyLine
line number where the definition ends
Definition: entry.h:285
Definition::inbodyFile
virtual QCString inbodyFile() const =0
FormulaManager::HighDPI::On
@ On
Argument
This class contains the information about the argument of a function or template
Definition: arguments.h:26
Entry::localToc
LocalToc localToc
Definition: entry.h:299
MemberDef::resolveAlias
virtual MemberDef * resolveAlias()=0
MemberDef::definition
virtual QCString definition() const =0
MemberDef::getClassDef
virtual const ClassDef * getClassDef() const =0
MemberDefMutable::setAnchor
virtual void setAnchor()=0
MemberDefMutable::setInbodyDocumentation
virtual void setInbodyDocumentation(const QCString &d, const QCString &inbodyFile, int inbodyLine)=0
defgen.h
resolveUserReferences
static void resolveUserReferences()
Definition: doxygen.cpp:9199
language.h
NamespaceDefMutable::addMembersToMemberGroup
virtual void addMembersToMemberGroup()=0
Entry::Explicit
static const uint64 Explicit
Definition: entry.h:148
createTagLessInstance
static ClassDefMutable * createTagLessInstance(const ClassDef *rootCd, const ClassDef *templ, const QCString &fieldName)
Definition: doxygen.cpp:1461
SrcLangExt_Python
@ SrcLangExt_Python
Definition: types.h:52
NamespaceDefMutable::sortMemberLists
virtual void sortMemberLists()=0
CitationManager::generatePage
void generatePage()
Generate the citations page
Definition: cite.cpp:192
FileDef::sortMemberLists
virtual void sortMemberLists()=0
findUsedNamespace
static const NamespaceDef * findUsedNamespace(const LinkedRefMap< const NamespaceDef > &unl, const QCString &name)
Definition: doxygen.cpp:1816
NamespaceDef::findInnerCompound
virtual const Definition * findInnerCompound(const QCString &name) const =0
QCString::lower
QCString lower() const
Definition: qcstring.h:232
PlantumlManager::run
void run()
Run plant UML tool for all images
Definition: plantuml.cpp:282
addCodeOnlyMappings
void addCodeOnlyMappings()
Definition: util.cpp:5568
Entry::callerGraph
bool callerGraph
do we need to draw the caller graph?
Definition: entry.h:255
substituteTemplatesInString
static QCString substituteTemplatesInString(const ArgumentLists &srcTempArgLists, const ArgumentLists &dstTempArgLists, const std::string &src)
Definition: doxygen.cpp:5501
DefinitionMutable::setOuterScope
virtual void setOuterScope(Definition *d)=0
ClassDef::getTemplateParameterLists
virtual ArgumentLists getTemplateParameterLists() const =0
Returns the template parameter lists that form the template declaration of this class.
NullOutlineParser::parseInput
void parseInput(const QCString &file, const char *buf, const std::shared_ptr< Entry > &, ClangTUParser *)
Parses a single input file with the goal to build an Entry tree.
Definition: doxygen.cpp:10599
RTFGenerator::init
static void init()
Definition: rtfgen.cpp:170
Doxygen::memberGroupInfoMap
static MemberGroupInfoMap memberGroupInfoMap
Definition: doxygen.h:100
warn_undoc
void warn_undoc(const QCString &file, int line, const char *fmt,...)
Definition: message.cpp:170
PageLinkedMap
Definition: pagedef.h:74
getLanguageSpecificSeparator
QCString getLanguageSpecificSeparator(SrcLangExt lang, bool classScope)
Returns the scope separator to use given the programming language lang
Definition: util.cpp:6545
ClassDefMutable::setTypeConstraints
virtual void setTypeConstraints(const ArgumentList &al)=0
Translator::trMainPage
virtual QCString trMainPage()=0
countDataStructures
void countDataStructures()
Definition: index.cpp:87
MemberDefMutable::enableReferencesRelation
virtual void enableReferencesRelation(bool e)=0
ClassDefMutable::computeAnchors
virtual void computeAnchors()=0
MemberDef::isFunction
virtual bool isFunction() const =0
symbolresolver.h
findUsingDirectives
static void findUsingDirectives(const Entry *root)
Definition: doxygen.cpp:1829
findDEV
static void findDEV(const MemberNameLinkedMap &mnsd)
Definition: doxygen.cpp:7542
ClassDef::isBaseClass
virtual bool isBaseClass(const ClassDef *bcd, bool followInstances, int level=0) const =0
Returns TRUE iff bcd is a direct or indirect base class of this class.
startFile
void startFile(OutputList &ol, const QCString &name, const QCString &manName, const QCString &title, HighlightedItem hli, bool additionalIndices, const QCString &altSidebarName)
Definition: index.cpp:235
createClassDef
ClassDefMutable * createClassDef(const QCString &fileName, int startLine, int startColumn, const QCString &name, ClassDef::CompoundType ct, const QCString &ref, const QCString &fName, bool isSymbol, bool isJavaEnum)
Factory method to create a new ClassDef object
Definition: classdef.cpp:367
FileDef::writeSourceFooter
virtual void writeSourceFooter(OutputList &ol)=0
minClassDistance
int minClassDistance(const ClassDef *cd, const ClassDef *bcd, int level)
Definition: classdef.cpp:5026
defargs.h
fileparser.h
Debug::setFlag
static int setFlag(const QCString &label)
Definition: debug.cpp:82
SectionInfo::fileName
QCString fileName() const
Definition: section.h:70
DefinitionMutable::setLanguage
virtual void setLanguage(SrcLangExt lang)=0
Config::checkAndCorrect
void checkAndCorrect(bool quiet)
distributeMemberGroupDocumentation
static void distributeMemberGroupDocumentation()
Definition: doxygen.cpp:8652
reg::Match
Object representing the matching results.
Definition: regex.h:163
ParserManager::getCodeParser
std::unique_ptr< CodeParserInterface > getCodeParser(const QCString &extension)
Gets the interface to the parser associated with a given extension.
Definition: parserintf.h:217
docparser.h
ClassDefMutable::addUsedByClass
virtual void addUsedByClass(ClassDef *cd, const QCString &accessName, Protection prot)=0
LATEX_STYLE_EXTENSION
#define LATEX_STYLE_EXTENSION
Definition: latexgen.h:24
Definition::briefDescription
virtual QCString briefDescription(bool abbreviate=FALSE) const =0
showFileDefMatches
QCString showFileDefMatches(const FileNameLinkedMap *fnMap, const QCString &n)
Definition: util.cpp:3308
TRUE
#define TRUE
Definition: qcstring.h:36
Portable::correct_path
void correct_path()
Correct a possible wrong PATH variable
Definition: portable.cpp:515
Definition::getOutputFileBase
virtual QCString getOutputFileBase() const =0
checkIfTypedef
bool checkIfTypedef(const Definition *scope, const FileDef *fileScope, const QCString &n)
Definition: util.cpp:5684
addMembersToMemberGroup
static void addMembersToMemberGroup()
Definition: doxygen.cpp:8615
generateNamespaceClassDocs
static void generateNamespaceClassDocs(const ClassLinkedRefMap &classList)
Definition: doxygen.cpp:9391
Definition::getStartBodyLine
virtual int getStartBodyLine() const =0
Definition::getEndBodyLine
virtual int getEndBodyLine() const =0
MemberDef::getNamespaceDef
virtual const NamespaceDef * getNamespaceDef() const =0
documentedPages
int documentedPages
Definition: index.cpp:75
FileInfo::readLink
std::string readLink() const
Definition: fileinfo.cpp:84
findSectionsInDocumentation
static void findSectionsInDocumentation()
Definition: doxygen.cpp:8689
extractClassNameFromType
int extractClassNameFromType(const QCString &type, int &pos, QCString &name, QCString &templSpec, SrcLangExt lang)
Definition: util.cpp:4338
PageDef::setPageScope
virtual void setPageScope(Definition *)=0
Entry::FUNCTION_SEC
@ FUNCTION_SEC
Definition: entry.h:97
createNamespaceDefAlias
NamespaceDef * createNamespaceDefAlias(const Definition *newScope, const NamespaceDef *nd)
Factory method to create an alias of an existing namespace.
Definition: namespacedef.cpp:244
tempArgListToString
QCString tempArgListToString(const ArgumentList &al, SrcLangExt lang, bool includeDefault)
Definition: util.cpp:1194
Portable::system
int system(const QCString &command, const QCString &args, bool commandHasConsole=true)
Definition: portable.cpp:42
Dir::setCurrent
static bool setCurrent(const std::string &path)
Definition: dir.cpp:290
Doxygen::expandAsDefinedSet
static StringUnorderedSet expandAsDefinedSet
Definition: doxygen.h:101
setAnonymousEnumType
static void setAnonymousEnumType()
Definition: doxygen.cpp:8391
MemberDefMutable::invalidateTypedefValCache
virtual void invalidateTypedefValCache()=0
regex.h
SrcLangExt_Fortran
@ SrcLangExt_Fortran
Definition: types.h:53
Portable::getSysElapsedTime
double getSysElapsedTime()
Definition: portable.cpp:482
NamespaceDefMutable::insertUsedFile
virtual void insertUsedFile(FileDef *fd)=0
normalizeNonTemplateArgumentsInString
QCString normalizeNonTemplateArgumentsInString(const QCString &name, const Definition *context, const ArgumentList &formalArgs)
Definition: util.cpp:4412
ClassDef::Category
@ Category
Definition: classdef.h:112
Config_updateBool
#define Config_updateBool(name, value)
Definition: config.h:39
findDirDocumentation
static void findDirDocumentation(const Entry *root)
Definition: doxygen.cpp:8974
Entry::Service
static const uint64 Service
Definition: entry.h:135
EclipseHelp
Generator for Eclipse help files.
Definition: eclipsehelp.h:40
SymbolResolver::getTypedef
const MemberDef * getTypedef() const
In case a call to resolveClass() resolves to a type member (e.g.
Definition: symbolresolver.cpp:1103
FileDef::getPath
virtual QCString getPath() const =0
ClassDef::isSubClass
virtual bool isSubClass(ClassDef *bcd, int level=0) const =0
Returns TRUE iff bcd is a direct or indirect sub class of this class.
Entry::COMPOUNDDOC_MASK
@ COMPOUNDDOC_MASK
Definition: entry.h:84
Entry::inbodyLine
int inbodyLine
line number at which the body doc was found
Definition: entry.h:274
Entry::MEMBERDOC_SEC
@ MEMBERDOC_SEC
Definition: entry.h:99
ClassDef::Struct
@ Struct
Definition: classdef.h:108
DefinitionMutable::computeTooltip
virtual void computeTooltip()=0
vhdlcode.h
findClassWithinClassContext
static ClassDef * findClassWithinClassContext(Definition *context, ClassDef *cd, const QCString &name)
Definition: doxygen.cpp:4015
MemberDef::reimplements
virtual const MemberDef * reimplements() const =0
ManGenerator::init
static void init()
Definition: mangen.cpp:101
Htags::execute
static bool execute(const QCString &htmldir)
Definition: htags.cpp:38
MemberDef::protection
virtual Protection protection() const =0
LinkedMap::find
const T * find(const std::string &key) const
Find an object given the key.
Definition: linkedmap.h:60
TextStream::str
std::string str() const
Return the contents of the buffer as a std::string object
Definition: textstream.h:208
toClassDef
ClassDef * toClassDef(Definition *d)
Definition: classdef.cpp:4907
readDir
static void readDir(FileInfo *fi, FileNameLinkedMap *fnMap, StringUnorderedSet *exclSet, const StringVector *patList, const StringVector *exclPatList, StringVector *resultList, StringUnorderedSet *resultSet, bool errorIfNotExist, bool recursive, StringUnorderedSet *killSet, StringSet *paths)
Definition: doxygen.cpp:10193
ClassDefMutable::insertUsedFile
virtual void insertUsedFile(const FileDef *)=0
Doxygen::dirRelations
static DirRelationLinkedMap dirRelations
Definition: doxygen.h:110
GroupDef::anchor
virtual QCString anchor() const =0
Definition::partOfGroups
virtual const GroupList & partOfGroups() const =0
Entry::Protocol
static const uint64 Protocol
Definition: entry.h:130
DirRelationLinkedMap
Definition: dirdef.h:185
MemberDefMutable::setInheritsDocsFrom
virtual void setInheritsDocsFrom(const MemberDef *md)=0
FileInfo::isDir
bool isDir() const
Definition: fileinfo.cpp:70
SectionType::Page
@ Page
reflist.h
FileDef::insertConcept
virtual void insertConcept(const ConceptDef *cd)=0
NamespaceDefMutable::setMetaData
virtual void setMetaData(const QCString &m)=0
addEnumDocs
static void addEnumDocs(const Entry *root, MemberDefMutable *md)
Definition: doxygen.cpp:7408
FileInfo::isSymLink
bool isSymLink() const
Definition: fileinfo.cpp:77
QCString::fill
bool fill(char c, int len=-1)
Fills a string with a predefined character
Definition: qcstring.h:175
MemberDefMutable::setDocumentedEnumValues
virtual void setDocumentedEnumValues(bool value)=0
SrcLangExt_CSharp
@ SrcLangExt_CSharp
Definition: types.h:46
generateDirDocs
void generateDirDocs(OutputList &ol)
Definition: dirdef.cpp:1094
Config::writeTemplate
void writeTemplate(TextStream &t, bool shortList, bool updateOnly=FALSE)
ConceptLinkedMap
Definition: conceptdef.h:63
addFileMemberNameToIndex
void addFileMemberNameToIndex(const MemberDef *md)
Definition: index.cpp:2811
MemberName::end
iterator end()
Definition: membername.h:53
MemberDef::isStrong
virtual bool isStrong() const =0
Entry::stat
bool stat
static ?
Definition: entry.h:250
ClassDefMutable::insertSubClass
virtual void insertSubClass(ClassDef *, Protection p, Specifier s, const QCString &t=QCString())=0
perlmodgen.h
createConceptDef
ConceptDefMutable * createConceptDef(const QCString &fileName, int startLine, int startColumn, const QCString &name, const QCString &tagRef, const QCString &tagFile)
Definition: conceptdef.cpp:84
Entry::tagInfo
const TagInfo * tagInfo() const
Definition: entry.h:243
memberlist.h
getArg
static const char * getArg(int argc, char **argv, int &optInd)
Definition: doxygen.cpp:10583
MemberDefMutable::copyArgumentNames
virtual void copyArgumentNames(const MemberDef *bmd)=0
SectionManager::add
SectionInfo * add(const SectionInfo &si)
Add a new section given the data of an existing section.
Definition: section.h:135
addRefItem
void addRefItem(const RefItemVector &sli, const QCString &key, const QCString &prefix, const QCString &name, const QCString &title, const QCString &args, const Definition *scope)
Definition: util.cpp:4880
Mappers::freeMappers
static void freeMappers()
Definition: cmdmapper.cpp:266
Definition::TypeClass
@ TypeClass
Definition: definition.h:87
DocumentedOnly
@ DocumentedOnly
Definition: doxygen.cpp:263
MemberDefMutable::invalidateCachedArgumentTypes
virtual void invalidateCachedArgumentTypes()=0
OutputList::startContents
void startContents()
Definition: outputlist.h:361
Definition::definitionType
virtual DefType definitionType() const =0
ClassDef::subClasses
virtual const BaseClassList & subClasses() const =0
Returns the list of sub classes that directly derive from this class
MemberDefMutable::setNamespace
virtual void setNamespace(const NamespaceDef *nd)=0
dirdef.h
IndexList::initialize
void initialize()
Definition: index.h:89
MemberType_Property
@ MemberType_Property
Definition: types.h:286
Entry::GROUPDOC_SEC
@ GROUPDOC_SEC
Definition: entry.h:107
MemberDef::declaration
virtual QCString declaration() const =0
FileDef::findSectionsInDocumentation
virtual void findSectionsInDocumentation()=0
NamespaceDefMutable::countMembers
virtual void countMembers()=0
Definition::briefFile
virtual QCString briefFile() const =0
mergeArguments
void mergeArguments(ArgumentList &srcAl, ArgumentList &dstAl, bool forceNameOverwrite)
Definition: util.cpp:2008
cleanUpDoxygen
void cleanUpDoxygen()
Definition: doxygen.cpp:10694
MemberType_Dictionary
@ MemberType_Dictionary
Definition: types.h:291
documentedFiles
int documentedFiles
Definition: index.cpp:74
getTemplateArgumentsFromName
std::unique_ptr< ArgumentList > getTemplateArgumentsFromName(const QCString &name, const ArgumentLists &tArgLists)
Definition: doxygen.cpp:874
generateDEF
void generateDEF()
Definition: defgen.cpp:526
Entry::USINGDECL_SEC
@ USINGDECL_SEC
Definition: entry.h:111
MemberDef::isForeign
virtual bool isForeign() const =0
Qhp
Definition: qhp.h:23
PageDef::setFileName
virtual void setFileName(const QCString &name)=0
clearAll
void clearAll()
Definition: doxygen.cpp:179
getQchFileName
static QCString getQchFileName()
Definition: doxygen.cpp:11352
ClassDef::compoundType
virtual CompoundType compoundType() const =0
Returns the type of compound this is, i.e.
getPrefixIndex
int getPrefixIndex(const QCString &name)
Definition: util.cpp:3357
QCString::setNum
QCString & setNum(short n)
Definition: qcstring.h:372
Portable::pathListSeparator
QCString pathListSeparator()
Definition: portable.cpp:356
ArgumentList::size
size_t size() const
Definition: arguments.h:93
NamespaceDefMutable::addListReferences
virtual void addListReferences()=0
Debug::elapsedTime
static double elapsedTime()
Definition: debug.cpp:138
Entry::fileName
QCString fileName
file this entry was extracted from
Definition: entry.h:290
computeIdealCacheParam
static int computeIdealCacheParam(size_t v)
Definition: doxygen.cpp:10726
LookupInfo::typeDef
const MemberDef * typeDef
Definition: doxygen.h:64
addClassToContext
static void addClassToContext(const Entry *root)
Definition: doxygen.cpp:961
FTVHelp::generateTreeViewImages
static void generateTreeViewImages()
Definition: ftvhelp.cpp:763
DocbookGenerator::init
static void init()
Definition: docbookgen.cpp:311
Grouping::groupname
QCString groupname
name of the group
Definition: types.h:95
generateFileDocs
static void generateFileDocs()
Definition: doxygen.cpp:8151
Debug::Variables
@ Variables
Definition: debug.h:28
MemberDef::getMemberSpecifiers
virtual uint64 getMemberSpecifiers() const =0
Entry::Exception
static const uint64 Exception
Definition: entry.h:129
parseTagFile
void parseTagFile(const std::shared_ptr< Entry > &root, const char *fullName)
Definition: tagreader.cpp:1566
ClangParser::createTUParser
std::unique_ptr< ClangTUParser > createTUParser(const FileDef *fd) const
Definition: clangparser.cpp:937
Entry::inbodyFile
QCString inbodyFile
file in which the body doc was found
Definition: entry.h:275
adjustConfiguration
void adjustConfiguration()
adjust globals that depend on configuration settings.
Definition: doxygen.cpp:11153
Entry::NAMESPACEDOC_SEC
@ NAMESPACEDOC_SEC
Definition: entry.h:77
pyscanner.h
Entry::lang
SrcLangExt lang
programming language in which this entry was found
Definition: entry.h:294
MemberDef::qualifiedName
virtual QCString qualifiedName() const =0
Config::compareDoxyfile
void compareDoxyfile(TextStream &t)
Doxygen::searchIndex
static SearchIndexIntf * searchIndex
Definition: doxygen.h:105
ArgumentLists
std::vector< ArgumentList > ArgumentLists
Definition: arguments.h:138
NullOutlineParser::needsPreprocessing
bool needsPreprocessing(const QCString &) const
Returns TRUE if the language identified by extension needs the C preprocessor to be run before feed t...
Definition: doxygen.cpp:10600
buildCompleteMemberLists
static void buildCompleteMemberLists()
Definition: doxygen.cpp:7917
GroupDef::sortSubGroups
virtual void sortSubGroups()=0
Entry::typeConstr
ArgumentList typeConstr
where clause (C#) for type constraints
Definition: entry.h:282
findMember
static void findMember(const Entry *root, const QCString &relates, const QCString &type, const QCString &args, QCString funcDecl, bool overloaded, bool isFunc)
Definition: doxygen.cpp:6165
generatePageDocs
static void generatePageDocs()
Definition: doxygen.cpp:9267
MemberDefMutable::setDeclFile
virtual void setDeclFile(const QCString &df, int line, int column)=0
Protected
@ Protected
Definition: types.h:26
ClassDefMutable::addListReferences
virtual void addListReferences()=0
QCString::mid
QCString mid(size_t index, size_t len=static_cast< size_t >(-1)) const
Definition: qcstring.h:224
substitute
QCString substitute(const QCString &s, const QCString &src, const QCString &dst)
substitute all occurrences of src in s by dst
Definition: qcstring.cpp:465
Argument::defval
QCString defval
Definition: arguments.h:54
FileInfo::dirPath
std::string dirPath(bool absPath=true) const
Definition: fileinfo.cpp:137
MemberOf
@ MemberOf
Definition: types.h:35
initNamespaceMemberIndices
void initNamespaceMemberIndices()
Definition: index.cpp:2733
Translator::trPage
virtual QCString trPage(bool first_capital, bool singular)=0
Entry::brief
QCString brief
brief description (doc block)
Definition: entry.h:270
MemberDefMutable::setRelatedAlso
virtual void setRelatedAlso(ClassDef *cd)=0
Doxygen::filterDBFileName
static QCString filterDBFileName
Definition: doxygen.h:113
MemberDef::isLinkableInProject
virtual bool isLinkableInProject() const =0
FormulaManager::Format::Bitmap
@ Bitmap
extractNamespaceName
void extractNamespaceName(const QCString &scopeName, QCString &className, QCString &namespaceName, bool allowEmptyClass)
Definition: util.cpp:3733
Entry::bodyLine
int bodyLine
line number of the body in the source
Definition: entry.h:283
MemberDefMutable::enableReferencedByRelation
virtual void enableReferencedByRelation(bool e)=0
readInputFile
bool readInputFile(const QCString &fileName, BufStr &inBuf, bool filter, bool isSourceCode)
read a file name fileName and optionally filter and transcode it
Definition: util.cpp:6158
MemberDef::templateArguments
virtual const ArgumentList & templateArguments() const =0
RefItemVector
std::vector< RefItem * > RefItemVector
Definition: reflist.h:132
parseInput
void parseInput()
Definition: doxygen.cpp:11558
FormulaManager
Definition: formula.h:27
NamespaceDef::getConcepts
virtual ConceptLinkedRefMap getConcepts() const =0
Entry::initLines
int initLines
define/variable initializer lines to show
Definition: entry.h:249
DefinitionMutable::setId
virtual void setId(const QCString &name)=0
ClangTUParser::parse
void parse()
Parse the file given at construction time as a translation unit This file should already be preproces...
Definition: clangparser.cpp:916
MemberDefMutable::enableCallGraph
virtual void enableCallGraph(bool e)=0
Entry::Strong
static const uint64 Strong
Definition: entry.h:169
buildExampleList
static void buildExampleList(Entry *root)
Definition: doxygen.cpp:9286
Doxygen::memberNameLinkedMap
static MemberNameLinkedMap * memberNameLinkedMap
Definition: doxygen.h:93
NamespaceDef::isLinkable
virtual bool isLinkable() const =0
RTFGenerator::preProcessFileInplace
static bool preProcessFileInplace(const QCString &path, const QCString &name)
This is an API to a VERY brittle RTF preprocessor that combines nested RTF files.
Definition: rtfgen.cpp:2297
ClassDefMutable::addTypeConstraints
virtual void addTypeConstraints()=0
ClassDefMutable::addMembersToMemberGroup
virtual void addMembersToMemberGroup()=0
Entry
Represents an unstructured piece of information, about an entity found in the sources.
Definition: entry.h:61
HtmlGenerator::writeSearchPage
static void writeSearchPage()
Definition: htmlgen.cpp:2634
Config_getBool
#define Config_getBool(name)
Definition: config.h:33
NamespaceDefMutable::findSectionsInDocumentation
virtual void findSectionsInDocumentation()=0
ClassDefMutable::setAnonymousEnumType
virtual void setAnonymousEnumType()=0
ClassDef::Protocol
@ Protocol
Definition: classdef.h:111
GroupDef::getOutputFileBase
virtual QCString getOutputFileBase() const =0
buildListOfUsingDecls
static void buildListOfUsingDecls(const Entry *root)
Definition: doxygen.cpp:1973
buildPageList
static void buildPageList(Entry *root)
Definition: doxygen.cpp:9036
writeTagFile
static void writeTagFile()
Definition: doxygen.cpp:11244
fortranscanner.h
MemberDefMutable::moveDeclArgumentList
virtual void moveDeclArgumentList(std::unique_ptr< ArgumentList > al)=0
Entry::children
const std::vector< std::shared_ptr< Entry > > & children() const
Definition: entry.h:205
parseFilesSingleThreading
static void parseFilesSingleThreading(const std::shared_ptr< Entry > &root)
parse the list of input files
Definition: doxygen.cpp:10040
layout.h
toNamespaceDef
NamespaceDef * toNamespaceDef(Definition *d)
Definition: namespacedef.cpp:1541
buildClassList
static void buildClassList(const Entry *root)
Definition: doxygen.cpp:1147
SearchIndexIntf::write
virtual void write(const QCString &file)=0
FormulaManager::hasFormulas
bool hasFormulas() const
Definition: formula.cpp:490
Doxygen::htmlFileExtension
static QCString htmlFileExtension
Definition: doxygen.h:103
MemberDef::isDocsForDefinition
virtual bool isDocsForDefinition() const =0
MemberDef::getEnumScope
virtual const MemberDef * getEnumScope() const =0
SectionManager::instance
static SectionManager & instance()
returns a reference to the singleton
Definition: section.h:172
htmlgen.h
rtfgen.h
Entry::PAGEDOC_SEC
@ PAGEDOC_SEC
Definition: entry.h:95
Entry::explicitExternal
bool explicitExternal
explicitly defined as external?
Definition: entry.h:251
BaseInfo::virt
Specifier virt
virtualness
Definition: entry.h:42
reg::Ex
Class representing a regular expression.
Definition: regex.h:48
FileDef::writeTagFile
virtual void writeTagFile(TextStream &t)=0
MemberDefMutable::setDocumentation
virtual void setDocumentation(const QCString &d, const QCString &docFile, int docLine, bool stripWhiteSpace=TRUE)=0
MemberDef::isEnumerate
virtual bool isEnumerate() const =0
readFileOrDirectory
void readFileOrDirectory(const QCString &s, FileNameLinkedMap *fnMap, StringUnorderedSet *exclSet, const StringVector *patList, const StringVector *exclPatList, StringVector *resultList, StringUnorderedSet *resultSet, bool recursive, bool errorIfNotExist, StringUnorderedSet *killSet, StringSet *paths)
Definition: doxygen.cpp:10302
generateOutputViaTemplate
void generateOutputViaTemplate()
Definition: context.cpp:8994
Config::updateObsolete
void updateObsolete()
Cache::remove
void remove(const K &key)
Removes entry key from the cache.
Definition: cache.h:85
MemberDef::isExternal
virtual bool isExternal() const =0
msg
void msg(const char *fmt,...)
Definition: message.cpp:53
Related
@ Related
Definition: types.h:38
MemberDefMutable::makeForeign
virtual void makeForeign()=0
MemberName::size
size_t size() const
Definition: membername.h:63
BufStr::curPos
uint curPos() const
Definition: bufstr.h:112
writeGraphInfo
void writeGraphInfo(OutputList &ol)
Definition: index.cpp:3686
ClassDefMutable::writeDocumentation
virtual void writeDocumentation(OutputList &ol) const =0
finalizeSearchIndexer
void finalizeSearchIndexer()
Definition: searchindex.cpp:1264
ParserManager::registerParser
void registerParser(const QCString &name, OutlineParserFactory outlineParserFactory, CodeParserFactory codeParserFactory)
Registers an additional parser.
Definition: parserintf.h:179
LayoutDocManager::instance
static LayoutDocManager & instance()
Returns a reference to this singleton.
Definition: layout.cpp:1574
Definition::documentation
virtual QCString documentation() const =0
Entry::relatesType
RelatesType relatesType
how relates is handled
Definition: entry.h:277
checkPageRelations
static void checkPageRelations()
Definition: doxygen.cpp:9179
ClassDef::isReference
virtual bool isReference() const =0
Returns TRUE if this class is imported via a tag file
SearchIndexIntf::setCurrentDoc
virtual void setCurrentDoc(const Definition *ctx, const QCString &anchor, bool isSourceFile)=0
term
void term(const char *fmt,...)
Definition: message.cpp:220
writeIndexHierarchy
void writeIndexHierarchy(OutputList &ol)
Definition: index.cpp:5155
Entry::EXAMPLE_LINENO_SEC
@ EXAMPLE_LINENO_SEC
Definition: entry.h:118
MemberType_Event
@ MemberType_Event
Definition: types.h:287
computeMemberRelations
static void computeMemberRelations()
Definition: doxygen.cpp:7802
DefinesPerFileList
std::unordered_map< std::string, DefineList > DefinesPerFileList
Definition: define.h:49
computeTemplateClassRelations
static void computeTemplateClassRelations()
Definition: doxygen.cpp:4927
Definition::getOuterScope
virtual Definition * getOuterScope() const =0
QCString::endsWith
bool endsWith(const char *s) const
Definition: qcstring.h:420
MemberDef::isEnumValue
virtual bool isEnumValue() const =0
mergeCategories
static void mergeCategories()
Definition: doxygen.cpp:7895
OutlineParserInterface
Abstract interface for outline parsers.
Definition: parserintf.h:42
ClassDef::Singleton
@ Singleton
Definition: classdef.h:115
g_dumpSymbolMap
static bool g_dumpSymbolMap
Definition: doxygen.cpp:176
FileInfo
Minimal replacement for QFileInfo.
Definition: fileinfo.h:22
ClassDef::isCSharp
virtual bool isCSharp() const =0
Returns TRUE if this class is implemented in C#
generateNamespaceConceptDocs
static void generateNamespaceConceptDocs(const ConceptLinkedRefMap &conceptList)
Definition: doxygen.cpp:9467
VhdlDocGen::computeVhdlComponentRelations
static void computeVhdlComponentRelations()
Definition: vhdldocgen.cpp:2501
FileDef::absFilePath
virtual QCString absFilePath() const =0
ConceptDefMutable::writeTagFile
virtual void writeTagFile(TextStream &)=0
sqlcode.h
FileInfo::absFilePath
std::string absFilePath() const
Definition: fileinfo.cpp:101
MemberType_Sequence
@ MemberType_Sequence
Definition: types.h:290
Definition::isArtificial
virtual bool isArtificial() const =0
Entry::Category
static const uint64 Category
Definition: entry.h:131
qPrint
const char * qPrint(const char *s)
Definition: qcstring.h:589
Debug::Time
@ Time
Definition: debug.h:35
LatexGenerator
Generator for LaTeX output.
Definition: latexgen.h:79
SrcLangExt_IDL
@ SrcLangExt_IDL
Definition: types.h:44
vhdlCorrectMemberProperties
static void vhdlCorrectMemberProperties()
Definition: doxygen.cpp:7766
ConceptLinkedRefMap
Definition: conceptdef.h:67
ClassDefMutable::setTagLessReference
virtual void setTagLessReference(const ClassDef *cd)=0
exitDoxygen
static void exitDoxygen()
Definition: doxygen.cpp:11316
MemberDef::getFileDef
virtual const FileDef * getFileDef() const =0
Config_getString
#define Config_getString(name)
Definition: config.h:32
context.h
Dir::setPath
void setPath(const std::string &path)
Definition: dir.cpp:171
DefinitionMutable::setBodySegment
virtual void setBodySegment(int defLine, int bls, int ble)=0
addMembersToIndex
static void addMembersToIndex()
Definition: doxygen.cpp:7576
generateSqlite3
void generateSqlite3()
Definition: sqlite3gen.cpp:2588
Qhp::getQhpFileName
static QCString getQhpFileName()
Definition: qhp.cpp:286
findMainPage
static void findMainPage(Entry *root)
Definition: doxygen.cpp:9063
Definition::getDefFileName
virtual QCString getDefFileName() const =0
SectionInfo
class that provide information about a section.
Definition: section.h:49
DocSets
A class that generates docset files.
Definition: docsets.h:32
xmlcode.h
generateClassDocs
static void generateClassDocs()
Definition: doxygen.cpp:8526
escapeAliases
static void escapeAliases()
Definition: doxygen.cpp:10388
DefinitionMutable::setRefItems
virtual void setRefItems(const RefItemVector &sli)=0
MemberDef::hasCallGraph
virtual bool hasCallGraph() const =0
OutputList::generateDoc
void generateDoc(const QCString &fileName, int startLine, const Definition *ctx, const MemberDef *md, const QCString &docStr, bool indexWords, bool isExample, const QCString &exampleName, bool singleLine, bool linkFromIndex, bool markdownSupport)
Definition: outputlist.cpp:142
Doxygen::insideMainPage
static bool insideMainPage
Definition: doxygen.h:84
GroupDef::computeAnchors
virtual void computeAnchors()=0
PageDef::addInnerCompound
virtual void addInnerCompound(const Definition *)=0
Entry::artificial
bool artificial
Artificially introduced item
Definition: entry.h:296
addSTLSupport
void addSTLSupport(std::shared_ptr< Entry > &root)
Add stub entries for the most used classes in the standard template library
Definition: stlsupport.cpp:264
ClassDefMutable::countMembers
virtual void countMembers()=0
Argument::name
QCString name
Definition: arguments.h:52
Config::parse
bool parse(const QCString &fileName, bool update=FALSE)
compareDoxyfile
static void compareDoxyfile()
Definition: doxygen.cpp:9573
Entry::EMPTY_SEC
@ EMPTY_SEC
Definition: entry.h:94
TemplateInstances
@ TemplateInstances
Definition: doxygen.cpp:262
MemberDef::argumentList
virtual const ArgumentList & argumentList() const =0
addVariableToFile
static MemberDef * addVariableToFile(const Entry *root, MemberType mtype, const QCString &scope, const QCString &type, const QCString &name, const QCString &args, bool fromAnnScope, MemberDef *fromAnnMemb)
Definition: doxygen.cpp:2351
convertNameToFile
QCString convertNameToFile(const QCString &name, bool allowDots, bool allowUnderscore)
Definition: util.cpp:3604
config.h
computePageRelations
static void computePageRelations(Entry *root)
Definition: doxygen.cpp:9145
Entry::Mutable
static const uint64 Mutable
Definition: entry.h:149
MemberListType_pubAttribs
@ MemberListType_pubAttribs
Definition: types.h:118
Portable::sysTimerStop
void sysTimerStop()
Definition: portable.cpp:475
ParserManager
Manages programming language parsers.
Definition: parserintf.h:145
Doxygen::namespaceLinkedMap
static NamespaceLinkedMap * namespaceLinkedMap
Definition: doxygen.h:97
removeAnonymousScopes
QCString removeAnonymousScopes(const QCString &str)
Definition: util.cpp:166
addListReferences
static void addListReferences()
Definition: doxygen.cpp:5029
ClassDef::displayName
virtual QCString displayName(bool includeScope=TRUE) const =0
Returns the name as it is appears in the documentation
ASSERT
#define ASSERT(x)
Definition: qcstring.h:44
groupdef.h
Statistics::stat
Definition: doxygen.cpp:237
ClassDefMutable::setUsedOnly
virtual void setUsedOnly(bool b)=0
Portable::pid
unsigned int pid()
Definition: portable.cpp:207
QCString::data
const char * data() const
Returns a pointer to the contents of the string in the form of a 0-terminated C string
Definition: qcstring.h:153
generateOutput
void generateOutput()
Definition: doxygen.cpp:12168
Doxygen::mscFileNameLinkedMap
static FileNameLinkedMap * mscFileNameLinkedMap
Definition: doxygen.h:91
initClassMemberIndices
void initClassMemberIndices()
Definition: index.cpp:2649
ClangTUParser
Clang parser object for a single translation unit, which consists of a source file and the directly o...
Definition: clangparser.h:21
ClassDef::getMemberList
virtual MemberList * getMemberList(MemberListType lt) const =0
Returns the members in the list identified by lt
Entry::inside
QCString inside
name of the class in which documents are found
Definition: entry.h:280
FileInfo::isReadable
bool isReadable() const
Definition: fileinfo.cpp:44
Signal
@ Signal
Definition: types.h:32
TagInfo::fileName
QCString fileName
Definition: entry.h:51
Debug::clearFlag
static void clearFlag(const QCString &label)
Definition: debug.cpp:89
Doxygen::lookupCache
static Cache< std::string, LookupInfo > * lookupCache
Definition: doxygen.h:108
NamespaceDefMutable
Definition: namespacedef.h:106
emoji.h
LookupInfo::classDef
const ClassDef * classDef
Definition: doxygen.h:63
Debug::Classes
@ Classes
Definition: debug.h:30
FileDef
A model of a file symbol.
Definition: filedef.h:73
qstrcmp
int qstrcmp(const char *str1, const char *str2)
Definition: qcstring.h:82
DefinitionMutable::addInnerCompound
virtual void addInnerCompound(const Definition *d)=0
generateClassList
static void generateClassList(const ClassLinkedMap &classList)
Definition: doxygen.cpp:8443
StringMap
std::map< std::string, std::string > StringMap
Definition: containers.h:29
buildNamespaceList
static void buildNamespaceList(const Entry *root)
Definition: doxygen.cpp:1648
Entry::read
QCString read
property read accessor
Definition: entry.h:278
addEnumValuesToEnums
static void addEnumValuesToEnums(const Entry *root)
Definition: doxygen.cpp:7182
BaseInfo
This class stores information about an inheritance relation
Definition: entry.h:35
mergeScopes
QCString mergeScopes(const QCString &leftScope, const QCString &rightScope)
Definition: util.cpp:4667
Dir::exists
bool exists() const
Definition: dir.cpp:199
MemberType_Define
@ MemberType_Define
Definition: types.h:276
Entry::HEADER_SEC
@ HEADER_SEC
Definition: entry.h:89
plantuml.h
SrcLangExt_VHDL
@ SrcLangExt_VHDL
Definition: types.h:54
FormulaManager::generateImages
void generateImages(const QCString &outputDir, Format format, HighDPI hd=HighDPI::Off) const
Definition: formula.cpp:130
GroupDef::addMembersToMemberGroup
virtual void addMembersToMemberGroup()=0
Entry::VARIABLE_SEC
@ VARIABLE_SEC
Definition: entry.h:96
scanner.h
Entry::subGrouping
bool subGrouping
automatically group class members?
Definition: entry.h:253
Entry::sli
RefItemVector sli
special lists (test/todo/bug/deprecated/..) this entry is in
Definition: entry.h:293
parseFuncDecl
void parseFuncDecl(const QCString &decl, const SrcLangExt lang, QCString &clName, QCString &type, QCString &name, QCString &args, QCString &funcTempList, QCString &exceptions)
Portable::setenv
void setenv(const QCString &variable, const QCString &value)
Definition: portable.cpp:246
ClassDefMutable::setRequiresClause
virtual void setRequiresClause(const QCString &req)=0
Entry::PACKAGEDOC_SEC
@ PACKAGEDOC_SEC
Definition: entry.h:113
FileDef::parseSource
virtual void parseSource(ClangTUParser *clangParser)=0
MemberDefMutable::moveArgumentList
virtual void moveArgumentList(std::unique_ptr< ArgumentList > al)=0
Entry::type
QCString type
member type
Definition: entry.h:239
conceptdef.h
FileDef::writeDocumentation
virtual void writeDocumentation(OutputList &ol)=0
Portable::isAbsolutePath
bool isAbsolutePath(const QCString &fileName)
Definition: portable.cpp:496
Dir::iterator
DirIterator iterator() const
Definition: dir.cpp:181
FileDef::distributeMemberGroupDocumentation
virtual void distributeMemberGroupDocumentation()=0
EmojiEntityMapper::instance
static EmojiEntityMapper * instance()
Returns the one and only instance of the Emoji entity mapper
Definition: emoji.cpp:1536
Statistics::print
void print()
Definition: doxygen.cpp:221
FTVHelp
A class that generates a dynamic tree view side panel.
Definition: ftvhelp.h:36
ClassDefMutable::insertMember
virtual void insertMember(MemberDef *)=0
Entry::parent
Entry * parent() const
Definition: entry.h:200
addMemberFunction
static void addMemberFunction(const Entry *root, MemberName *mn, const QCString &scopeName, const QCString &namespaceName, const QCString &className, const QCString &funcTyp, const QCString &funcName, const QCString &funcArgs, const QCString &funcTempList, const QCString &exceptions, const QCString &type, const QCString &args, bool isFriend, uint64 spec, const QCString &relates, const QCString &funcDecl, bool overloaded, bool isFunc)
Definition: doxygen.cpp:5680
MemberDefMutable::setExplicitExternal
virtual void setExplicitExternal(bool b, const QCString &df, int line, int column)=0
Doxygen::suppressDocWarnings
static bool suppressDocWarnings
Definition: doxygen.h:112
SearchIndexIntf
Definition: searchindex.h:67
checkExtension
bool checkExtension(const QCString &fName, const QCString &ext)
Definition: util.cpp:5270
Property
@ Property
Definition: types.h:32
Statistics::end
void end()
Definition: doxygen.cpp:215
FileInfo::fileName
std::string fileName() const
Definition: fileinfo.cpp:118
Entry::exception
QCString exception
throw specification
Definition: entry.h:281
Entry::proto
bool proto
prototype ?
Definition: entry.h:252
OutputList::add
void add()
Definition: outputlist.h:46
Entry::bitfields
QCString bitfields
member's bit fields
Definition: entry.h:260
Statistics::stats
std::vector< stat > stats
Definition: doxygen.cpp:244
toClassDefMutable
ClassDefMutable * toClassDefMutable(Definition *d)
Definition: classdef.cpp:4944
findMainPageTagFiles
static void findMainPageTagFiles(Entry *root)
Definition: doxygen.cpp:9133
FileDef::writeSourceBody
virtual void writeSourceBody(OutputList &ol, ClangTUParser *clangParser)=0
createGroupDef
GroupDef * createGroupDef(const QCString &fileName, int line, const QCString &name, const QCString &title, const QCString &refFileName)
Definition: groupdef.cpp:162
Entry::DEFINEDOC_SEC
@ DEFINEDOC_SEC
Definition: entry.h:104
expandAlias
std::string expandAlias(const std::string &aliasName, const std::string &aliasValue)
Definition: util.cpp:6060
ftvhelp.h
MemberDefMutable::setDefinition
virtual void setDefinition(const QCString &d)=0
portable.h
Portable versions of functions that are platform dependent.
Entry::referencesRelation
bool referencesRelation
do we need to show the references relation?
Definition: entry.h:257
searchindex.h
ClassDefMutable::setProtection
virtual void setProtection(Protection p)=0
bufstr.h
make_parser_factory
std::function< std::unique_ptr< T >) > make_parser_factory()
Definition: doxygen.cpp:10605
NamespaceDef::getStructs
virtual ClassLinkedRefMap getStructs() const =0
copyStyleSheet
static void copyStyleSheet()
Definition: doxygen.cpp:9655
reg::search
bool search(const std::string &str, Match &match, const Ex &re, size_t pos)
Search in a given string str starting at position pos for a match against regular expression re.
Definition: regex.cpp:718
LinkedRefMap::find
const T * find(const std::string &key) const
find an object given the key.
Definition: linkedmap.h:243
ConceptDefMutable::writeDocumentation
virtual void writeDocumentation(OutputList &ol)=0
convertToCompoundType
static ClassDef::CompoundType convertToCompoundType(int section, uint64 specifier)
Definition: doxygen.cpp:904
SymbolResolver::resolveClass
const ClassDef * resolveClass(const Definition *scope, const QCString &name, bool maybeUnlinkable=false, bool mayBeHidden=false)
Find the class definition matching name within the scope set.
Definition: symbolresolver.cpp:1033
copyLogo
static void copyLogo(const QCString &outputOption)
Definition: doxygen.cpp:9696
MemberDef::hasReferencesRelation
virtual bool hasReferencesRelation() const =0
Entry::argList
ArgumentList argList
member arguments as a list
Definition: entry.h:261
SymbolMap< Definition >
DocbookGenerator
Definition: docbookgen.h:93
MemberDefMutable::enableCallerGraph
virtual void enableCallerGraph(bool e)=0
DefinitionMutable::setHidden
virtual void setHidden(bool b)=0
searchInputFiles
void searchInputFiles()
Definition: doxygen.cpp:11369
ClassDef::Exception
@ Exception
Definition: classdef.h:113
dir.h
ClassLinkedMap
Definition: classlist.h:26
LinkedMap::clear
void clear()
Definition: linkedmap.h:225
Doxygen::classLinkedMap
static ClassLinkedMap * classLinkedMap
Definition: doxygen.h:78
LayoutDocManager::parse
void parse(const QCString &fileName)
Parses a user provided layout
Definition: layout.cpp:1600
MemberDef::initializer
virtual const QCString & initializer() const =0
getScopeFragment
int getScopeFragment(const QCString &s, int p, int *l)
Definition: util.cpp:4702
ClassDefMutable::addMembersToTemplateInstance
virtual void addMembersToTemplateInstance(const ClassDef *cd, const ArgumentList &templateArguments, const QCString &templSpec)=0
NamespaceDefMutable::addUsingDirective
virtual void addUsingDirective(const NamespaceDef *nd)=0
Definition::getStartDefLine
virtual int getStartDefLine() const =0
Entry::Singleton
static const uint64 Singleton
Definition: entry.h:136
addSourceReferences
static void addSourceReferences()
Definition: doxygen.cpp:8215
EmojiEntityMapper::writeEmojiFile
void writeEmojiFile(TextStream &t)
Writes the list of supported emojis to the given file.
Definition: emoji.cpp:1567
readAliases
void readAliases()
Definition: doxygen.cpp:10432
MemberDefMutable::setFileDef
virtual void setFileDef(const FileDef *fd)=0
Dir::mkdir
bool mkdir(const std::string &path, bool acceptsAbsPath=true) const
Definition: dir.cpp:237
MemberDef::isRelated
virtual bool isRelated() const =0
Foreign
@ Foreign
Definition: types.h:38
guessSection
int guessSection(const QCString &name)
Definition: util.cpp:331
util.h
A bunch of utility functions.
Statistics::stat::name
const char * name
Definition: doxygen.cpp:239
TemplateNameMap
std::map< std::string, int > TemplateNameMap
Definition: classdef.h:93
ClassDef::qualifiedNameWithTemplateParameters
virtual QCString qualifiedNameWithTemplateParameters(const ArgumentLists *actualParams=0, uint *actualParamIndex=0) const =0
Entry::docFile
QCString docFile
file in which the documentation was found
Definition: entry.h:269
replaceNamespaceAliases
void replaceNamespaceAliases(QCString &scope, int i)
Definition: util.cpp:5300
HtmlGenerator::init
static void init()
Definition: htmlgen.cpp:930
MemberDef::typeString
virtual QCString typeString() const =0
MemberDefMutable::setEnumClassScope
virtual void setEnumClassScope(const ClassDef *cd)=0
buildDirectories
void buildDirectories()
Definition: dirdef.cpp:1005
GroupDef::hasGroupTitle
virtual bool hasGroupTitle() const =0
Definition::localName
virtual QCString localName() const =0
MemberDef::requiresClause
virtual QCString requiresClause() const =0
buildScopeFromQualifiedName
static Definition * buildScopeFromQualifiedName(const QCString &name_, SrcLangExt lang, const TagInfo *tagInfo)
Definition: doxygen.cpp:723
toConceptDefMutable
ConceptDefMutable * toConceptDefMutable(Definition *d)
Definition: conceptdef.cpp:713
OutputList::enable
void enable(OutputGenerator::OutputType o)
Definition: outputlist.cpp:108
HtmlGenerator::writeHeaderFile
static void writeHeaderFile(TextStream &t, const QCString &cssname)
Definition: htmlgen.cpp:1106
findFunctionPtr
static int findFunctionPtr(const std::string &type, SrcLangExt lang, int *pLength=0)
Definition: doxygen.cpp:2599
Translator::trDir
virtual QCString trDir(bool first_capital, bool singular)=0
ClassDef::isForwardDeclared
virtual bool isForwardDeclared() const =0
Returns TRUE if this class represents a forward declaration of a template class
Dir::cleanDirPath
static std::string cleanDirPath(const std::string &path)
Definition: dir.cpp:297
ConceptDefMutable::setTemplateArguments
virtual void setTemplateArguments(const ArgumentList &al)=0
NamespaceDefSet
std::set< const NamespaceDef * > NamespaceDefSet
Definition: namespacedef.h:39
GroupDef::setGroupTitle
virtual void setGroupTitle(const QCString &newtitle)=0
Relationship
Relationship
Kind of member relationship
Definition: types.h:38
Entry::write
QCString write
property write accessor
Definition: entry.h:279
Simple
@ Simple
Definition: types.h:35
ClassDef::isLinkable
virtual bool isLinkable() const =0
return TRUE iff a link to this class is possible (either within this project, or as a cross-reference...
Entry::groups
std::vector< Grouping > groups
list of groups this entry belongs to
Definition: entry.h:288
stringToArgumentList
std::unique_ptr< ArgumentList > stringToArgumentList(SrcLangExt lang, const QCString &argsString, QCString *extraTypeChars=0)
findTagLessClasses
static void findTagLessClasses(std::vector< ClassDefMutable * > &candidates, const ClassDef *cd)
Definition: doxygen.cpp:1607
MemberDefMutable::setReimplements
virtual void setReimplements(const MemberDef *md)=0
MemberList
A list of MemberDef objects as shown in documentation sections.
Definition: memberlist.h:81
QCString::stripPrefix
bool stripPrefix(const QCString &prefix)
Definition: qcstring.h:197
matchArguments2
bool matchArguments2(const Definition *srcScope, const FileDef *srcFileScope, const ArgumentList *srcAl, const Definition *dstScope, const FileDef *dstFileScope, const ArgumentList *dstAl, bool checkCV)
Definition: util.cpp:1919
filterMemberDocumentation
static void filterMemberDocumentation(const Entry *root, const QCString &relates)
Definition: doxygen.cpp:6807
resolveSymlink
static std::string resolveSymlink(const std::string &path)
Definition: doxygen.cpp:10120
ClassLinkedRefMap
Definition: classlist.h:30
createTemplateInstanceMembers
static void createTemplateInstanceMembers()
Definition: doxygen.cpp:7876
uint64
uint64_t uint64
Definition: qcstring.h:43
NullOutlineParser
/dev/null outline parser
Definition: doxygen.cpp:10596
addMemberToSearchIndex
static void addMemberToSearchIndex(const MemberDef *md)
Definition: searchindex.cpp:631
QCString::right
QCString right(size_t len) const
Definition: qcstring.h:217
ClassDefMutable::setTemplateArguments
virtual void setTemplateArguments(const ArgumentList &al)=0
ManGenerator
Generator for Man page output.
Definition: mangen.h:24
getTemplateArgumentsInName
static TemplateNameMap getTemplateArgumentsInName(const ArgumentList &templateArguments, const std::string &name)
Definition: doxygen.cpp:3987
QCString::prepend
QCString & prepend(const char *s)
Definition: qcstring.h:339
QCString::resize
bool resize(size_t newlen)
Resizes the string to hold newlen characters (this value should also count the 0-terminator).
Definition: qcstring.h:164
qstrlen
uint qstrlen(const char *str)
Definition: qcstring.h:65
MemberDef::memberType
virtual MemberType memberType() const =0
openOutputFile
bool openOutputFile(const QCString &outFile, std::ofstream &f)
Definition: util.cpp:7039
computeDirDependencies
void computeDirDependencies()
Definition: dirdef.cpp:1078
docsets.h
QCString::sprintf
QCString & sprintf(const char *format,...)
Definition: qcstring.cpp:24
HtmlGenerator::writeTabData
static void writeTabData()
Additional initialization after indices have been created
Definition: htmlgen.cpp:1013
debug.h
NamespaceDefMutable::setFileName
virtual void setFileName(const QCString &fn)=0
Entry::Published
static const uint64 Published
Definition: entry.h:186
PageDef::setShowLineNo
virtual void setShowLineNo(bool)=0
NamespaceLinkedMap
Definition: namespacedef.h:41
LookupInfo
Definition: doxygen.h:58
Entry::FILE_MASK
@ FILE_MASK
Definition: entry.h:90
ClassDef::templateArguments
virtual const ArgumentList & templateArguments() const =0
Returns the template arguments of this class
getClassMutable
ClassDefMutable * getClassMutable(const QCString &key)
Definition: classdef.h:485
combineUsingRelations
static void combineUsingRelations()
Definition: doxygen.cpp:8590
Doxygen::clangUsrMap
static ClangUsrMap * clangUsrMap
Definition: doxygen.h:107
computeMemberReferences
static void computeMemberReferences()
Definition: doxygen.cpp:4996
ClassDefSet
std::set< const ClassDef * > ClassDefSet
Definition: classdef.h:95
getResolvedNamespaceMutable
NamespaceDefMutable * getResolvedNamespaceMutable(const QCString &key)
Definition: namespacedef.h:157
Slot
@ Slot
Definition: types.h:32
MemberDef::getGroupDef
virtual const GroupDef * getGroupDef() const =0
vhdljjparser.h
Doxygen::spaces
static QCString spaces
Definition: doxygen.h:116
vhdldocgen.h
NamespaceDefMutable::insertMember
virtual void insertMember(MemberDef *md)=0
GroupDef::setGroupScope
virtual void setGroupScope(Definition *d)=0
endFile
void endFile(OutputList &ol, bool skipNavIndex, bool skipEndContents, const QCString &navPath)
Definition: index.cpp:254
OutputList::cleanup
void cleanup()
Definition: outputlist.h:479
Cache::clear
void clear()
Clears all values in the cache.
Definition: cache.h:144
FileDef::insertMember
virtual void insertMember(MemberDef *md)=0
findUsingDeclImports
static void findUsingDeclImports(const Entry *root)
Definition: doxygen.cpp:2075
DefinitionMutable::mergeReferencedBy
virtual void mergeReferencedBy(const Definition *other)=0
DCOP
@ DCOP
Definition: types.h:32
Config_getList
#define Config_getList(name)
Definition: config.h:37
RTFGenerator::writeExtensionsFile
static void writeExtensionsFile(TextStream &t)
Definition: rtfgen.cpp:118
scopeIsTemplate
static bool scopeIsTemplate(const Definition *d)
Definition: doxygen.cpp:5490
FALSE
#define FALSE
Definition: qcstring.h:33
ClassDef::isTemplate
virtual bool isTemplate() const =0
Returns TRUE if this class is a template
g_classEntries
static std::multimap< std::string, const Entry * > g_classEntries
Definition: doxygen.cpp:170
ClassDefMutable::mergeMembers
virtual void mergeMembers()=0
Entry::Enum
static const uint64 Enum
Definition: entry.h:134
Doxygen::exampleLinkedMap
static PageLinkedMap * exampleLinkedMap
Definition: doxygen.h:81
BufStr::addChar
void addChar(char c)
Definition: bufstr.h:57
ClassDef::anchor
virtual QCString anchor() const =0
Duplicate
@ Duplicate
Definition: types.h:35
Doxygen::includeNameLinkedMap
static FileNameLinkedMap * includeNameLinkedMap
Definition: doxygen.h:85
LinkedMap::size
size_t size() const
Definition: linkedmap.h:223
OutputGenerator::Man
@ Man
Definition: outputgen.h:333
QCString
This is an alternative implementation of QCString.
Definition: qcstring.h:108
Entry::EXPORTED_INTERFACE_SEC
@ EXPORTED_INTERFACE_SEC
Definition: entry.h:116
Entry::req
QCString req
C++20 requires clause
Definition: entry.h:301