doxygen  1.8.18
About: Doxygen is a source code documentation generator tool for C++, C, Objective-C, C#, PHP, Java, Python, IDL (diverse flavors), Fortran, VHDL, Tcl, and to some extent D. Different output formats are supported.
  Fossies Dox: doxygen-1.8.18.src.tar.gz  ("unofficial" and yet experimental doxygen-generated source code documentation)  

doxygen.cpp
Go to the documentation of this file.
1 
16 #if !defined(_WIN32) || defined(__CYGWIN__)
17 #define _DEFAULT_SOURCE 1
18 #endif
19 
20 #include <locale.h>
21 
22 #include <qfileinfo.h>
23 #include <qfile.h>
24 #include <qdir.h>
25 #include <qdict.h>
26 #include <qregexp.h>
27 #include <qstrlist.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31 #include <qtextcodec.h>
32 #include <errno.h>
33 #include <qptrdict.h>
34 #include <qtextstream.h>
35 
36 #include <algorithm>
37 #include <unordered_map>
38 #include <memory>
39 
40 #include "version.h"
41 #include "doxygen.h"
42 #include "scanner.h"
43 #include "entry.h"
44 #include "index.h"
45 #include "message.h"
46 #include "config.h"
47 #include "util.h"
48 #include "pre.h"
49 #include "tagreader.h"
50 #include "dot.h"
51 #include "msc.h"
52 #include "docparser.h"
53 #include "dirdef.h"
54 #include "outputlist.h"
55 #include "declinfo.h"
56 #include "htmlgen.h"
57 #include "latexgen.h"
58 #include "mangen.h"
59 #include "language.h"
60 #include "debug.h"
61 #include "htmlhelp.h"
62 #include "qhp.h"
63 #include "ftvhelp.h"
64 #include "defargs.h"
65 #include "rtfgen.h"
66 #include "sqlite3gen.h"
67 #include "xmlgen.h"
68 #include "docbookgen.h"
69 #include "defgen.h"
70 #include "perlmodgen.h"
71 #include "reflist.h"
72 #include "pagedef.h"
73 #include "bufstr.h"
74 #include "commentcnv.h"
75 #include "cmdmapper.h"
76 #include "searchindex.h"
77 #include "parserintf.h"
78 #include "htags.h"
79 #include "pycode.h"
80 #include "pyscanner.h"
81 #include "fortrancode.h"
82 #include "fortranscanner.h"
83 #include "xmlcode.h"
84 #include "sqlcode.h"
85 #include "code.h"
86 #include "portable.h"
87 #include "vhdljjparser.h"
88 #include "vhdldocgen.h"
89 #include "vhdlcode.h"
90 #include "eclipsehelp.h"
91 #include "cite.h"
92 #include "markdown.h"
93 #include "arguments.h"
94 #include "memberlist.h"
95 #include "layout.h"
96 #include "groupdef.h"
97 #include "classlist.h"
98 #include "namespacedef.h"
99 #include "filename.h"
100 #include "membername.h"
101 #include "membergroup.h"
102 #include "docsets.h"
103 #include "formula.h"
104 #include "settings.h"
105 #include "context.h"
106 #include "fileparser.h"
107 #include "emoji.h"
108 #include "plantuml.h"
109 #include "stlsupport.h"
110 
111 // provided by the generated file resources.cpp
112 extern void initResources();
113 
114 #if !defined(_WIN32) || defined(__CYGWIN__)
115 #include <signal.h>
116 #define HAS_SIGNALS
117 #endif
118 
119 // globally accessible variables
129 StringDict Doxygen::aliasDict(257); // aliases
137 StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases
138 StringDict Doxygen::tagDestinationDict(257); // all tag locations
139 QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
140 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
142 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
157 //Store *Doxygen::symbolStorage;
169 
170 // locally accessible globals
171 static std::unordered_map< std::string, const Entry* > g_classEntries;
173 static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds
174 static OutputList *g_outputList = 0; // list of output generating objects
175 static QDict<FileDef> g_usingDeclarations(1009); // used classes
176 static bool g_successfulRun = FALSE;
177 static bool g_dumpSymbolMap = FALSE;
179 
180 void clearAll()
181 {
183  //g_excludeNameDict.clear();
184  //delete g_outputList; g_outputList=0;
185 
202 }
203 
205 {
206  public:
207  Statistics() { stats.setAutoDelete(TRUE); }
208  void begin(const char *name)
209  {
210  msg("%s", name);
211  stat *entry= new stat(name,0);
212  stats.append(entry);
213  time.restart();
214  }
215  void end()
216  {
217  stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
218  }
219  void print()
220  {
221  bool restore=FALSE;
223  {
224  Debug::clearFlag("time");
225  restore=TRUE;
226  }
227  msg("----------------------\n");
229  stat *s;
230  for ( sli.toFirst(); (s=sli.current()); ++sli )
231  {
232  msg("Spent %.3f 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  };
246 } g_s;
247 
248 
250 {
251 #if 0
252  fprintf(stderr,"--- inputNameLinkedMap stats ----\n");
253  Doxygen::inputNameLinkedMap->statistics();
254  fprintf(stderr,"--- includeNameDict stats ----\n");
255  Doxygen::includeNameDict->statistics();
256  fprintf(stderr,"--- exampleNameDict stats ----\n");
257  Doxygen::exampleNameDict->statistics();
258  fprintf(stderr,"--- imageNameDict stats ----\n");
259  Doxygen::imageNameDict->statistics();
260  fprintf(stderr,"--- dotFileNameDict stats ----\n");
261  Doxygen::dotFileNameDict->statistics();
262  fprintf(stderr,"--- mscFileNameDict stats ----\n");
263  Doxygen::mscFileNameDict->statistics();
264  fprintf(stderr,"--- diaFileNameDict stats ----\n");
265  Doxygen::diaFileNameDict->statistics();
266 #endif
267  //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
268  //g_excludeNameDict.statistics();
269  fprintf(stderr,"--- aliasDict stats ----\n");
270  Doxygen::aliasDict.statistics();
271  fprintf(stderr,"--- typedefDict stats ----\n");
272  fprintf(stderr,"--- namespaceAliasDict stats ----\n");
273  Doxygen::namespaceAliasDict.statistics();
274  fprintf(stderr,"--- tagDestinationDict stats ----\n");
275  Doxygen::tagDestinationDict.statistics();
276  fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
277  g_compoundKeywordDict.statistics();
278  fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
279  Doxygen::expandAsDefinedDict.statistics();
280  fprintf(stderr,"--- memGrpInfoDict stats ----\n");
282 }
283 
284 
285 
286 static void addMemberDocs(const Entry *root,MemberDef *md, const char *funcDecl,
287  const ArgumentList *al,bool over_load,uint64 spec);
288 static void findMember(const Entry *root,
289  const QCString &relates,
290  const QCString &type,
291  const QCString &args,
292  QCString funcDecl,
293  bool overloaded,
294  bool isFunc
295  );
296 
298 {
302 };
303 
304 static bool findClassRelation(
305  const Entry *root,
306  Definition *context,
307  ClassDef *cd,
308  const BaseInfo *bi,
309  QDict<int> *templateNames,
310  /*bool insertUndocumented*/
312  bool isArtificial
313  );
314 
315 //----------------------------------------------------------------------------
316 
317 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
318  FileDef *fileScope,const TagInfo *tagInfo);
319 
320 static void addPageToContext(PageDef *pd,Entry *root)
321 {
322  if (root->parent()) // add the page to it's scope
323  {
324  QCString scope = root->parent()->name;
325  if (root->parent()->section==Entry::PACKAGEDOC_SEC)
326  {
327  scope=substitute(scope,".","::");
328  }
329  scope = stripAnonymousNamespaceScope(scope);
330  scope+="::"+pd->name();
332  if (d)
333  {
334  pd->setPageScope(d);
335  }
336  }
337 }
338 
339 static void addRelatedPage(Entry *root)
340 {
341  GroupDef *gd=0;
342  for (const Grouping &g : root->groups)
343  {
344  if (!g.groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g.groupname))) break;
345  }
346  //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
347  QCString doc;
348  if (root->brief.isEmpty())
349  {
350  doc=root->doc+root->inbodyDocs;
351  }
352  else
353  {
354  doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
355  }
356 
357  PageDef *pd = addRelatedPage(root->name,root->args,doc,
358  root->docFile,root->docLine,
359  root->sli,
360  gd,root->tagInfo(),
361  FALSE,
362  root->lang
363  );
364  if (pd)
365  {
366  pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
367  pd->addSectionsToDefinition(root->anchors);
368  pd->setLocalToc(root->localToc);
369  addPageToContext(pd,root);
370  }
371 }
372 
373 static void buildGroupListFiltered(const Entry *root,bool additional, bool includeExternal)
374 {
375  if (root->section==Entry::GROUPDOC_SEC && !root->name.isEmpty() &&
376  ((!includeExternal && root->tagInfo()==0) ||
377  ( includeExternal && root->tagInfo()!=0))
378  )
379  {
380  if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
381  (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
382  {
383  GroupDef *gd = Doxygen::groupSDict->find(root->name);
384  //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
385  // root->type.data(),root->name.data(),additional,includeExternal,gd);
386 
387  if (gd)
388  {
389  if ( !gd->hasGroupTitle() )
390  {
391  gd->setGroupTitle( root->type );
392  }
393  else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
394  {
395  warn( root->fileName,root->startLine,
396  "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
397  qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
398  }
399  gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
400  gd->setDocumentation( root->doc, root->docFile, root->docLine );
401  gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
402  gd->addSectionsToDefinition(root->anchors);
403  gd->setRefItems(root->sli);
404  gd->setLanguage(root->lang);
405  }
406  else
407  {
408  if (root->tagInfo())
409  {
410  gd = createGroupDef(root->fileName,root->startLine,root->name,root->type,root->tagInfo()->fileName);
411  gd->setReference(root->tagInfo()->tagName);
412  }
413  else
414  {
415  gd = createGroupDef(root->fileName,root->startLine,root->name,root->type);
416  }
417  gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
418  // allow empty docs for group
419  gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
420  gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
421  gd->addSectionsToDefinition(root->anchors);
422  Doxygen::groupSDict->append(root->name,gd);
423  gd->setRefItems(root->sli);
424  gd->setLanguage(root->lang);
425  }
426  }
427  }
428  for (const auto &e : root->children()) buildGroupListFiltered(e.get(),additional,includeExternal);
429 }
430 
431 static void buildGroupList(const Entry *root)
432 {
433  // --- first process only local groups
434  // first process the @defgroups blocks
436  // then process the @addtogroup, @weakgroup blocks
438 
439  // --- then also process external groups
440  // first process the @defgroups blocks
442  // then process the @addtogroup, @weakgroup blocks
444 }
445 
446 static void findGroupScope(const Entry *root)
447 {
448  if (root->section==Entry::GROUPDOC_SEC && !root->name.isEmpty() &&
449  root->parent() && !root->parent()->name.isEmpty())
450  {
451  GroupDef *gd;
452  if ((gd=Doxygen::groupSDict->find(root->name)))
453  {
454  QCString scope = root->parent()->name;
455  if (root->parent()->section==Entry::PACKAGEDOC_SEC)
456  {
457  scope=substitute(scope,".","::");
458  }
459  scope = stripAnonymousNamespaceScope(scope);
460  scope+="::"+gd->name();
462  if (d)
463  {
464  gd->setGroupScope(d);
465  }
466  }
467  }
468  for (const auto &e : root->children()) findGroupScope(e.get());
469 }
470 
471 static void organizeSubGroupsFiltered(const Entry *root,bool additional)
472 {
473  if (root->section==Entry::GROUPDOC_SEC && !root->name.isEmpty())
474  {
475  if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
476  (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
477  {
478  GroupDef *gd;
479  if ((gd=Doxygen::groupSDict->find(root->name)))
480  {
481  //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
482  addGroupToGroups(root,gd);
483  }
484  }
485  }
486  for (const auto &e : root->children()) organizeSubGroupsFiltered(e.get(),additional);
487 }
488 
489 static void organizeSubGroups(const Entry *root)
490 {
491  //printf("Defining groups\n");
492  // first process the @defgroups blocks
494  //printf("Additional groups\n");
495  // then process the @addtogroup, @weakgroup blocks
497 }
498 
499 //----------------------------------------------------------------------
500 
501 static void buildFileList(const Entry *root)
502 {
503  if (((root->section==Entry::FILEDOC_SEC) ||
504  ((root->section & Entry::FILE_MASK) && Config_getBool(EXTRACT_ALL))) &&
505  !root->name.isEmpty() && !root->tagInfo() // skip any file coming from tag files
506  )
507  {
508  bool ambig;
510  if (!fd || ambig)
511  {
512  int save_ambig = ambig;
513  // use the directory of the file to see if the described file is in the same
514  // directory as the describing file.
515  QCString fn = root->fileName;
516  int newIndex=fn.findRev('/');
517  fd=findFileDef(Doxygen::inputNameLinkedMap,fn.left(newIndex) + "/" + root->name,ambig);
518  if (!fd) ambig = save_ambig;
519  }
520  //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
521  if (fd && !ambig)
522  {
523  //printf("Adding documentation!\n");
524  // using FALSE in setDocumentation is small hack to make sure a file
525  // is documented even if a \file command is used without further
526  // documentation
527  fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
528  fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
529  fd->addSectionsToDefinition(root->anchors);
530  fd->setRefItems(root->sli);
531  for (const Grouping &g : root->groups)
532  {
533  GroupDef *gd=0;
534  if (!g.groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g.groupname)))
535  {
536  gd->addFile(fd);
537  fd->makePartOfGroup(gd);
538  //printf("File %s: in group %s\n",fd->name().data(),s->data());
539  }
540  }
541  }
542  else
543  {
544  const char *fn = root->fileName.data();
545  QCString text(4096);
546  text.sprintf("the name '%s' supplied as "
547  "the argument in the \\file statement ",
548  qPrint(root->name));
549  if (ambig) // name is ambiguous
550  {
551  text+="matches the following input files:\n";
553  text+="Please use a more specific name by "
554  "including a (larger) part of the path!";
555  }
556  else // name is not an input file
557  {
558  text+="is not an input file";
559  }
560  warn(fn,root->startLine,"%s", text.data());
561  }
562  }
563  for (const auto &e : root->children()) buildFileList(e.get());
564 }
565 
566 static void addIncludeFile(ClassDef *cd,FileDef *ifd,const Entry *root)
567 {
568  if (
569  (!root->doc.stripWhiteSpace().isEmpty() ||
570  !root->brief.stripWhiteSpace().isEmpty() ||
571  Config_getBool(EXTRACT_ALL)
572  ) && root->protection!=Private
573  )
574  {
575  //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
576 
577  bool local=Config_getBool(FORCE_LOCAL_INCLUDES);
578  QCString includeFile = root->includeFile;
579  if (!includeFile.isEmpty() && includeFile.at(0)=='"')
580  {
581  local = TRUE;
582  includeFile=includeFile.mid(1,includeFile.length()-2);
583  }
584  else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
585  {
586  local = FALSE;
587  includeFile=includeFile.mid(1,includeFile.length()-2);
588  }
589 
590  bool ambig;
591  FileDef *fd=0;
592  // see if we need to include a verbatim copy of the header file
593  //printf("root->includeFile=%s\n",root->includeFile.data());
594  if (!includeFile.isEmpty() &&
595  (fd=findFileDef(Doxygen::inputNameLinkedMap,includeFile,ambig))==0
596  )
597  { // explicit request
598  QCString text;
599  text.sprintf("the name '%s' supplied as "
600  "the argument of the \\class, \\struct, \\union, or \\include command ",
601  qPrint(includeFile)
602  );
603  if (ambig) // name is ambiguous
604  {
605  text+="matches the following input files:\n";
607  text+="Please use a more specific name by "
608  "including a (larger) part of the path!";
609  }
610  else // name is not an input file
611  {
612  text+="is not an input file";
613  }
614  warn(root->fileName,root->startLine, "%s", text.data());
615  }
616  else if (includeFile.isEmpty() && ifd &&
617  // see if the file extension makes sense
619  { // implicit assumption
620  fd=ifd;
621  }
622 
623  // if a file is found, we mark it as a source file.
624  if (fd)
625  {
626  QCString iName = !root->includeName.isEmpty() ?
627  root->includeName : includeFile;
628  if (!iName.isEmpty()) // user specified include file
629  {
630  if (iName.at(0)=='<') local=FALSE; // explicit override
631  else if (iName.at(0)=='"') local=TRUE;
632  if (iName.at(0)=='"' || iName.at(0)=='<')
633  {
634  iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
635  }
636  if (iName.isEmpty())
637  {
638  iName=fd->name();
639  }
640  }
641  else if (!Config_getList(STRIP_FROM_INC_PATH).isEmpty())
642  {
643  iName=stripFromIncludePath(fd->absFilePath());
644  }
645  else // use name of the file containing the class definition
646  {
647  iName=fd->name();
648  }
649  if (fd->generateSourceFile()) // generate code for header
650  {
651  cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
652  }
653  else // put #include in the class documentation without link
654  {
655  cd->setIncludeFile(0,iName,local,TRUE);
656  }
657  }
658  }
659 }
660 
661 #if 0
662 static bool addNamespace(Entry *root,ClassDef *cd)
663 {
664  // see if this class is defined inside a namespace
665  if (root->section & Entry::COMPOUND_MASK)
666  {
667  Entry *e = root->parent;
668  while (e)
669  {
671  {
672  NamespaceDef *nd=0;
674  //printf("addNameSpace() trying: %s\n",nsName.data());
675  if (!nsName.isEmpty() && nsName.at(0)!='@' &&
676  (nd=getResolvedNamespace(nsName))
677  )
678  {
679  cd->setNamespace(nd);
680  cd->setOuterScope(nd);
681  nd->insertClass(cd);
682  return TRUE;
683  }
684  }
685  e=e->parent;
686  }
687  }
688  return FALSE;
689 }
690 #endif
691 
692 #if 0
693 static Definition *findScope(Entry *root,int level=0)
694 {
695  if (root==0) return 0;
696  //printf("start findScope name=%s\n",root->name.data());
697  Definition *result=0;
698  if (root->section&Entry::SCOPE_MASK)
699  {
700  result = findScope(root->parent,level+1); // traverse to the root of the tree
701  if (result)
702  {
703  //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
704  // TODO: look at template arguments
705  result = result->findInnerCompound(root->name);
706  }
707  else // reached the global scope
708  {
709  // TODO: look at template arguments
711  //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
712  }
713  }
714  //printf("end findScope(%s,%d)=%s\n",root->name.data(),
715  // level,result==0 ? "<none>" : result->name().data());
716  return result;
717 }
718 #endif
719 
725  int level,SrcLangExt lang,const TagInfo *tagInfo)
726 {
727  //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),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;
740  NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
741  Definition *innerScope = nd;
742  ClassDef *cd=0;
743  if (nd==0) cd = getClass(fullScope);
744  if (nd==0 && cd) // scope is a class
745  {
746  innerScope = 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",nsName.data(),prevScope->name().data(),tagInfo);
753  "[generated]",1,1,fullScope,
754  tagInfo?tagInfo->tagName:QCString(),
755  tagInfo?tagInfo->fileName:QCString());
756  nd->setLanguage(lang);
757 
758  // add namespace to the list
759  Doxygen::namespaceSDict->inSort(fullScope,nd);
760  innerScope = nd;
761  }
762  else // scope is a namespace
763  {
764  }
765  if (innerScope)
766  {
767  // make the parent/child scope relation
768  prevScope->addInnerCompound(innerScope);
769  innerScope->setOuterScope(prevScope);
770  }
771  else // current scope is a class, so return only the namespace part...
772  {
773  return prevScope;
774  }
775  // proceed to the next scope fragment
776  p=idx+l+2;
777  prevScope=innerScope;
778  i++;
779  }
780  return prevScope;
781 }
782 
784  FileDef *fileScope,const TagInfo *tagInfo)
785 {
786  //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
787  Definition *resultScope=startScope;
788  if (resultScope==0) resultScope=Doxygen::globalScope;
790  int l1=0,i1;
791  i1=getScopeFragment(scope,0,&l1);
792  if (i1==-1)
793  {
794  //printf(">no fragments!\n");
795  return resultScope;
796  }
797  int p=i1+l1,l2=0,i2;
798  while ((i2=getScopeFragment(scope,p,&l2))!=-1)
799  {
800  QCString nestedNameSpecifier = scope.mid(i1,l1);
801  Definition *orgScope = resultScope;
802  //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
803  resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
804  //printf(" resultScope=%p\n",resultScope);
805  if (resultScope==0)
806  {
807  NamespaceSDict *usedNamespaces;
808  if (orgScope==Doxygen::globalScope && fileScope &&
809  (usedNamespaces = fileScope->getUsedNamespaces()))
810  // also search for used namespaces
811  {
812  NamespaceSDict::Iterator ni(*usedNamespaces);
813  NamespaceDef *nd;
814  for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
815  {
816  // restart search within the used namespace
817  resultScope = findScopeFromQualifiedName(nd,n,fileScope,tagInfo);
818  }
819  if (resultScope)
820  {
821  // for a nested class A::I in used namespace N, we get
822  // N::A::I while looking for A, so we should compare
823  // resultScope->name() against scope.left(i2+l2)
824  //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
825  if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
826  {
827  break;
828  }
829  goto nextFragment;
830  }
831  }
832 
833  // also search for used classes. Complication: we haven't been able
834  // to put them in the right scope yet, because we are still resolving
835  // the scope relations!
836  // Therefore loop through all used classes and see if there is a right
837  // scope match between the used class and nestedNameSpecifier.
839  FileDef *usedFd;
840  for (ui.toFirst();(usedFd=ui.current());++ui)
841  {
842  //printf("Checking using class %s\n",ui.currentKey());
843  if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
844  {
845  // ui.currentKey() is the fully qualified name of nestedNameSpecifier
846  // so use this instead.
847  QCString fqn = QCString(ui.currentKey())+
848  scope.right(scope.length()-p);
849  resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),
850  startScope->getLanguage(),0);
851  //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
852  if (resultScope)
853  {
854  //printf("> Match! resultScope=%s\n",resultScope->name().data());
855  return resultScope;
856  }
857  }
858  }
859 
860  //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
861  return 0;
862  }
863  nextFragment:
864  i1=i2;
865  l1=l2;
866  p=i2+l2;
867  }
868  //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
869  return resultScope;
870 }
871 
873  const QCString &name,
874  const std::vector<ArgumentList> &tArgLists)
875 {
876  // for each scope fragment, check if it is a template and advance through
877  // the list if so.
878  int i,p=0;
879  auto alIt = tArgLists.begin();
880  while ((i=name.find("::",p))!=-1 && alIt!=tArgLists.end())
881  {
883  if (nd==0)
884  {
885  ClassDef *cd = getClass(name.left(i));
886  if (cd)
887  {
888  if (!cd->templateArguments().empty())
889  {
890  ++alIt;
891  }
892  }
893  }
894  p=i+2;
895  }
896  return alIt!=tArgLists.end() ? *alIt : ArgumentList();
897 }
898 
899 static
901 {
903  if (specifier&Entry::Struct)
904  sec=ClassDef::Struct;
905  else if (specifier&Entry::Union)
906  sec=ClassDef::Union;
907  else if (specifier&Entry::Category)
908  sec=ClassDef::Category;
909  else if (specifier&Entry::Interface)
911  else if (specifier&Entry::Protocol)
912  sec=ClassDef::Protocol;
913  else if (specifier&Entry::Exception)
915  else if (specifier&Entry::Service)
916  sec=ClassDef::Service;
917  else if (specifier&Entry::Singleton)
919 
920  switch(section)
921  {
922  //case Entry::UNION_SEC:
923  case Entry::UNIONDOC_SEC:
924  sec=ClassDef::Union;
925  break;
926  //case Entry::STRUCT_SEC:
928  sec=ClassDef::Struct;
929  break;
930  //case Entry::INTERFACE_SEC:
933  break;
934  //case Entry::PROTOCOL_SEC:
936  sec=ClassDef::Protocol;
937  break;
938  //case Entry::CATEGORY_SEC:
940  sec=ClassDef::Category;
941  break;
942  //case Entry::EXCEPTION_SEC:
945  break;
947  sec=ClassDef::Service;
948  break;
951  break;
952  }
953  return sec;
954 }
955 
956 
957 static void addClassToContext(const Entry *root)
958 {
959  FileDef *fd = root->fileDef();
960 
961  QCString scName;
962  if (root->parent()->section&Entry::SCOPE_MASK)
963  {
964  scName=root->parent()->name;
965  }
966  // name without parent's scope
967  QCString fullName = root->name;
968 
969  // strip off any template parameters (but not those for specializations)
970  fullName=stripTemplateSpecifiersFromScope(fullName);
971 
972  // name with scope (if not present already)
973  QCString qualifiedName = fullName;
974  if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
975  {
976  qualifiedName.prepend(scName+"::");
977  }
978 
979  // see if we already found the class before
980  ClassDef *cd = getClass(qualifiedName);
981 
982  Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",
983  cd ? qPrint(cd->name()) : qPrint(root->name), qPrint(qualifiedName),cd);
984 
985  if (cd)
986  {
987  fullName=cd->name();
988  Debug::print(Debug::Classes,0," Existing class %s!\n",qPrint(cd->name()));
989  //if (cd->templateArguments()==0)
990  //{
991  // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
992  // cd->setTemplateArguments(tArgList);
993  //}
994 
995  cd->setDocumentation(root->doc,root->docFile,root->docLine);
996  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
997 
998  if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
999  {
1000  cd->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
1001  cd->setBodyDef(fd);
1002  }
1003  //cd->setName(fullName); // change name to match docs
1004 
1005  if (cd->templateArguments().empty() || (cd->isForwardDeclared() && (root->spec&Entry::ForwardDecl)==0))
1006  {
1007  // this happens if a template class declared with @class is found
1008  // before the actual definition or if a forward declaration has different template
1009  // parameter names.
1010  ArgumentList tArgList = getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1011  cd->setTemplateArguments(tArgList);
1012  }
1013 
1015 
1016  cd->setMetaData(root->metaData);
1017  }
1018  else // new class
1019  {
1021 
1022  QCString className;
1023  QCString namespaceName;
1024  extractNamespaceName(fullName,className,namespaceName);
1025 
1026  //printf("New class: fullname %s namespace '%s' name='%s' brief='%s' docs='%s'\n",
1027  // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1028 
1029  QCString tagName;
1030  QCString refFileName;
1031  const TagInfo *tagInfo = root->tagInfo();
1032  int i;
1033  if (tagInfo)
1034  {
1035  tagName = tagInfo->tagName;
1036  refFileName = tagInfo->fileName;
1037  if (fullName.find("::")!=-1)
1038  // symbols imported via tag files may come without the parent scope,
1039  // so we artificially create it here
1040  {
1041  buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1042  }
1043  }
1044  ArgumentList tArgList;
1045  if ((root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java) && (i=fullName.find('<'))!=-1)
1046  {
1047  // a Java/C# generic class looks like a C++ specialization, so we need to split the
1048  // name and template arguments here
1049  stringToArgumentList(root->lang,fullName.mid(i),tArgList);
1050  fullName=fullName.left(i);
1051  }
1052  else
1053  {
1054  tArgList = getTemplateArgumentsFromName(fullName,root->tArgLists);
1055  }
1056  cd=createClassDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn,
1057  fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1058  Debug::print(Debug::Classes,0," New class '%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1059  qPrint(fullName),sec,root->tArgLists.size(), tagInfo);
1060  cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1061  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1062  cd->setLanguage(root->lang);
1063  cd->setId(root->id);
1064  cd->setHidden(root->hidden);
1065  cd->setArtificial(root->artificial);
1066  cd->setClassSpecifier(root->spec);
1067  cd->setTypeConstraints(root->typeConstr);
1068  //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1069 
1070  //printf("class %s template args=%s\n",fullName.data(),
1071  // tArgList ? tempArgListToString(tArgList,root->lang).data() : "<none>");
1072  cd->setTemplateArguments(tArgList);
1073  cd->setProtection(root->protection);
1074  cd->setIsStatic(root->stat);
1075 
1076  // file definition containing the class cd
1077  cd->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
1078  cd->setBodyDef(fd);
1079 
1080  cd->setMetaData(root->metaData);
1081 
1082  // see if the class is found inside a namespace
1083  //bool found=addNamespace(root,cd);
1084 
1085  cd->insertUsedFile(fd);
1086 
1087  // add class to the list
1088  //printf("ClassDict.insert(%s)\n",fullName.data());
1089  Doxygen::classSDict->append(fullName,cd);
1090 
1091  if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instances
1092  {
1093  //printf("inserting generic '%s' cd=%p\n",fullName.data(),cd);
1094  Doxygen::genericsDict->insert(fullName,cd);
1095  }
1096  }
1097 
1098  cd->addSectionsToDefinition(root->anchors);
1099  if (!root->subGrouping) cd->setSubGrouping(FALSE);
1100  if (cd->hasDocumentation())
1101  {
1102  addIncludeFile(cd,fd,root);
1103  }
1104  if (fd && (root->section & Entry::COMPOUND_MASK))
1105  {
1106  //printf(">> Inserting class '%s' in file '%s' (root->fileName='%s')\n",
1107  // cd->name().data(),
1108  // fd->name().data(),
1109  // root->fileName.data()
1110  // );
1111  cd->setFileDef(fd);
1112  fd->insertClass(cd);
1113  }
1114  addClassToGroups(root,cd);
1115  cd->setRefItems(root->sli);
1116 }
1117 
1118 //----------------------------------------------------------------------
1119 // build a list of all classes mentioned in the documentation
1120 // and all classes that have a documentation block before their definition.
1121 static void buildClassList(const Entry *root)
1122 {
1123  if (
1124  ((root->section & Entry::COMPOUND_MASK) ||
1125  root->section==Entry::OBJCIMPL_SEC) && !root->name.isEmpty()
1126  )
1127  {
1128  addClassToContext(root);
1129  }
1130  for (const auto &e : root->children()) buildClassList(e.get());
1131 }
1132 
1133 static void buildClassDocList(const Entry *root)
1134 {
1135  if (
1136  (root->section & Entry::COMPOUNDDOC_MASK) && !root->name.isEmpty()
1137  )
1138  {
1139  addClassToContext(root);
1140  }
1141  for (const auto &e : root->children()) buildClassDocList(e.get());
1142 }
1143 
1145 {
1147  for (cli.toFirst();cli.current();++cli) cli.current()->setVisited(FALSE);
1148 
1149  bool done=FALSE;
1150  int iteration=0;
1151  while (!done)
1152  {
1153  done=TRUE;
1154  ++iteration;
1155  ClassDef *cd=0;
1156  for (cli.toFirst();(cd=cli.current());++cli)
1157  {
1158  if (!cd->isVisited())
1159  {
1161  //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1162  // also add class to the correct structural context
1164  name,cd->getFileDef(),0);
1165  if (d)
1166  {
1167  //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1168  d->addInnerCompound(cd);
1169  cd->setOuterScope(d);
1170 
1171  // for inline namespace add an alias of the class to the outer scope
1173  {
1174  NamespaceDef *nd = dynamic_cast<NamespaceDef*>(d);
1175  //printf("d->isInline()=%d\n",nd->isInline());
1176  if (nd->isInline())
1177  {
1178  d = d->getOuterScope();
1179  if (d)
1180  {
1181  ClassDef *aliasCd = createClassDefAlias(d,cd);
1182  d->addInnerCompound(aliasCd);
1183  QCString aliasFullName = d->qualifiedName()+"::"+aliasCd->localName();
1184  Doxygen::classSDict->append(aliasFullName,aliasCd);
1185  //printf("adding %s to %s as %s\n",qPrint(aliasCd->name()),qPrint(d->name()),qPrint(aliasFullName));
1186  aliasCd->setVisited(TRUE);
1187  }
1188  }
1189  else
1190  {
1191  break;
1192  }
1193  }
1194 
1195  cd->setVisited(TRUE);
1196  done=FALSE;
1197  }
1198  //else
1199  //{
1200  // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1201  //}
1202  }
1203  }
1204  }
1205 
1206  //give warnings for unresolved compounds
1207  ClassDef *cd=0;
1208  for (cli.toFirst();(cd=cli.current());++cli)
1209  {
1210  if (!cd->isVisited())
1211  {
1213  //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1215  // anyway, so we can at least relate scopes properly.
1216  Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1217  if (d!=cd && !cd->getDefFileName().isEmpty())
1218  // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1219  // for this case doxygen assumes the existence of a namespace N::N in which C is to be found!
1220  // also avoid warning for stuff imported via a tagfile.
1221  {
1222  d->addInnerCompound(cd);
1223  cd->setOuterScope(d);
1224  warn(cd->getDefFileName(),cd->getDefLine(),
1225  "Internal inconsistency: scope for class %s not "
1226  "found!",name.data()
1227  );
1228  }
1229  }
1230  }
1231 }
1232 
1234 {
1235  //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
1236  //if (!inlineGroupedClasses) return;
1237  //printf("** distributeClassGroupRelations()\n");
1238 
1240  for (cli.toFirst();cli.current();++cli) cli.current()->setVisited(FALSE);
1241 
1242  ClassDef *cd;
1243  for (cli.toFirst();(cd=cli.current());++cli)
1244  {
1245  //printf("Checking %s\n",cd->name().data());
1246  // distribute the group to nested classes as well
1247  if (!cd->isVisited() && cd->partOfGroups()!=0 && cd->getClassSDict())
1248  {
1249  //printf(" Candidate for merging\n");
1250  ClassSDict::Iterator ncli(*cd->getClassSDict());
1251  ClassDef *ncd;
1252  GroupDef *gd = cd->partOfGroups()->at(0);
1253  for (ncli.toFirst();(ncd=ncli.current());++ncli)
1254  {
1255  if (ncd->partOfGroups()==0)
1256  {
1257  //printf(" Adding %s to group '%s'\n",ncd->name().data(),
1258  // gd->groupTitle());
1259  ncd->makePartOfGroup(gd);
1260  gd->addClass(ncd);
1261  }
1262  }
1263  cd->setVisited(TRUE); // only visit every class once
1264  }
1265  }
1266 }
1267 
1268 //----------------------------
1269 
1270 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1271 {
1272  QCString fullName = removeAnonymousScopes(templ->name());
1273  if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1274  fullName+="."+fieldName;
1275  ClassDef *cd = createClassDef(templ->getDefFileName(),
1276  templ->getDefLine(),
1277  templ->getDefColumn(),
1278  fullName,
1279  templ->compoundType());
1280  cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1281  cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1282  cd->setLanguage(templ->getLanguage());
1283  cd->setBodySegment(templ->getDefLine(),templ->getStartBodyLine(),templ->getEndBodyLine());
1284  cd->setBodyDef(templ->getBodyDef());
1285 
1286  cd->setOuterScope(rootCd->getOuterScope());
1287  if (rootCd->getOuterScope()!=Doxygen::globalScope)
1288  {
1289  rootCd->getOuterScope()->addInnerCompound(cd);
1290  }
1291 
1292  FileDef *fd = templ->getFileDef();
1293  if (fd)
1294  {
1295  cd->setFileDef(fd);
1296  fd->insertClass(cd);
1297  }
1298  GroupList *groups = rootCd->partOfGroups();
1299  if ( groups!=0 )
1300  {
1301  GroupListIterator gli(*groups);
1302  GroupDef *gd;
1303  for (gli.toFirst();(gd=gli.current());++gli)
1304  {
1305  cd->makePartOfGroup(gd);
1306  gd->addClass(cd);
1307  }
1308  }
1309  //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1310  Doxygen::classSDict->append(fullName,cd);
1311 
1313  if (ml)
1314  {
1315  MemberListIterator li(*ml);
1316  MemberDef *md;
1317  for (li.toFirst();(md=li.current());++li)
1318  {
1319  //printf(" Member %s type=%s\n",md->name().data(),md->typeString());
1321  md->typeString(),md->name(),md->argsString(),md->excpString(),
1322  md->protection(),md->virtualness(),md->isStatic(),Member,
1323  md->memberType(),
1324  ArgumentList(),ArgumentList(),"");
1325  imd->setMemberClass(cd);
1326  imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1327  imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1330  imd->setMemberGroupId(md->getMemberGroupId());
1331  imd->setInitializer(md->initializer());
1332  imd->setMaxInitLines(md->initializerLines());
1333  imd->setBitfields(md->bitfieldString());
1334  imd->setLanguage(md->getLanguage());
1335  cd->insertMember(imd);
1336  }
1337  }
1338  return cd;
1339 }
1340 
1350 static void processTagLessClasses(ClassDef *rootCd,
1351  ClassDef *cd,
1352  ClassDef *tagParentCd,
1353  const QCString &prefix,int count)
1354 {
1355  //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1356  //printf("checking members for %s\n",cd->name().data());
1357  if (cd->getClassSDict())
1358  {
1360  if (ml)
1361  {
1362  MemberListIterator li(*ml);
1363  MemberDef *md;
1364  for (li.toFirst();(md=li.current());++li)
1365  {
1366  QCString type = md->typeString();
1367  if (type.find("::@")!=-1) // member of tag less struct/union
1368  {
1370  ClassDef *icd;
1371  for (it.toFirst();(icd=it.current());++it)
1372  {
1373  //printf(" member %s: type='%s'\n",md->name().data(),type.data());
1374  //printf(" comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1375  if (type.find(icd->name())!=-1) // matching tag less struct/union
1376  {
1377  QCString name = md->name();
1378  if (md->isAnonymous()) name = "__unnamed__";
1379  if (!prefix.isEmpty()) name.prepend(prefix+".");
1380  //printf(" found %s for class %s\n",name.data(),cd->name().data());
1381  ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1382  processTagLessClasses(rootCd,icd,ncd,name,count+1);
1383  //printf(" addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1384  tagParentCd->addTaggedInnerClass(ncd);
1385  ncd->setTagLessReference(icd);
1386 
1387  // replace tag-less type for generated/original member
1388  // by newly created class name.
1389  // note the difference between changing cd and tagParentCd.
1390  // for the initial call this is the same pointer, but for
1391  // recursive calls cd is the original tag-less struct (of which
1392  // there is only one instance) and tagParentCd is the newly
1393  // generated tagged struct of which there can be multiple instances!
1394  MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1395  if (pml)
1396  {
1397  MemberListIterator pli(*pml);
1398  MemberDef *pmd;
1399  for (pli.toFirst();(pmd=pli.current());++pli)
1400  {
1401  if (pmd->name()==md->name())
1402  {
1403  pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1404  //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1405  }
1406  }
1407  }
1408  }
1409  }
1410  }
1411  }
1412  }
1413  }
1414 }
1415 
1417 {
1418  if (cd->getClassSDict())
1419  {
1421  ClassDef *icd;
1422  for (it.toFirst();(icd=it.current());++it)
1423  {
1424  if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1425  {
1426  findTagLessClasses(icd);
1427  }
1428  }
1429  }
1430 
1431  processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1432 }
1433 
1434 static void findTagLessClasses()
1435 {
1437  ClassDef *cd;
1438  for (cli.toFirst();(cd=cli.current());++cli) // for each class
1439  {
1440  Definition *scope = cd->getOuterScope();
1441  if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1442  {
1443  findTagLessClasses(cd);
1444  }
1445  }
1446 }
1447 
1448 
1449 //----------------------------------------------------------------------
1450 // build a list of all namespaces mentioned in the documentation
1451 // and all namespaces that have a documentation block before their definition.
1452 static void buildNamespaceList(const Entry *root)
1453 {
1454  if (
1455  (root->section==Entry::NAMESPACE_SEC ||
1458  ) &&
1459  !root->name.isEmpty()
1460  )
1461  {
1462  //printf("** buildNamespaceList(%s)\n",root->name.data());
1463 
1464  QCString fName = root->name;
1465  if (root->section==Entry::PACKAGEDOC_SEC)
1466  {
1467  fName=substitute(fName,".","::");
1468  }
1469 
1470  QCString fullName = stripAnonymousNamespaceScope(fName);
1471  if (!fullName.isEmpty())
1472  {
1473  //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1474  // root->fileName.data(), root->startLine);
1475  NamespaceDef *nd;
1476  if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1477  {
1478  nd->setDocumentation(root->doc,root->docFile,root->docLine);
1479  nd->setName(fullName); // change name to match docs
1480  nd->addSectionsToDefinition(root->anchors);
1481  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1482  if (nd->getLanguage()==SrcLangExt_Unknown)
1483  {
1484  nd->setLanguage(root->lang);
1485  }
1486  if (root->tagInfo()==0) // if we found the namespace in a tag file
1487  // and also in a project file, then remove
1488  // the tag file reference
1489  {
1490  nd->setReference("");
1491  nd->setFileName(fullName);
1492  }
1493  nd->setMetaData(root->metaData);
1494 
1495  // file definition containing the namespace nd
1496  FileDef *fd=root->fileDef();
1497  // insert the namespace in the file definition
1498  if (fd) fd->insertNamespace(nd);
1499  addNamespaceToGroups(root,nd);
1500  nd->setRefItems(root->sli);
1501  }
1502  else // fresh namespace
1503  {
1504  QCString tagName;
1505  QCString tagFileName;
1506  const TagInfo *tagInfo = root->tagInfo();
1507  if (tagInfo)
1508  {
1509  tagName = tagInfo->tagName;
1510  tagFileName = tagInfo->fileName;
1511  }
1512  //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1513  nd=createNamespaceDef(tagInfo?tagName:root->fileName,root->startLine,
1514  root->startColumn,fullName,tagName,tagFileName,
1515  root->type,root->spec&Entry::Published);
1516  nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1517  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1518  nd->addSectionsToDefinition(root->anchors);
1519  nd->setHidden(root->hidden);
1520  nd->setArtificial(root->artificial);
1521  nd->setLanguage(root->lang);
1522  nd->setId(root->id);
1523  nd->setMetaData(root->metaData);
1524  nd->setInline((root->spec&Entry::Inline)!=0);
1525 
1526  //printf("Adding namespace to group\n");
1527  addNamespaceToGroups(root,nd);
1528  nd->setRefItems(root->sli);
1529 
1530  // file definition containing the namespace nd
1531  FileDef *fd=root->fileDef();
1532  // insert the namespace in the file definition
1533  if (fd) fd->insertNamespace(nd);
1534 
1535  // the empty string test is needed for extract all case
1536  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1537  nd->insertUsedFile(fd);
1538  nd->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
1539  nd->setBodyDef(fd);
1540  // add class to the list
1541  Doxygen::namespaceSDict->inSort(fullName,nd);
1542 
1543  // also add namespace to the correct structural context
1545  //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1546  if (d==0) // we didn't find anything, create the scope artificially
1547  // anyway, so we can at least relate scopes properly.
1548  {
1549  d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1550  d->addInnerCompound(nd);
1551  nd->setOuterScope(d);
1552  // TODO: Due to the order in which the tag file is written
1553  // a nested class can be found before its parent!
1554  }
1555  else
1556  {
1557  d->addInnerCompound(nd);
1558  nd->setOuterScope(d);
1559  // in case of d is an inline namespace, alias insert nd in the part scope of d.
1561  {
1562  NamespaceDef *pnd = dynamic_cast<NamespaceDef*>(d);
1563  if (pnd->isInline())
1564  {
1565  d = d->getOuterScope();
1566  if (d)
1567  {
1568  NamespaceDef *aliasNd = createNamespaceDefAlias(d,nd);
1569  //printf("adding %s to %s\n",qPrint(aliasNd->name()),qPrint(d->name()));
1570  d->addInnerCompound(aliasNd);
1571  }
1572  }
1573  else
1574  {
1575  break;
1576  }
1577  }
1578  }
1579  }
1580  }
1581  }
1582  for (const auto &e : root->children()) buildNamespaceList(e.get());
1583 }
1584 
1585 //----------------------------------------------------------------------
1586 
1588  const QCString &name)
1589 {
1590  const NamespaceDef *usingNd =0;
1591  if (unl)
1592  {
1593  //printf("Found namespace dict %d\n",unl->count());
1594  NamespaceSDict::Iterator unli(*unl);
1595  const NamespaceDef *und;
1596  for (unli.toFirst();(und=unli.current());++unli)
1597  {
1598  QCString uScope=und->name()+"::";
1599  usingNd = getResolvedNamespace(uScope+name);
1600  //printf("Also trying with scope='%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1601  }
1602  }
1603  return usingNd;
1604 }
1605 
1606 static void findUsingDirectives(const Entry *root)
1607 {
1608  if (root->section==Entry::USINGDIR_SEC)
1609  {
1610  //printf("Found using directive %s at line %d of %s\n",
1611  // root->name.data(),root->startLine,root->fileName.data());
1612  QCString name=substitute(root->name,".","::");
1613  if (name.right(2)=="::")
1614  {
1615  name=name.left(name.length()-2);
1616  }
1617  if (!name.isEmpty())
1618  {
1619  const NamespaceDef *usingNd = 0;
1620  NamespaceDef *nd = 0;
1621  FileDef *fd = root->fileDef();
1622  QCString nsName;
1623 
1624  // see if the using statement was found inside a namespace or inside
1625  // the global file scope.
1626  if (root->parent() && root->parent()->section==Entry::NAMESPACE_SEC &&
1627  (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1628  )
1629  {
1630  nsName=stripAnonymousNamespaceScope(root->parent()->name);
1631  if (!nsName.isEmpty())
1632  {
1633  nd = getResolvedNamespace(nsName);
1634  }
1635  }
1636 
1637  // find the scope in which the 'using' namespace is defined by prepending
1638  // the possible scopes in which the using statement was found, starting
1639  // with the most inner scope and going to the most outer scope (i.e.
1640  // file scope).
1641  int scopeOffset = nsName.length();
1642  do
1643  {
1644  QCString scope=scopeOffset>0 ?
1645  nsName.left(scopeOffset)+"::" : QCString();
1646  usingNd = getResolvedNamespace(scope+name);
1647  //printf("Trying with scope='%s' usingNd=%p\n",(scope+name).data(),usingNd);
1648  if (scopeOffset==0)
1649  {
1650  scopeOffset=-1;
1651  }
1652  else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1653  {
1654  scopeOffset=0;
1655  }
1656  } while (scopeOffset>=0 && usingNd==0);
1657 
1658  if (usingNd==0 && nd) // not found, try used namespaces in this scope
1659  // or in one of the parent namespace scopes
1660  {
1661  const NamespaceDef *pnd = nd;
1662  while (pnd && usingNd==0)
1663  {
1664  // also try with one of the used namespaces found earlier
1665  usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1666 
1667  // goto the parent
1668  const Definition *s = pnd->getOuterScope();
1670  {
1671  pnd = dynamic_cast<const NamespaceDef*>(s);
1672  }
1673  else
1674  {
1675  pnd = 0;
1676  }
1677  }
1678  }
1679  if (usingNd==0 && fd) // still nothing, also try used namespace in the
1680  // global scope
1681  {
1682  usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1683  }
1684 
1685  //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1686 
1687  // add the namespace the correct scope
1688  if (usingNd)
1689  {
1690  //printf("using fd=%p nd=%p\n",fd,nd);
1691  if (nd)
1692  {
1693  //printf("Inside namespace %s\n",nd->name().data());
1694  nd->addUsingDirective(usingNd);
1695  }
1696  else if (fd)
1697  {
1698  //printf("Inside file %s\n",fd->name().data());
1699  fd->addUsingDirective(usingNd);
1700  }
1701  }
1702  else // unknown namespace, but add it anyway.
1703  {
1704  //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1705  nd=createNamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1706  nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1707  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1708  nd->addSectionsToDefinition(root->anchors);
1709  //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1710  nd->setHidden(root->hidden);
1711  nd->setArtificial(TRUE);
1712  nd->setLanguage(root->lang);
1713  nd->setId(root->id);
1714  nd->setMetaData(root->metaData);
1715  nd->setInline((root->spec&Entry::Inline)!=0);
1716 
1717  //QListIterator<Grouping> gli(*root->groups);
1718  //Grouping *g;
1719  //for (;(g=gli.current());++gli)
1720  for (const Grouping &g : root->groups)
1721  {
1722  GroupDef *gd=0;
1723  if (!g.groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g.groupname)))
1724  gd->addNamespace(nd);
1725  }
1726 
1727  // insert the namespace in the file definition
1728  if (fd)
1729  {
1730  fd->insertNamespace(nd);
1731  fd->addUsingDirective(nd);
1732  }
1733 
1734  // the empty string test is needed for extract all case
1735  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1736  nd->insertUsedFile(fd);
1737  // add class to the list
1738  Doxygen::namespaceSDict->inSort(name,nd);
1739  nd->setRefItems(root->sli);
1740  }
1741  }
1742  }
1743  for (const auto &e : root->children()) findUsingDirectives(e.get());
1744 }
1745 
1746 //----------------------------------------------------------------------
1747 
1748 static void buildListOfUsingDecls(const Entry *root)
1749 {
1750  if (root->section==Entry::USINGDECL_SEC &&
1751  !(root->parent()->section&Entry::COMPOUND_MASK) // not a class/struct member
1752  )
1753  {
1754  QCString name = substitute(root->name,".","::");
1755 
1756  if (g_usingDeclarations.find(name)==0)
1757  {
1758  FileDef *fd = root->fileDef();
1759  if (fd)
1760  {
1761  g_usingDeclarations.insert(name,fd);
1762  }
1763  }
1764  }
1765  for (const auto &e : root->children()) buildListOfUsingDecls(e.get());
1766 }
1767 
1768 
1769 static void findUsingDeclarations(const Entry *root)
1770 {
1771  if (root->section==Entry::USINGDECL_SEC &&
1772  !(root->parent()->section&Entry::COMPOUND_MASK) // not a class/struct member
1773  )
1774  {
1775  //printf("Found using declaration %s at line %d of %s inside section %x\n",
1776  // root->name.data(),root->startLine,root->fileName.data(),
1777  // rootNav->parent()->section());
1778  if (!root->name.isEmpty())
1779  {
1780  ClassDef *usingCd = 0;
1781  NamespaceDef *nd = 0;
1782  FileDef *fd = root->fileDef();
1783  QCString scName;
1784 
1785  // see if the using statement was found inside a namespace or inside
1786  // the global file scope.
1787  if (root->parent()->section == Entry::NAMESPACE_SEC)
1788  {
1789  scName=root->parent()->name;
1790  if (!scName.isEmpty())
1791  {
1792  nd = getResolvedNamespace(scName);
1793  }
1794  }
1795 
1796  // Assume the using statement was used to import a class.
1797  // Find the scope in which the 'using' namespace is defined by prepending
1798  // the possible scopes in which the using statement was found, starting
1799  // with the most inner scope and going to the most outer scope (i.e.
1800  // file scope).
1801 
1802  QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
1803  usingCd = getClass(name); // try direct lookup first, this is needed to get
1804  // builtin STL classes to properly resolve, e.g.
1805  // vector -> std::vector
1806  if (usingCd==0)
1807  {
1808  usingCd = const_cast<ClassDef*>(getResolvedClass(nd,fd,name)); // try via resolving (see also bug757509)
1809  }
1810  if (usingCd==0)
1811  {
1812  usingCd = Doxygen::hiddenClasses->find(name); // check if it is already hidden
1813  }
1814 
1815  //printf("%s -> %p\n",root->name.data(),usingCd);
1816  if (usingCd==0) // definition not in the input => add an artificial class
1817  {
1818  Debug::print(Debug::Classes,0," New using class '%s' (sec=0x%08x)! #tArgLists=%d\n",
1819  qPrint(name),root->section,root->tArgLists.size());
1820  usingCd = createClassDef(
1821  "<using>",1,1,
1822  name,
1823  ClassDef::Class);
1824  Doxygen::hiddenClasses->append(root->name,usingCd);
1825  usingCd->setArtificial(TRUE);
1826  usingCd->setLanguage(root->lang);
1827  }
1828  else
1829  {
1830  Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",
1831  qPrint(usingCd->name()),
1832  nd?qPrint(nd->name()):
1833  fd?qPrint(fd->name()):
1834  "<unknown>");
1835  }
1836 
1837  if (nd)
1838  {
1839  //printf("Inside namespace %s\n",nd->name().data());
1840  nd->addUsingDeclaration(usingCd);
1841  }
1842  else if (fd)
1843  {
1844  //printf("Inside file %s\n",fd->name().data());
1845  fd->addUsingDeclaration(usingCd);
1846  }
1847  }
1848  }
1849  for (const auto &e : root->children()) findUsingDeclarations(e.get());
1850 }
1851 
1852 //----------------------------------------------------------------------
1853 
1854 static void findUsingDeclImports(const Entry *root)
1855 {
1856  if (root->section==Entry::USINGDECL_SEC &&
1857  (root->parent()->section&Entry::COMPOUND_MASK) // in a class/struct member
1858  )
1859  {
1860  //printf("Found using declaration %s inside section %x\n",
1861  // root->name.data(), root->parent()->section);
1862  QCString fullName=removeRedundantWhiteSpace(root->parent()->name);
1863  fullName=stripAnonymousNamespaceScope(fullName);
1864  fullName=stripTemplateSpecifiersFromScope(fullName);
1865  ClassDef *cd = getClass(fullName);
1866  if (cd)
1867  {
1868  //printf("found class %s\n",cd->name().data());
1869  int i=root->name.find("::");
1870  if (i!=-1)
1871  {
1872  QCString scope=root->name.left(i);
1873  QCString memName=root->name.right(root->name.length()-i-2);
1874  const ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
1875  if (bcd && bcd!=cd)
1876  {
1877  //printf("found class %s memName=%s\n",bcd->name().data(),memName.data());
1879  if (mndict)
1880  {
1881  MemberNameInfo *mni = mndict->find(memName);
1882  if (mni)
1883  {
1884  MemberNameInfoIterator mnii(*mni);
1885  MemberInfo *mi;
1886  for ( ; (mi=mnii.current()) ; ++mnii )
1887  {
1888  MemberDef *md = mi->memberDef;
1889  if (md && md->protection()!=Private)
1890  {
1891  //printf("found member %s\n",mni->memberName());
1892  MemberDef *newMd = 0;
1893  {
1894  QCString fileName = root->fileName;
1895  if (fileName.isEmpty() && root->tagInfo())
1896  {
1897  fileName = root->tagInfo()->tagName;
1898  }
1899  const ArgumentList &templAl = md->templateArguments();
1900  const ArgumentList &al = md->templateArguments();
1901  newMd = createMemberDef(
1902  fileName,root->startLine,root->startColumn,
1903  md->typeString(),memName,md->argsString(),
1904  md->excpString(),root->protection,root->virt,
1905  md->isStatic(),Member,md->memberType(),
1906  templAl,al,root->metaData
1907  );
1908  }
1909  newMd->setMemberClass(cd);
1910  cd->insertMember(newMd);
1911  if (!root->doc.isEmpty() || !root->brief.isEmpty())
1912  {
1913  newMd->setDocumentation(root->doc,root->docFile,root->docLine);
1914  newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1915  newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
1916  }
1917  else
1918  {
1919  newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1920  newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1922  }
1923  newMd->setDefinition(md->definition());
1924  newMd->enableCallGraph(root->callGraph);
1925  newMd->enableCallerGraph(root->callerGraph);
1928  newMd->setBitfields(md->bitfieldString());
1929  newMd->addSectionsToDefinition(root->anchors);
1930  newMd->setBodySegment(md->getDefLine(),md->getStartBodyLine(),md->getEndBodyLine());
1931  newMd->setBodyDef(md->getBodyDef());
1932  newMd->setInitializer(md->initializer());
1933  newMd->setMaxInitLines(md->initializerLines());
1934  newMd->setMemberGroupId(root->mGrpId);
1936  newMd->setLanguage(root->lang);
1937  newMd->setId(root->id);
1938  }
1939  }
1940  }
1941  }
1942  }
1943  }
1944  }
1945 
1946  }
1947  for (const auto &e : root->children()) findUsingDeclImports(e.get());
1948 }
1949 
1950 //----------------------------------------------------------------------
1951 
1953 {
1954  // first mark all files as not visited
1955  for (const auto &fn : *Doxygen::inputNameLinkedMap)
1956  {
1957  for (const auto &fd : *fn)
1958  {
1959  fd->setVisited(FALSE);
1960  }
1961  }
1962  // then recursively add using directives found in #include files
1963  // to files that have not been visited.
1964  for (const auto &fn : *Doxygen::inputNameLinkedMap)
1965  {
1966  for (const auto &fd : *fn)
1967  {
1968  if (!fd->isVisited())
1969  {
1970  //printf("----- adding using directives for file %s\n",fd->name().data());
1971  fd->addIncludedUsingDirectives();
1972  }
1973  }
1974  }
1975 }
1976 
1977 //----------------------------------------------------------------------
1978 
1980  const Entry *root,
1981  ClassDef *cd,
1982  MemberType mtype,
1983  const QCString &type,
1984  const QCString &name,
1985  const QCString &args,
1986  bool fromAnnScope,
1987  MemberDef *fromAnnMemb,
1988  Protection prot,
1989  Relationship related)
1990 {
1992  QCString scopeSeparator="::";
1993  SrcLangExt lang = cd->getLanguage();
1994  if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
1995  {
1996  qualScope = substitute(qualScope,"::",".");
1997  scopeSeparator=".";
1998  }
2000  " class variable:\n"
2001  " '%s' '%s'::'%s' '%s' prot=%d ann=%d init='%s'\n",
2002  qPrint(type),
2003  qPrint(qualScope),
2004  qPrint(name),
2005  qPrint(args),
2006  root->protection,
2007  fromAnnScope,
2008  qPrint(root->initializer)
2009  );
2010 
2011  QCString def;
2012  if (!type.isEmpty())
2013  {
2014  if (related || mtype==MemberType_Friend || Config_getBool(HIDE_SCOPE_NAMES))
2015  {
2016  if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2017  {
2018  def="using "+name+" = "+type.mid(7);
2019  }
2020  else
2021  {
2022  def=type+" "+name+args;
2023  }
2024  }
2025  else
2026  {
2027  if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2028  {
2029  def="using "+qualScope+scopeSeparator+name+" = "+type.mid(7);
2030  }
2031  else
2032  {
2033  def=type+" "+qualScope+scopeSeparator+name+args;
2034  }
2035  }
2036  }
2037  else
2038  {
2040  {
2041  def=name+args;
2042  }
2043  else
2044  {
2045  def=qualScope+scopeSeparator+name+args;
2046  }
2047  }
2048  def.stripPrefix("static ");
2049 
2050  // see if the member is already found in the same scope
2051  // (this may be the case for a static member that is initialized
2052  // outside the class)
2054  if (mn)
2055  {
2056  for (const auto &md : *mn)
2057  {
2058  //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2059  // md->getClassDef(),cd,type.data(),md->typeString());
2060  if (!md->isAlias() &&
2061  md->getClassDef()==cd &&
2062  removeRedundantWhiteSpace(type)==md->typeString())
2063  // member already in the scope
2064  {
2065 
2066  if (root->lang==SrcLangExt_ObjC &&
2067  root->mtype==Property &&
2068  md->memberType()==MemberType_Variable)
2069  { // Objective-C 2.0 property
2070  // turn variable into a property
2071  md->setProtection(root->protection);
2072  cd->reclassifyMember(md.get(),MemberType_Property);
2073  }
2074  addMemberDocs(root,md.get(),def,0,FALSE,root->spec);
2075  //printf(" Member already found!\n");
2076  return md.get();
2077  }
2078  }
2079  }
2080 
2081  QCString fileName = root->fileName;
2082  if (fileName.isEmpty() && root->tagInfo())
2083  {
2084  fileName = root->tagInfo()->tagName;
2085  }
2086 
2087  // new member variable, typedef or enum value
2088  std::unique_ptr<MemberDef> md { createMemberDef(
2089  fileName,root->startLine,root->startColumn,
2090  type,name,args,root->exception,
2091  prot,Normal,root->stat,related,
2092  mtype,!root->tArgLists.empty() ? root->tArgLists.back() : ArgumentList(),
2093  ArgumentList(), root->metaData) };
2094  md->setTagInfo(root->tagInfo());
2095  md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2096  //md->setDefFile(root->fileName);
2097  //md->setDefLine(root->startLine);
2098  md->setDocumentation(root->doc,root->docFile,root->docLine);
2099  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2100  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2101  md->setDefinition(def);
2102  md->setBitfields(root->bitfields);
2103  md->addSectionsToDefinition(root->anchors);
2104  md->setFromAnonymousScope(fromAnnScope);
2105  md->setFromAnonymousMember(fromAnnMemb);
2106  //md->setIndentDepth(indentDepth);
2107  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
2108  md->setInitializer(root->initializer);
2109  md->setMaxInitLines(root->initLines);
2110  md->setMemberGroupId(root->mGrpId);
2111  md->setMemberSpecifiers(root->spec);
2112  md->setReadAccessor(root->read);
2113  md->setWriteAccessor(root->write);
2114  md->enableCallGraph(root->callGraph);
2115  md->enableCallerGraph(root->callerGraph);
2116  md->enableReferencedByRelation(root->referencedByRelation);
2117  md->enableReferencesRelation(root->referencesRelation);
2118  md->setHidden(root->hidden);
2119  md->setArtificial(root->artificial);
2120  md->setLanguage(root->lang);
2121  md->setId(root->id);
2122  addMemberToGroups(root,md.get());
2123  md->setBodyDef(root->fileDef());
2124 
2125  //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd);
2126  cd->insertMember(md.get());
2127  md->setRefItems(root->sli);
2128 
2129  //TODO: insert FileDef instead of filename strings.
2130  cd->insertUsedFile(root->fileDef());
2131  root->markAsProcessed();
2132 
2133  //printf(" Adding member=%s\n",md->name().data());
2134  // add the member to the global list
2135  MemberDef *result = md.get();
2136  mn = Doxygen::memberNameLinkedMap->add(name);
2137  mn->push_back(std::move(md));
2138 
2139  return result;
2140 }
2141 
2142 //----------------------------------------------------------------------
2143 
2145  const Entry *root,
2146  MemberType mtype,
2147  const QCString &scope,
2148  const QCString &type,
2149  const QCString &name,
2150  const QCString &args,
2151  bool fromAnnScope,
2152  /*int indentDepth,*/
2153  MemberDef *fromAnnMemb)
2154 {
2156  " global variable:\n"
2157  " file='%s' type='%s' scope='%s' name='%s' args='%s' prot=`%d mtype=%d lang=%d\n",
2158  qPrint(root->fileName),
2159  qPrint(type),
2160  qPrint(scope),
2161  qPrint(name),
2162  qPrint(args),
2163  root->protection,
2164  mtype,
2165  root->lang
2166  );
2167 
2168  FileDef *fd = root->fileDef();
2169 
2170  // see if we have a typedef that should hide a struct or union
2171  if (mtype==MemberType_Typedef && Config_getBool(TYPEDEF_HIDES_STRUCT))
2172  {
2173  QCString ttype = type;
2174  ttype.stripPrefix("typedef ");
2175  if (ttype.left(7)=="struct " || ttype.left(6)=="union ")
2176  {
2177  ttype.stripPrefix("struct ");
2178  ttype.stripPrefix("union ");
2179  static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2180  int l,s;
2181  s = re.match(ttype,0,&l);
2182  if (s>=0)
2183  {
2184  QCString typeValue = ttype.mid(s,l);
2185  ClassDef *cd = getClass(typeValue);
2186  if (cd)
2187  {
2188  // this typedef should hide compound name cd, so we
2189  // change the name that is displayed from cd.
2190  cd->setClassName(name);
2191  cd->setDocumentation(root->doc,root->docFile,root->docLine);
2192  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2193  return 0;
2194  }
2195  }
2196  }
2197  }
2198 
2199  // see if the function is inside a namespace
2200  NamespaceDef *nd = 0;
2201  if (!scope.isEmpty())
2202  {
2203  if (scope.find('@')!=-1) return 0; // anonymous scope!
2204  //nscope=removeAnonymousScopes(scope);
2205  //if (!nscope.isEmpty())
2206  //{
2207  nd = getResolvedNamespace(scope);
2208  //}
2209  }
2210  QCString def;
2211 
2212  // determine the definition of the global variable
2213  if (nd && !nd->isAnonymous() &&
2215  )
2216  // variable is inside a namespace, so put the scope before the name
2217  {
2218  SrcLangExt lang = nd->getLanguage();
2220 
2221  if (!type.isEmpty())
2222  {
2223  if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2224  {
2225  def="using "+nd->name()+sep+name+" = "+type;
2226  }
2227  else // normal member
2228  {
2229  def=type+" "+nd->name()+sep+name+args;
2230  }
2231  }
2232  else
2233  {
2234  def=nd->name()+sep+name+args;
2235  }
2236  }
2237  else
2238  {
2239  if (!type.isEmpty() && !root->name.isEmpty())
2240  {
2241  if (name.at(0)=='@') // dummy variable representing anonymous union
2242  {
2243  def=type;
2244  }
2245  else
2246  {
2247  if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2248  {
2249  def="using "+root->name+" = "+type.mid(7);
2250  }
2251  else // normal member
2252  {
2253  def=type+" "+name+args;
2254  }
2255  }
2256  }
2257  else
2258  {
2259  def=name+args;
2260  }
2261  }
2262  def.stripPrefix("static ");
2263 
2265  if (mn)
2266  {
2267  //QCString nscope=removeAnonymousScopes(scope);
2268  //NamespaceDef *nd=0;
2269  //if (!nscope.isEmpty())
2270  if (!scope.isEmpty())
2271  {
2272  nd = getResolvedNamespace(scope);
2273  }
2274  for (const auto &md : *mn)
2275  {
2276  if (!md->isAlias() &&
2277  ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2278  root->fileName==md->getFileDef()->absFilePath()
2279  ) // both variable names in the same file
2280  || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2281  )
2282  && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2283  && !md->isEnumerate() // in C# an enum value and enum can have the same name
2284  )
2285  // variable already in the scope
2286  {
2287  bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2288  md->argsString()!=args &&
2289  args.find('[')!=-1;
2290  bool staticsInDifferentFiles =
2291  root->stat && md->isStatic() &&
2292  root->fileName!=md->getDefFileName();
2293 
2294  if (md->getFileDef() &&
2295  !isPHPArray && // not a php array
2296  !staticsInDifferentFiles
2297  )
2298  // not a php array variable
2299  {
2301  " variable already found: scope=%s\n",qPrint(md->getOuterScope()->name()));
2302  addMemberDocs(root,md.get(),def,0,FALSE,root->spec);
2303  md->setRefItems(root->sli);
2304  // if md is a variable forward declaration and root is the definition that
2305  // turn md into the definition
2306  if (!root->explicitExternal && md->isExternal())
2307  {
2308  md->setDeclFile(md->getDefFileName(),md->getDefLine(),md->getDefColumn());
2309  md->setExplicitExternal(FALSE,root->fileName,root->startLine,root->startColumn);
2310  }
2311  // if md is the definition and root point at a declaration, then add the
2312  // declaration info
2313  else if (root->explicitExternal && !md->isExternal())
2314  {
2315  md->setDeclFile(root->fileName,root->startLine,root->startColumn);
2316  }
2317  return md.get();
2318  }
2319  }
2320  }
2321  }
2322 
2323  QCString fileName = root->fileName;
2324  if (fileName.isEmpty() && root->tagInfo())
2325  {
2326  fileName = root->tagInfo()->tagName;
2327  }
2328 
2330  " new variable, nd=%s tagInfo=%p!\n",nd?qPrint(nd->name()):"<global>",root->tagInfo());
2331  // new global variable, enum value or typedef
2332  std::unique_ptr<MemberDef> md { createMemberDef(
2333  fileName,root->startLine,root->startColumn,
2334  type,name,args,0,
2335  root->protection, Normal,root->stat,Member,
2336  mtype,!root->tArgLists.empty() ? root->tArgLists.back() : ArgumentList(),
2337  ArgumentList(), root->metaData) };
2338  md->setTagInfo(root->tagInfo());
2339  md->setMemberSpecifiers(root->spec);
2340  md->setDocumentation(root->doc,root->docFile,root->docLine);
2341  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2342  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2343  md->addSectionsToDefinition(root->anchors);
2344  md->setFromAnonymousScope(fromAnnScope);
2345  md->setFromAnonymousMember(fromAnnMemb);
2346  md->setInitializer(root->initializer);
2347  md->setMaxInitLines(root->initLines);
2348  md->setMemberGroupId(root->mGrpId);
2349  md->setDefinition(def);
2350  md->setLanguage(root->lang);
2351  md->setId(root->id);
2352  md->enableCallGraph(root->callGraph);
2353  md->enableCallerGraph(root->callerGraph);
2354  md->enableReferencedByRelation(root->referencedByRelation);
2355  md->enableReferencesRelation(root->referencesRelation);
2356  md->setExplicitExternal(root->explicitExternal,fileName,root->startLine,root->startColumn);
2357  //md->setOuterScope(fd);
2358  if (!root->explicitExternal)
2359  {
2360  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
2361  md->setBodyDef(fd);
2362  }
2363  addMemberToGroups(root,md.get());
2364 
2365  md->setRefItems(root->sli);
2366  if (nd && !nd->isAnonymous())
2367  {
2368  md->setNamespace(nd);
2369  nd->insertMember(md.get());
2370  }
2371 
2372  // add member to the file (we do this even if we have already inserted
2373  // it into the namespace.
2374  if (fd)
2375  {
2376  md->setFileDef(fd);
2377  fd->insertMember(md.get());
2378  }
2379 
2380  root->markAsProcessed();
2381 
2382  // add member definition to the list of globals
2383  MemberDef *result = md.get();
2384  mn = Doxygen::functionNameLinkedMap->add(name);
2385  mn->push_back(std::move(md));
2386 
2387  return result;
2388 }
2389 
2394 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2395 {
2396  if (lang == SrcLangExt_Fortran || lang == SrcLangExt_VHDL)
2397  {
2398  return -1; // Fortran and VHDL do not have function pointers
2399  }
2400  static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2401  int i=-1,l;
2402  int bb=type.find('<');
2403  int be=type.findRev('>');
2404  if (!type.isEmpty() && // return type is non-empty
2405  (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2406  type.find("operator")==-1 && // not an operator
2407  (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2408  // not a function pointer return type
2409  !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2410  )
2411  {
2412  if (pLength) *pLength=l;
2413  //printf("findFunctionPtr=%d\n",i);
2414  return i;
2415  }
2416  else
2417  {
2418  //printf("findFunctionPtr=%d\n",-1);
2419  return -1;
2420  }
2421 }
2422 
2423 
2427 static bool isVarWithConstructor(const Entry *root)
2428 {
2429  static QRegExp initChars("[0-9\"'&*!^]+");
2430  static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2431  bool result=FALSE;
2432  bool typeIsClass;
2433  QCString type;
2434  Definition *ctx = 0;
2435  FileDef *fd = 0;
2436  int ti;
2437 
2438  //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2439  if (root->parent()->section & Entry::COMPOUND_MASK)
2440  { // inside a class
2441  result=FALSE;
2442  goto done;
2443  }
2444  else if ((fd = root->fileDef()) &&
2445  (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2446  )
2447  { // inside a .c file
2448  result=FALSE;
2449  goto done;
2450  }
2451  if (root->type.isEmpty())
2452  {
2453  result=FALSE;
2454  goto done;
2455  }
2456  if (!root->parent()->name.isEmpty())
2457  {
2458  ctx=Doxygen::namespaceSDict->find(root->parent()->name);
2459  }
2460  type = root->type;
2461  // remove qualifiers
2462  findAndRemoveWord(type,"const");
2463  findAndRemoveWord(type,"static");
2464  findAndRemoveWord(type,"volatile");
2465  //if (type.left(6)=="const ") type=type.right(type.length()-6);
2466  typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2467  if (!typeIsClass && (ti=type.find('<'))!=-1)
2468  {
2469  typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2470  }
2471  if (typeIsClass) // now we still have to check if the arguments are
2472  // types or values. Since we do not have complete type info
2473  // we need to rely on heuristics :-(
2474  {
2475  //printf("typeIsClass\n");
2476  if (root->argList.empty())
2477  {
2478  result=FALSE; // empty arg list -> function prototype.
2479  goto done;
2480  }
2481  for (const Argument &a : root->argList)
2482  {
2483  if (!a.name.isEmpty() || !a.defval.isEmpty())
2484  {
2485  if (a.name.find(initChars)==0)
2486  {
2487  result=TRUE;
2488  }
2489  else
2490  {
2491  result=FALSE; // arg has (type,name) pair -> function prototype
2492  }
2493  goto done;
2494  }
2495  if (a.type.isEmpty() || getResolvedClass(ctx,fd,a.type)!=0)
2496  {
2497  result=FALSE; // arg type is a known type
2498  goto done;
2499  }
2500  if (checkIfTypedef(ctx,fd,a.type))
2501  {
2502  //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2503  result=FALSE; // argument is a typedef
2504  goto done;
2505  }
2506  if (a.type.at(a.type.length()-1)=='*' ||
2507  a.type.at(a.type.length()-1)=='&')
2508  // type ends with * or & => pointer or reference
2509  {
2510  result=FALSE;
2511  goto done;
2512  }
2513  if (a.type.find(initChars)==0)
2514  {
2515  result=TRUE; // argument type starts with typical initializer char
2516  goto done;
2517  }
2518  QCString resType=resolveTypeDef(ctx,a.type);
2519  if (resType.isEmpty()) resType=a.type;
2520  int len;
2521  if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2522  {
2523  resType=resType.left(len);
2524  //printf("resType=%s\n",resType.data());
2525  if (resType=="int" || resType=="long" || resType=="float" ||
2526  resType=="double" || resType=="char" || resType=="signed" ||
2527  resType=="const" || resType=="unsigned" || resType=="void")
2528  {
2529  result=FALSE; // type keyword -> function prototype
2530  goto done;
2531  }
2532  }
2533  }
2534  result=TRUE;
2535  }
2536 
2537 done:
2538  //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2539  // root->type.data(),result);
2540  return result;
2541 }
2542 
2543 static void addVariable(const Entry *root,int isFuncPtr=-1)
2544 {
2545  static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE);
2546 
2548  "VARIABLE_SEC: \n"
2549  " type='%s' name='%s' args='%s' bodyLine=%d mGrpId=%d relates='%s'\n",
2550  qPrint(root->type),
2551  qPrint(root->name),
2552  qPrint(root->args),
2553  root->bodyLine,
2554  root->mGrpId,
2555  qPrint(root->relates)
2556  );
2557  //printf("root->parent->name=%s\n",root->parent->name.data());
2558 
2559  QCString type = root->type;
2560  QCString name = root->name;
2561  QCString args = root->args;
2562  if (type.isEmpty() && name.find("operator")==-1 &&
2563  (name.find('*')!=-1 || name.find('&')!=-1))
2564  {
2565  // recover from parse error caused by redundant braces
2566  // like in "int *(var[10]);", which is parsed as
2567  // type="" name="int *" args="(var[10])"
2568 
2569  type=name;
2570  static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2571  int l=0;
2572  int j=0;
2573  int i=args.isEmpty() ? -1 : reName.match(args,0,&l);
2574  if (i!=-1)
2575  {
2576  name=args.mid(i,l);
2577  j=args.find(')',i+l)-i-l;
2578  if (j >= 0) args=args.mid(i+l,j);
2579  }
2580  //printf("new: type='%s' name='%s' args='%s'\n",
2581  // type.data(),name.data(),args.data());
2582  }
2583  else
2584  {
2585  int i=isFuncPtr;
2586  if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(type,root->lang); // for typedefs isFuncPtr is not yet set
2587  Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no");
2588  if (i!=-1) // function pointer
2589  {
2590  int ai = type.find('[',i);
2591  if (ai>i) // function pointer array
2592  {
2593  args.prepend(type.right(type.length()-ai));
2594  type=type.left(ai);
2595  }
2596  else if (type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2597  {
2598  type=type.left(type.length()-1);
2599  args.prepend(") ");
2600  //printf("type=%s args=%s\n",type.data(),args.data());
2601  }
2602  }
2603  }
2604 
2605  QCString scope;
2606  name=removeRedundantWhiteSpace(name);
2607 
2608  // find the scope of this variable
2609  Entry *p = root->parent();
2610  while ((p->section & Entry::SCOPE_MASK))
2611  {
2612  QCString scopeName = p->name;
2613  if (!scopeName.isEmpty())
2614  {
2615  scope.prepend(scopeName);
2616  break;
2617  }
2618  p=p->parent();
2619  }
2620 
2621  MemberType mtype;
2622  type=type.stripWhiteSpace();
2623  ClassDef *cd=0;
2624  bool isRelated=FALSE;
2625  bool isMemberOf=FALSE;
2626 
2627  QCString classScope=stripAnonymousNamespaceScope(scope);
2628  classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2629  QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2630 
2631  if (name.findRev("::")!=-1)
2632  {
2633  if (type=="friend class" || type=="friend struct" ||
2634  type=="friend union")
2635  {
2636  cd=getClass(scope);
2637  if (cd)
2638  {
2639  addVariableToClass(root, // entry
2640  cd, // class to add member to
2641  MemberType_Friend, // type of member
2642  type, // type value as string
2643  name, // name of the member
2644  args, // arguments as string
2645  FALSE, // from Anonymous scope
2646  0, // anonymous member
2647  Public, // protection
2648  Member // related to a class
2649  );
2650  }
2651  }
2652  return; /* skip this member, because it is a
2653  * static variable definition (always?), which will be
2654  * found in a class scope as well, but then we know the
2655  * correct protection level, so only then it will be
2656  * inserted in the correct list!
2657  */
2658  }
2659 
2660  if (type=="@")
2661  mtype=MemberType_EnumValue;
2662  else if (type.left(8)=="typedef ")
2663  mtype=MemberType_Typedef;
2664  else if (type.left(7)=="friend ")
2665  mtype=MemberType_Friend;
2666  else if (root->mtype==Property)
2667  mtype=MemberType_Property;
2668  else if (root->mtype==Event)
2669  mtype=MemberType_Event;
2670  else if (type.find("sequence<") != -1)
2671  mtype=sliceOpt ? MemberType_Sequence : MemberType_Typedef;
2672  else if (type.find("dictionary<") != -1)
2673  mtype=sliceOpt ? MemberType_Dictionary : MemberType_Typedef;
2674  else
2675  mtype=MemberType_Variable;
2676 
2677  if (!root->relates.isEmpty()) // related variable
2678  {
2679  isRelated=TRUE;
2680  isMemberOf=(root->relatesType == MemberOf);
2681  if (getClass(root->relates)==0 && !scope.isEmpty())
2682  scope=mergeScopes(scope,root->relates);
2683  else
2684  scope=root->relates;
2685  }
2686 
2687  cd=getClass(scope);
2688  if (cd==0 && classScope!=scope) cd=getClass(classScope);
2689  if (cd)
2690  {
2691  MemberDef *md=0;
2692 
2693  // if cd is an anonymous (=tag less) scope we insert the member
2694  // into a non-anonymous parent scope as well. This is needed to
2695  // be able to refer to it using \var or \fn
2696 
2697  //int indentDepth=0;
2698  int si=scope.find('@');
2699  //int anonyScopes = 0;
2700  //bool added=FALSE;
2701 
2702  static bool inlineSimpleStructs = Config_getBool(INLINE_SIMPLE_STRUCTS);
2703  if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2704  {
2705  QCString pScope;
2706  ClassDef *pcd=0;
2707  pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2708  if (!pScope.isEmpty())
2709  pScope.prepend(annScopePrefix);
2710  else if (annScopePrefix.length()>2)
2711  pScope=annScopePrefix.left(annScopePrefix.length()-2);
2712  if (name.at(0)!='@')
2713  {
2714  if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2715  {
2716  md=addVariableToClass(root, // entry
2717  pcd, // class to add member to
2718  mtype, // member type
2719  type, // type value as string
2720  name, // member name
2721  args, // arguments as string
2722  TRUE, // from anonymous scope
2723  0, // from anonymous member
2724  root->protection,
2725  isMemberOf ? Foreign : isRelated ? Related : Member
2726  );
2727  //added=TRUE;
2728  }
2729  else // anonymous scope inside namespace or file => put variable in the global scope
2730  {
2731  if (mtype==MemberType_Variable)
2732  {
2733  md=addVariableToFile(root,mtype,pScope,type,name,args,TRUE,0);
2734  }
2735  //added=TRUE;
2736  }
2737  }
2738  }
2739 
2740  //printf("name='%s' scope=%s scope.right=%s\n",
2741  // name.data(),scope.data(),
2742  // scope.right(scope.length()-si).data());
2743  addVariableToClass(root, // entry
2744  cd, // class to add member to
2745  mtype, // member type
2746  type, // type value as string
2747  name, // name of the member
2748  args, // arguments as string
2749  FALSE, // from anonymous scope
2750  md, // from anonymous member
2751  root->protection,
2752  isMemberOf ? Foreign : isRelated ? Related : Member);
2753  }
2754  else if (!name.isEmpty()) // global variable
2755  {
2756  //printf("Inserting member in global scope %s!\n",scope.data());
2757  addVariableToFile(root,mtype,scope,type,name,args,FALSE,/*0,*/0);
2758  }
2759 
2760 }
2761 
2762 //----------------------------------------------------------------------
2763 // Searches the Entry tree for typedef documentation sections.
2764 // If found they are stored in their class or in the global list.
2765 static void buildTypedefList(const Entry *root)
2766 {
2767  //printf("buildVarList(%s)\n",rootNav->name().data());
2768  if (!root->name.isEmpty() &&
2769  root->section==Entry::VARIABLE_SEC &&
2770  root->type.find("typedef ")!=-1 // its a typedef
2771  )
2772  {
2773  addVariable(root);
2774  }
2775  for (const auto &e : root->children())
2776  if (e->section!=Entry::ENUM_SEC)
2777  buildTypedefList(e.get());
2778 }
2779 
2780 //----------------------------------------------------------------------
2781 // Searches the Entry tree for sequence documentation sections.
2782 // If found they are stored in the global list.
2783 static void buildSequenceList(const Entry *root)
2784 {
2785  if (!root->name.isEmpty() &&
2786  root->section==Entry::VARIABLE_SEC &&
2787  root->type.find("sequence<")!=-1 // it's a sequence
2788  )
2789  {
2790  addVariable(root);
2791  }
2792  for (const auto &e : root->children())
2793  if (e->section!=Entry::ENUM_SEC)
2794  buildSequenceList(e.get());
2795 }
2796 
2797 //----------------------------------------------------------------------
2798 // Searches the Entry tree for dictionary documentation sections.
2799 // If found they are stored in the global list.
2800 static void buildDictionaryList(const Entry *root)
2801 {
2802  if (!root->name.isEmpty() &&
2803  root->section==Entry::VARIABLE_SEC &&
2804  root->type.find("dictionary<")!=-1 // it's a dictionary
2805  )
2806  {
2807  addVariable(root);
2808  }
2809  for (const auto &e : root->children())
2810  if (e->section!=Entry::ENUM_SEC)
2811  buildDictionaryList(e.get());
2812 }
2813 
2814 //----------------------------------------------------------------------
2815 // Searches the Entry tree for Variable documentation sections.
2816 // If found they are stored in their class or in the global list.
2817 
2818 static void buildVarList(const Entry *root)
2819 {
2820  //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
2821  int isFuncPtr=-1;
2822  if (!root->name.isEmpty() &&
2823  (root->type.isEmpty() || g_compoundKeywordDict.find(root->type)==0) &&
2824  (
2825  (root->section==Entry::VARIABLE_SEC // it's a variable
2826  ) ||
2827  (root->section==Entry::FUNCTION_SEC && // or maybe a function pointer variable
2828  (isFuncPtr=findFunctionPtr(root->type,root->lang))!=-1
2829  ) ||
2830  (root->section==Entry::FUNCTION_SEC && // class variable initialized by constructor
2831  isVarWithConstructor(root)
2832  )
2833  )
2834  ) // documented variable
2835  {
2836  addVariable(root,isFuncPtr);
2837  }
2838  for (const auto &e : root->children())
2839  if (e->section!=Entry::ENUM_SEC)
2840  buildVarList(e.get());
2841 }
2842 
2843 //----------------------------------------------------------------------
2844 // Searches the Entry tree for Interface sections (UNO IDL only).
2845 // If found they are stored in their service or in the global list.
2846 //
2847 
2849  const Entry *root,
2850  ClassDef *const cd,
2851  QCString const& rname)
2852 {
2853  FileDef *fd = root->fileDef();
2854  enum MemberType type = (root->section==Entry::EXPORTED_INTERFACE_SEC)
2857  QCString fileName = root->fileName;
2858  if (fileName.isEmpty() && root->tagInfo())
2859  {
2860  fileName = root->tagInfo()->tagName;
2861  }
2862  std::unique_ptr<MemberDef> md { createMemberDef(
2863  fileName, root->startLine, root->startColumn, root->type, rname,
2864  "", "", root->protection, root->virt, root->stat, Member,
2865  type, ArgumentList(), root->argList, root->metaData) };
2866  md->setTagInfo(root->tagInfo());
2867  md->setMemberClass(cd);
2868  md->setDocumentation(root->doc,root->docFile,root->docLine);
2869  md->setDocsForDefinition(false);
2870  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2871  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2872  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
2873  md->setMemberSpecifiers(root->spec);
2874  md->setMemberGroupId(root->mGrpId);
2875  md->setTypeConstraints(root->typeConstr);
2876  md->setLanguage(root->lang);
2877  md->setBodyDef(fd);
2878  md->setFileDef(fd);
2879  md->addSectionsToDefinition(root->anchors);
2880  QCString const def = root->type + " " + rname;
2881  md->setDefinition(def);
2882  md->enableCallGraph(root->callGraph);
2883  md->enableCallerGraph(root->callerGraph);
2884  md->enableReferencedByRelation(root->referencedByRelation);
2885  md->enableReferencesRelation(root->referencesRelation);
2886 
2888  " Interface Member:\n"
2889  " '%s' '%s' proto=%d\n"
2890  " def='%s'\n",
2891  qPrint(root->type),
2892  qPrint(rname),
2893  root->proto,
2894  qPrint(def)
2895  );
2896 
2897 
2898  // add member to the class cd
2899  cd->insertMember(md.get());
2900  // also add the member as a "base" (to get nicer diagrams)
2901  // "optional" interface/service get Protected which turns into dashed line
2902  BaseInfo base(rname,
2903  (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
2904  findClassRelation(root,cd,cd,&base,0,DocumentedOnly,true) || findClassRelation(root,cd,cd,&base,0,Undocumented,true);
2905  // add file to list of used files
2906  cd->insertUsedFile(fd);
2907 
2908  addMemberToGroups(root,md.get());
2909  root->markAsProcessed();
2910  md->setRefItems(root->sli);
2911 
2912  // add member to the global list of all members
2914  mn->push_back(std::move(md));
2915 }
2916 
2917 static void buildInterfaceAndServiceList(const Entry *root)
2918 {
2921  {
2923  "EXPORTED_INTERFACE_SEC:\n"
2924  " '%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",
2925  qPrint(root->type),
2926  qPrint(root->parent()->name),
2927  qPrint(root->name),
2928  qPrint(root->args),
2929  qPrint(root->relates),
2930  root->relatesType,
2931  qPrint(root->fileName),
2932  root->startLine,
2933  root->bodyLine,
2934  root->tArgLists.size(),
2935  root->mGrpId,
2936  root->spec,
2937  root->proto,
2938  qPrint(root->docFile)
2939  );
2940 
2941  QCString rname = removeRedundantWhiteSpace(root->name);
2942 
2943  if (!rname.isEmpty())
2944  {
2945  QCString scope = root->parent()->name;
2946  ClassDef *cd = getClass(scope);
2947  assert(cd);
2948  if (cd && ((ClassDef::Interface == cd->compoundType()) ||
2949  (ClassDef::Service == cd->compoundType()) ||
2950  (ClassDef::Singleton == cd->compoundType())))
2951  {
2953  }
2954  else
2955  {
2956  assert(false); // was checked by scanner.l
2957  }
2958  }
2959  else if (rname.isEmpty())
2960  {
2961  warn(root->fileName,root->startLine,
2962  "Illegal member name found.");
2963  }
2964  }
2965  // can only have these in IDL anyway
2966  switch (root->lang)
2967  {
2968  case SrcLangExt_Unknown: // fall through (root node always is Unknown)
2969  case SrcLangExt_IDL:
2970  for (const auto &e : root->children()) buildInterfaceAndServiceList(e.get());
2971  break;
2972  default:
2973  return; // nothing to do here
2974  }
2975 }
2976 
2977 
2978 //----------------------------------------------------------------------
2979 // Searches the Entry tree for Function sections.
2980 // If found they are stored in their class or in the global list.
2981 
2982 static void addMethodToClass(const Entry *root,ClassDef *cd,
2983  const QCString &rtype,const QCString &rname,const QCString &rargs,
2984  bool isFriend,
2985  Protection protection,bool stat,Specifier virt,uint64 spec,
2986  const QCString &relates
2987  )
2988 {
2989  FileDef *fd=root->fileDef();
2990 
2991  int l;
2992  static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
2993  QCString type = rtype;
2994  QCString args = rargs;
2995  int ts=type.find('<');
2996  int te=type.findRev('>');
2997  int i=re.match(type,0,&l);
2998  if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
2999  {
3000  i=-1;
3001  }
3002 
3003  if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3004  !type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3005  {
3006  args+=type.right(type.length()-i-l);
3007  type=type.left(i+l);
3008  }
3009 
3010  QCString name=removeRedundantWhiteSpace(rname);
3011  if (name.left(2)=="::") name=name.right(name.length()-2);
3012 
3013  MemberType mtype;
3014  if (isFriend) mtype=MemberType_Friend;
3015  else if (root->mtype==Signal) mtype=MemberType_Signal;
3016  else if (root->mtype==Slot) mtype=MemberType_Slot;
3017  else if (root->mtype==DCOP) mtype=MemberType_DCOP;
3018  else mtype=MemberType_Function;
3019 
3020  // strip redundant template specifier for constructors
3021  if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3022  name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3023  {
3024  name=name.left(i);
3025  }
3026 
3027  QCString fileName = root->fileName;
3028  if (fileName.isEmpty() && root->tagInfo())
3029  {
3030  fileName = root->tagInfo()->tagName;
3031  }
3032 
3033  //printf("root->name='%s; args='%s' root->argList='%s'\n",
3034  // root->name.data(),args.data(),argListToString(root->argList).data()
3035  // );
3036 
3037  // adding class member
3038  std::unique_ptr<MemberDef> md { createMemberDef(
3039  fileName,root->startLine,root->startColumn,
3040  type,name,args,root->exception,
3041  protection,virt,
3042  stat && root->relatesType != MemberOf,
3043  relates.isEmpty() ? Member :
3044  root->relatesType == MemberOf ? Foreign : Related,
3045  mtype,!root->tArgLists.empty() ? root->tArgLists.back() : ArgumentList(),
3046  root->argList, root->metaData) };
3047  md->setTagInfo(root->tagInfo());
3048  md->setMemberClass(cd);
3049  md->setDocumentation(root->doc,root->docFile,root->docLine);
3050  md->setDocsForDefinition(!root->proto);
3051  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3052  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3053  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
3054  md->setMemberSpecifiers(spec);
3055  md->setMemberGroupId(root->mGrpId);
3056  md->setTypeConstraints(root->typeConstr);
3057  md->setLanguage(root->lang);
3058  md->setId(root->id);
3059  md->setBodyDef(fd);
3060  md->setFileDef(fd);
3061  //md->setScopeTemplateArguments(root->tArgList);
3062  md->addSectionsToDefinition(root->anchors);
3063  QCString def;
3065  SrcLangExt lang = cd->getLanguage();
3066  QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3067  if (scopeSeparator!="::")
3068  {
3069  qualScope = substitute(qualScope,"::",scopeSeparator);
3070  }
3071  if (lang==SrcLangExt_PHP)
3072  {
3073  // for PHP we use Class::method and Namespace\method
3074  scopeSeparator="::";
3075  }
3076 // QCString optArgs = root->argList.empty() ? args : QCString();
3077  if (!relates.isEmpty() || isFriend || Config_getBool(HIDE_SCOPE_NAMES))
3078  {
3079  if (!type.isEmpty())
3080  {
3081  def=type+" "+name; //+optArgs;
3082  }
3083  else
3084  {
3085  def=name; //+optArgs;
3086  }
3087  }
3088  else
3089  {
3090  if (!type.isEmpty())
3091  {
3092  def=type+" "+qualScope+scopeSeparator+name; //+optArgs;
3093  }
3094  else
3095  {
3096  def=qualScope+scopeSeparator+name; //+optArgs;
3097  }
3098  }
3099  if (def.left(7)=="friend ") def=def.right(def.length()-7);
3100  md->setDefinition(def);
3101  md->enableCallGraph(root->callGraph);
3102  md->enableCallerGraph(root->callerGraph);
3103  md->enableReferencedByRelation(root->referencedByRelation);
3104  md->enableReferencesRelation(root->referencesRelation);
3105 
3107  " Func Member:\n"
3108  " '%s' '%s'::'%s' '%s' proto=%d\n"
3109  " def='%s'\n",
3110  qPrint(type),
3111  qPrint(qualScope),
3112  qPrint(rname),
3113  qPrint(args),
3114  root->proto,
3115  qPrint(def)
3116  );
3117 
3118  // add member to the class cd
3119  cd->insertMember(md.get());
3120  // add file to list of used files
3121  cd->insertUsedFile(fd);
3122 
3123  addMemberToGroups(root,md.get());
3124  root->markAsProcessed();
3125  md->setRefItems(root->sli);
3126 
3127  // add member to the global list of all members
3128  //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3130  mn->push_back(std::move(md));
3131 }
3132 
3133 //------------------------------------------------------------------------------------------
3134 
3135 void addGlobalFunction(const Entry *root,const QCString &rname,const QCString &sc,
3136  NamespaceDef *nd)
3137 {
3138  QCString scope = sc;
3139  Debug::print(Debug::Functions,0," --> new function %s found!\n",qPrint(rname));
3140  //printf("New function type='%s' name='%s' args='%s' bodyLine=%d\n",
3141  // root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3142 
3143  // new global function
3144  QCString name=removeRedundantWhiteSpace(rname);
3145  std::unique_ptr<MemberDef> md { createMemberDef(
3146  root->fileName,root->startLine,root->startColumn,
3147  root->type,name,root->args,root->exception,
3148  root->protection,root->virt,root->stat,Member,
3150  !root->tArgLists.empty() ? root->tArgLists.back() : ArgumentList(),
3151  root->argList,root->metaData) };
3152 
3153  md->setTagInfo(root->tagInfo());
3154  md->setLanguage(root->lang);
3155  md->setId(root->id);
3156  //md->setDefFile(root->fileName);
3157  //md->setDefLine(root->startLine);
3158  md->setDocumentation(root->doc,root->docFile,root->docLine);
3159  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3160  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3161  md->setPrototype(root->proto,root->fileName,root->startLine,root->startColumn);
3162  md->setDocsForDefinition(!root->proto);
3163  md->setTypeConstraints(root->typeConstr);
3164  //md->setBody(root->body);
3165  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
3166  FileDef *fd=root->fileDef();
3167  md->setBodyDef(fd);
3168  md->addSectionsToDefinition(root->anchors);
3169  md->setMemberSpecifiers(root->spec);
3170  md->setMemberGroupId(root->mGrpId);
3171 
3172  // see if the function is inside a namespace that was not part of
3173  // the name already (in that case nd should be non-zero already)
3174  if (nd==0 && root->parent()->section == Entry::NAMESPACE_SEC )
3175  {
3176  //QCString nscope=removeAnonymousScopes(root->parent()->name);
3177  QCString nscope=root->parent()->name;
3178  if (!nscope.isEmpty())
3179  {
3180  nd = getResolvedNamespace(nscope);
3181  }
3182  }
3183 
3184  if (!scope.isEmpty())
3185  {
3187  if (sep!="::")
3188  {
3189  scope = substitute(scope,"::",sep);
3190  }
3191  scope+=sep;
3192  }
3193 
3194  QCString def;
3195  //QCString optArgs = root->argList.empty() ? QCString() : root->args;
3196  if (!root->type.isEmpty())
3197  {
3198  def=root->type+" "+scope+name; //+optArgs;
3199  }
3200  else
3201  {
3202  def=scope+name; //+optArgs;
3203  }
3205  " Global Function:\n"
3206  " '%s' '%s'::'%s' '%s' proto=%d\n"
3207  " def='%s'\n",
3208  qPrint(root->type),
3209  qPrint(root->parent()->name),
3210  qPrint(rname),
3211  qPrint(root->args),
3212  root->proto,
3213  qPrint(def)
3214  );
3215  md->setDefinition(def);
3216  md->enableCallGraph(root->callGraph);
3217  md->enableCallerGraph(root->callerGraph);
3218  md->enableReferencedByRelation(root->referencedByRelation);
3219  md->enableReferencesRelation(root->referencesRelation);
3220  //if (root->mGrpId!=-1)
3221  //{
3222  // md->setMemberGroup(memberGroupDict[root->mGrpId]);
3223  //}
3224 
3225  md->setRefItems(root->sli);
3226  if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3227  {
3228  // add member to namespace
3229  md->setNamespace(nd);
3230  nd->insertMember(md.get());
3231  }
3232  if (fd)
3233  {
3234  // add member to the file (we do this even if we have already
3235  // inserted it into the namespace)
3236  md->setFileDef(fd);
3237  fd->insertMember(md.get());
3238  }
3239 
3240  addMemberToGroups(root,md.get());
3241  if (root->relatesType == Simple) // if this is a relatesalso command,
3242  // allow find Member to pick it up
3243  {
3244  root->markAsProcessed(); // Otherwise we have finished with this entry.
3245  }
3246 
3247  // add member to the list of file members
3248  //printf("Adding member=%s\n",md->name().data());
3250  mn->push_back(std::move(md));
3251 }
3252 
3253 //------------------------------------------------------------------------------------------
3254 
3255 static void buildFunctionList(const Entry *root)
3256 {
3257  if (root->section==Entry::FUNCTION_SEC)
3258  {
3260  "FUNCTION_SEC:\n"
3261  " '%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",
3262  qPrint(root->type),
3263  qPrint(root->parent()->name),
3264  qPrint(root->name),
3265  qPrint(root->args),
3266  qPrint(root->relates),
3267  root->relatesType,
3268  qPrint(root->fileName),
3269  root->startLine,
3270  root->bodyLine,
3271  root->tArgLists.size(),
3272  root->mGrpId,
3273  root->spec,
3274  root->proto,
3275  qPrint(root->docFile)
3276  );
3277 
3278  bool isFriend=root->type.find("friend ")!=-1;
3279  QCString rname = removeRedundantWhiteSpace(root->name);
3280  //printf("rname=%s\n",rname.data());
3281 
3282  QCString scope=root->parent()->name; //stripAnonymousNamespaceScope(root->parent->name);
3283  if (!rname.isEmpty() && scope.find('@')==-1)
3284  {
3285  ClassDef *cd=0;
3286  // check if this function's parent is a class
3288 
3289  FileDef *rfd=root->fileDef();
3290 
3291  int memIndex=rname.findRev("::");
3292 
3293  cd=getClass(scope);
3294  if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3295  {
3296  // strip scope from name
3297  rname=rname.right(rname.length()-root->parent()->name.length()-2);
3298  }
3299 
3300  NamespaceDef *nd = 0;
3301  bool isMember=FALSE;
3302  if (memIndex!=-1)
3303  {
3304  int ts=rname.find('<');
3305  int te=rname.find('>');
3306  if (memIndex>0 && (ts==-1 || te==-1))
3307  {
3308  // note: the following code was replaced by inMember=TRUE to deal with a
3309  // function rname='X::foo' of class X inside a namespace also called X...
3310  // bug id 548175
3311  //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3312  //isMember = nd==0;
3313  //if (nd)
3314  //{
3315  // // strip namespace scope from name
3316  // scope=rname.left(memIndex);
3317  // rname=rname.right(rname.length()-memIndex-2);
3318  //}
3319  isMember = TRUE;
3320  }
3321  else
3322  {
3323  isMember=memIndex<ts || memIndex>te;
3324  }
3325  }
3326 
3327  static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3328  int ts=root->type.find('<');
3329  int te=root->type.findRev('>');
3330  int ti;
3331  if (!root->parent()->name.isEmpty() &&
3332  (root->parent()->section & Entry::COMPOUND_MASK) &&
3333  cd &&
3334  // do some fuzzy things to exclude function pointers
3335  (root->type.isEmpty() ||
3336  ((ti=root->type.find(re,0))==-1 || // type does not contain ..(..*
3337  (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3338  root->args.find(")[")!=-1) || // and args not )[.. -> function pointer
3339  root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3340  cd->getLanguage()!=SrcLangExt_Cpp // language other than C
3341  )
3342  )
3343  {
3344  Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
3345  qPrint(rname),qPrint(cd->name()));
3346  addMethodToClass(root,cd,root->type,rname,root->args,isFriend,
3347  root->protection,root->stat,root->virt,root->spec,root->relates);
3348  }
3349  else if (!((root->parent()->section & Entry::COMPOUND_MASK)
3350  || root->parent()->section==Entry::OBJCIMPL_SEC
3351  ) &&
3352  !isMember &&
3353  (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3354  root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3355  )
3356  // no member => unrelated function
3357  {
3358  /* check the uniqueness of the function name in the file.
3359  * A file could contain a function prototype and a function definition
3360  * or even multiple function prototypes.
3361  */
3362  bool found=FALSE;
3363  MemberName *mn;
3364  MemberDef *md_found=0;
3365  if ((mn=Doxygen::functionNameLinkedMap->find(rname)))
3366  {
3367  Debug::print(Debug::Functions,0," --> function %s already found!\n",qPrint(rname));
3368  for (const auto &md : *mn)
3369  {
3370  if (!md->isAlias())
3371  {
3372  const NamespaceDef *mnd = md->getNamespaceDef();
3373  NamespaceDef *rnd = 0;
3374  //printf("root namespace=%s\n",rootNav->parent()->name().data());
3375  QCString fullScope = scope;
3376  QCString parentScope = root->parent()->name;
3377  if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3378  {
3379  if (!scope.isEmpty()) fullScope.prepend("::");
3380  fullScope.prepend(parentScope);
3381  }
3382  //printf("fullScope=%s\n",fullScope.data());
3383  rnd = getResolvedNamespace(fullScope);
3384  const FileDef *mfd = md->getFileDef();
3385  QCString nsName,rnsName;
3386  if (mnd) nsName = mnd->name().copy();
3387  if (rnd) rnsName = rnd->name().copy();
3388  //printf("matching arguments for %s%s %s%s\n",
3389  // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3390  ArgumentList &mdAl = md->argumentList();
3391  const ArgumentList &mdTempl = md->templateArguments();
3392 
3393  // in case of template functions, we need to check if the
3394  // functions have the same number of template parameters
3395  bool sameNumTemplateArgs = TRUE;
3396  bool matchingReturnTypes = TRUE;
3397  if (!mdTempl.empty() && !root->tArgLists.empty())
3398  {
3399  if (mdTempl.size()!=root->tArgLists.back().size())
3400  {
3401  sameNumTemplateArgs = FALSE;
3402  }
3403  if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3404  {
3405  matchingReturnTypes = FALSE;
3406  }
3407  }
3408 
3409  bool staticsInDifferentFiles =
3410  root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3411 
3412  if (
3413  matchArguments2(md->getOuterScope(),mfd,mdAl,
3414  rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3415  FALSE) &&
3416  sameNumTemplateArgs &&
3417  matchingReturnTypes &&
3418  !staticsInDifferentFiles
3419  )
3420  {
3421  GroupDef *gd=0;
3422  if (!root->groups.empty() && !root->groups.front().groupname.isEmpty())
3423  {
3424  gd = Doxygen::groupSDict->find(root->groups.front().groupname);
3425  }
3426  //printf("match!\n");
3427  //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3428  // see if we need to create a new member
3429  found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace
3430  ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and
3431  mfd->absFilePath()==root->fileName // prototype in the same file
3432  )
3433  );
3434  // otherwise, allow a duplicate global member with the same argument list
3435  if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3436  {
3437  // member is already in the group, so we don't want to add it again.
3438  found=TRUE;
3439  }
3440 
3441  //printf("combining function with prototype found=%d in namespace %s\n",
3442  // found,nsName.data());
3443 
3444  if (found)
3445  {
3446  // merge argument lists
3447  ArgumentList mergedArgList = root->argList;
3448  mergeArguments(mdAl,mergedArgList,!root->doc.isEmpty());
3449  // merge documentation
3450  if (md->documentation().isEmpty() && !root->doc.isEmpty())
3451  {
3452  ArgumentList argList;
3453  stringToArgumentList(root->lang,root->args,argList);
3454  if (root->proto)
3455  {
3456  //printf("setDeclArgumentList to %p\n",argList);
3457  md->setDeclArgumentList(argList);
3458  }
3459  else
3460  {
3461  md->setArgumentList(argList);
3462  }
3463  }
3464 
3465  md->setDocumentation(root->doc,root->docFile,root->docLine);
3466  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3467  md->setDocsForDefinition(!root->proto);
3468  if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3469  {
3470  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
3471  md->setBodyDef(rfd);
3472  }
3473 
3474  if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3475  {
3476  md->setArgsString(root->args);
3477  }
3478  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3479 
3480  md->addSectionsToDefinition(root->anchors);
3481 
3482  md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3483  md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3484  md->enableReferencedByRelation(md->hasReferencedByRelation() || root->referencedByRelation);
3485  md->enableReferencesRelation(md->hasReferencesRelation() || root->referencesRelation);
3486 
3487  // merge ingroup specifiers
3488  if (md->getGroupDef()==0 && !root->groups.empty())
3489  {
3490  addMemberToGroups(root,md.get());
3491  }
3492  else if (md->getGroupDef()!=0 && root->groups.empty())
3493  {
3494  //printf("existing member is grouped, new member not\n");
3495  }
3496  else if (md->getGroupDef()!=0 && !root->groups.empty())
3497  {
3498  //printf("both members are grouped\n");
3499  }
3500 
3501  // if md is a declaration and root is the corresponding
3502  // definition, then turn md into a definition.
3503  if (md->isPrototype() && !root->proto)
3504  {
3505  md->setDeclFile(md->getDefFileName(),md->getDefLine(),md->getDefColumn());
3506  md->setPrototype(FALSE,root->fileName,root->startLine,root->startColumn);
3507  }
3508  // if md is already the definition, then add the declaration info
3509  else if (!md->isPrototype() && root->proto)
3510  {
3511  md->setDeclFile(root->fileName,root->startLine,root->startColumn);
3512  }
3513  }
3514  }
3515  }
3516  if (found)
3517  {
3518  md_found = md.get();
3519  break;
3520  }
3521  }
3522  }
3523  if (!found) /* global function is unique with respect to the file */
3524  {
3525  addGlobalFunction(root,rname,scope,nd);
3526  }
3527  else
3528  {
3529  FileDef *fd=root->fileDef();
3530  if (fd)
3531  {
3532  // add member to the file (we do this even if we have already
3533  // inserted it into the namespace)
3534  fd->insertMember(md_found);
3535  }
3536  }
3537 
3538  //printf("unrelated function %d '%s' '%s' '%s'\n",
3539  // root->parent->section,root->type.data(),rname.data(),root->args.data());
3540  }
3541  else
3542  {
3543  Debug::print(Debug::Functions,0," --> %s not processed!\n",qPrint(rname));
3544  }
3545  }
3546  else if (rname.isEmpty())
3547  {
3548  warn(root->fileName,root->startLine,
3549  "Illegal member name found."
3550  );
3551  }
3552  }
3553  for (const auto &e : root->children()) buildFunctionList(e.get());
3554 }
3555 
3556 //----------------------------------------------------------------------
3557 
3558 static void findFriends()
3559 {
3560  //printf("findFriends()\n");
3561  for (const auto &fn : *Doxygen::functionNameLinkedMap) // for each global function name
3562  {
3563  //printf("Function name='%s'\n",fn->memberName());
3564  MemberName *mn;
3565  if ((mn=Doxygen::memberNameLinkedMap->find(fn->memberName())))
3566  { // there are members with the same name
3567  //printf("Function name is also a member name\n");
3568  // for each function with that name
3569  for (const auto &fmd : *fn)
3570  {
3571  const MemberDef *cfmd = fmd.get();
3572  // for each member with that name
3573  for (const auto &mmd : *mn)
3574  {
3575  const MemberDef *cmmd = mmd.get();
3576  //printf("Checking for matching arguments
3577  // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3578  // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3579  if ((cmmd->isFriend() || (cmmd->isRelated() && cmmd->isFunction())) &&
3580  !fmd->isAlias() && !mmd->isAlias() &&
3581  matchArguments2(cmmd->getOuterScope(), cmmd->getFileDef(), cmmd->argumentList(),
3582  cfmd->getOuterScope(), cfmd->getFileDef(), cfmd->argumentList(),
3583  TRUE
3584  )
3585 
3586  ) // if the member is related and the arguments match then the
3587  // function is actually a friend.
3588  {
3589  ArgumentList &mmdAl = mmd->argumentList();
3590  ArgumentList &fmdAl = fmd->argumentList();
3591  mergeArguments(mmdAl,fmdAl);
3592  if (!fmd->documentation().isEmpty())
3593  {
3594  mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3595  }
3596  else if (!mmd->documentation().isEmpty())
3597  {
3598  fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3599  }
3600  if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3601  {
3602  mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3603  }
3604  else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3605  {
3606  fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3607  }
3608  if (!fmd->inbodyDocumentation().isEmpty())
3609  {
3610  mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3611  }
3612  else if (!mmd->inbodyDocumentation().isEmpty())
3613  {
3614  fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3615  }
3616  //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3617  if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3618  {
3619  mmd->setBodySegment(fmd->getDefLine(),fmd->getStartBodyLine(),fmd->getEndBodyLine());
3620  mmd->setBodyDef(fmd->getBodyDef());
3621  //mmd->setBodyMember(fmd);
3622  }
3623  else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3624  {
3625  fmd->setBodySegment(mmd->getDefLine(),mmd->getStartBodyLine(),mmd->getEndBodyLine());
3626  fmd->setBodyDef(mmd->getBodyDef());
3627  //fmd->setBodyMember(mmd);
3628  }
3629  mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3630 
3631  mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3632  mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3633  mmd->enableReferencedByRelation(mmd->hasReferencedByRelation() || fmd->hasReferencedByRelation());
3634  mmd->enableReferencesRelation(mmd->hasReferencesRelation() || fmd->hasReferencesRelation());
3635 
3636  fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3637  fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3638  fmd->enableReferencedByRelation(mmd->hasReferencedByRelation() || fmd->hasReferencedByRelation());
3639  fmd->enableReferencesRelation(mmd->hasReferencesRelation() || fmd->hasReferencesRelation());
3640  }
3641  }
3642  }
3643  }
3644  }
3645 }
3646 
3647 //----------------------------------------------------------------------
3648 
3650 {
3651  //printf("---- transferFunctionDocumentation()\n");
3652 
3653  // find matching function declaration and definitions.
3654  for (const auto &mn : *Doxygen::functionNameLinkedMap)
3655  {
3656  //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3657  /* find a matching function declaration and definition for this function */
3658  for (const auto &mdec : *mn)
3659  {
3660  if (mdec->isPrototype() ||
3661  (mdec->isVariable() && mdec->isExternal())
3662  )
3663  {
3664  for (const auto &mdef : *mn)
3665  {
3666  if (mdec!=mdef &&
3667  !mdec->isAlias() && !mdef->isAlias() &&
3668  mdec->getNamespaceDef()==mdef->getNamespaceDef())
3669  {
3670  combineDeclarationAndDefinition(mdec.get(),mdef.get());
3671  }
3672  }
3673  }
3674  }
3675  }
3676 }
3677 
3678 //----------------------------------------------------------------------
3679 
3681 {
3682  for (const auto &mn : *Doxygen::functionNameLinkedMap)
3683  {
3684  MemberDef *mdef=0,*mdec=0;
3685  /* find a matching function declaration and definition for this function */
3686  for (const auto &md : *mn)
3687  {
3688  if (md->isPrototype())
3689  mdec=md.get();
3690  else if (md->isVariable() && md->isExternal())
3691  mdec=md.get();
3692 
3693  if (md->isFunction() && !md->isStatic() && !md->isPrototype())
3694  mdef=md.get();
3695  else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3696  mdef=md.get();
3697 
3698  if (mdef && mdec) break;
3699  }
3700  if (mdef && mdec)
3701  {
3702  ArgumentList &mdefAl = mdef->argumentList();
3703  ArgumentList &mdecAl = mdec->argumentList();
3704  if (
3705  matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
3706  mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
3707  TRUE
3708  )
3709  ) /* match found */
3710  {
3711  MemberSDict *defDict = mdef->getReferencesMembers();
3712  MemberSDict *decDict = mdec->getReferencesMembers();
3713  if (defDict!=0)
3714  {
3715  MemberSDict::IteratorDict msdi(*defDict);
3716  MemberDef *rmd;
3717  for (msdi.toFirst();(rmd=msdi.current());++msdi)
3718  {
3719  if (decDict==0 || decDict->find(rmd->name())==0)
3720  {
3721  mdec->addSourceReferences(rmd);
3722  }
3723  }
3724  }
3725  if (decDict!=0)
3726  {
3727  MemberSDict::IteratorDict msdi(*decDict);
3728  MemberDef *rmd;
3729  for (msdi.toFirst();(rmd=msdi.current());++msdi)
3730  {
3731  if (defDict==0 || defDict->find(rmd->name())==0)
3732  {
3733  mdef->addSourceReferences(rmd);
3734  }
3735  }
3736  }
3737 
3738  defDict = mdef->getReferencedByMembers();
3739  decDict = mdec->getReferencedByMembers();
3740  if (defDict!=0)
3741  {
3742  MemberSDict::IteratorDict msdi(*defDict);
3743  MemberDef *rmd;
3744  for (msdi.toFirst();(rmd=msdi.current());++msdi)
3745  {
3746  if (decDict==0 || decDict->find(rmd->name())==0)
3747  {
3748  mdec->addSourceReferencedBy(rmd);
3749  }
3750  }
3751  }
3752  if (decDict!=0)
3753  {
3754  MemberSDict::IteratorDict msdi(*decDict);
3755  MemberDef *rmd;
3756  for (msdi.toFirst();(rmd=msdi.current());++msdi)
3757  {
3758  if (defDict==0 || defDict->find(rmd->name())==0)
3759  {
3760  mdef->addSourceReferencedBy(rmd);
3761  }
3762  }
3763  }
3764  }
3765  }
3766  }
3767 }
3768 
3769 //----------------------------------------------------------------------
3770 
3772 {
3773  // find match between function declaration and definition for
3774  // related functions
3775  for (const auto &mn : *Doxygen::functionNameLinkedMap)
3776  {
3777  /* find a matching function declaration and definition for this function */
3778  // for each global function
3779  for (const auto &md : *mn)
3780  {
3781  //printf(" Function '%s'\n",md->name().data());
3782  MemberName *rmn;
3783  if ((rmn=Doxygen::memberNameLinkedMap->find(md->name()))) // check if there is a member with the same name
3784  {
3785  //printf(" Member name found\n");
3786  // for each member with the same name
3787  for (const auto &rmd : *rmn)
3788  {
3789  //printf(" Member found: related='%d'\n",rmd->isRelated());
3790  if ((rmd->isRelated() || rmd->isForeign()) && // related function
3791  !md->isAlias() && !rmd->isAlias() &&
3792  matchArguments2( md->getOuterScope(), md->getFileDef(), md->argumentList(),
3793  rmd->getOuterScope(),rmd->getFileDef(),rmd->argumentList(),
3794  TRUE
3795  )
3796  )
3797  {
3798  //printf(" Found related member '%s'\n",md->name().data());
3799  if (rmd->relatedAlso())
3800  md->setRelatedAlso(rmd->relatedAlso());
3801  else if (rmd->isForeign())
3802  md->makeForeign();
3803  else
3804  md->makeRelated();
3805  }
3806  }
3807  }
3808  }
3809  }
3810 }
3811 
3812 //----------------------------------------------------------------------
3813 
3819 static QDict<int> *getTemplateArgumentsInName(const ArgumentList &templateArguments,const QCString &name)
3820 {
3821  QDict<int> *templateNames = new QDict<int>(17);
3822  templateNames->setAutoDelete(TRUE);
3823  static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
3824  int count=0;
3825  for (const Argument &arg : templateArguments)
3826  {
3827  int i,p=0,l;
3828  while ((i=re.match(name,p,&l))!=-1)
3829  {
3830  QCString n = name.mid(i,l);
3831  if (n==arg.name)
3832  {
3833  if (templateNames->find(n)==0)
3834  {
3835  templateNames->insert(n,new int(count));
3836  }
3837  }
3838  p=i+l;
3839  }
3840  }
3841  return templateNames;
3842 }
3843 
3848 {
3849  ClassDef *result=0;
3850  if (cd==0)
3851  {
3852  return result;
3853  }
3854  FileDef *fd=cd->getFileDef();
3855  if (context && cd!=context)
3856  {
3857  result = const_cast<ClassDef*>(getResolvedClass(context,0,name,0,0,TRUE,TRUE));
3858  }
3859  if (result==0)
3860  {
3861  result = const_cast<ClassDef*>(getResolvedClass(cd,fd,name,0,0,TRUE,TRUE));
3862  }
3863  if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
3864  {
3865  result = getClass(name);
3866  }
3867  if (result==0 &&
3869  name.find('<')!=-1)
3870  {
3871  result = Doxygen::genericsDict->find(name);
3872  }
3873  //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
3874  // name.data(),
3875  // context ? context->name().data() : "<none>",
3876  // cd ? cd->name().data() : "<none>",
3877  // result ? result->name().data() : "<none>",
3878  // Doxygen::classSDict->find(name)
3879  // );
3880  return result;
3881 }
3882 
3883 
3884 static void findUsedClassesForClass(const Entry *root,
3885  Definition *context,
3886  ClassDef *masterCd,
3887  ClassDef *instanceCd,
3888  bool isArtificial,
3889  const ArgumentList &actualArgs=ArgumentList(),
3890  QDict<int> *templateNames=0
3891  )
3892 {
3893  masterCd->setVisited(TRUE);
3894  const ArgumentList &formalArgs = masterCd->templateArguments();
3895  if (masterCd->memberNameInfoSDict())
3896  {
3898  MemberNameInfo *mni;
3899  for (;(mni=mnili.current());++mnili)
3900  {
3901  MemberNameInfoIterator mnii(*mni);
3902  MemberInfo *mi;
3903  for (mnii.toFirst();(mi=mnii.current());++mnii)
3904  {
3905  MemberDef *md=mi->memberDef;
3906  if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
3907  {
3908  //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
3909  QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
3910  QCString typedefValue = resolveTypeDef(masterCd,type);
3911  if (!typedefValue.isEmpty())
3912  {
3913  type = typedefValue;
3914  }
3915  int pos=0;
3916  QCString usedClassName;
3917  QCString templSpec;
3918  bool found=FALSE;
3919  // the type can contain template variables, replace them if present
3920  type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
3921 
3922  //printf(" template substitution gives=%s\n",type.data());
3923  while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,root->lang)!=-1)
3924  {
3925  // find the type (if any) that matches usedClassName
3926  const ClassDef *typeCd = getResolvedClass(masterCd,
3927  masterCd->getFileDef(),
3928  usedClassName,
3929  0,0,
3930  FALSE,TRUE
3931  );
3932  //printf("====> usedClassName=%s -> typeCd=%s\n",
3933  // usedClassName.data(),typeCd?typeCd->name().data():"<none>");
3934  if (typeCd)
3935  {
3936  usedClassName = typeCd->name();
3937  }
3938 
3939  int sp=usedClassName.find('<');
3940  if (sp==-1) sp=0;
3941  int si=usedClassName.findRev("::",sp);
3942  if (si!=-1)
3943  {
3944  // replace any namespace aliases
3945  replaceNamespaceAliases(usedClassName,si);
3946  }
3947  // add any template arguments to the class
3948  QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
3949  //printf(" usedName=%s\n",usedName.data());
3950 
3951  bool delTempNames=FALSE;
3952  if (templateNames==0)
3953  {
3954  templateNames = getTemplateArgumentsInName(formalArgs,usedName);
3955  delTempNames=TRUE;
3956  }
3957  BaseInfo bi(usedName,Public,Normal);
3958  findClassRelation(root,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
3959 
3960  for (const Argument &arg : masterCd->templateArguments())
3961  {
3962  if (arg.name==usedName) // type is a template argument
3963  {
3964  found=TRUE;
3965  Debug::print(Debug::Classes,0," New used class '%s'\n", qPrint(usedName));
3966 
3967  ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
3968  if (usedCd==0)
3969  {
3970  usedCd = createClassDef(
3971  masterCd->getDefFileName(),masterCd->getDefLine(),
3972  masterCd->getDefColumn(),
3973  usedName,
3974  ClassDef::Class);
3975  //printf("making %s a template argument!!!\n",usedCd->name().data());
3976  usedCd->makeTemplateArgument();
3977  usedCd->setUsedOnly(TRUE);
3978  usedCd->setLanguage(masterCd->getLanguage());
3979  Doxygen::hiddenClasses->append(usedName,usedCd);
3980  }
3981  if (isArtificial) usedCd->setArtificial(TRUE);
3982  Debug::print(Debug::Classes,0," Adding used class '%s' (1)\n", qPrint(usedCd->name()));
3983  instanceCd->addUsedClass(usedCd,md->name(),md->protection());
3984  usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
3985  }
3986  }
3987 
3988  if (!found)
3989  {
3990  ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
3991  //printf("Looking for used class %s: result=%s master=%s\n",
3992  // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
3993 
3994  if (usedCd)
3995  {
3996  found=TRUE;
3997  Debug::print(Debug::Classes,0," Adding used class '%s' (2)\n", qPrint(usedCd->name()));
3998  instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
3999  usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4000  }
4001  }
4002  if (delTempNames)
4003  {
4004  delete templateNames;
4005  templateNames=0;
4006  }
4007  }
4008  if (!found && !type.isEmpty()) // used class is not documented in any scope
4009  {
4010  ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4011  if (usedCd==0 && !Config_getBool(HIDE_UNDOC_RELATIONS))
4012  {
4013  if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4014  {
4015  type+=md->argsString();
4016  }
4017  Debug::print(Debug::Classes,0," New undocumented used class '%s'\n", qPrint(type));
4018  usedCd = createClassDef(
4019  masterCd->getDefFileName(),masterCd->getDefLine(),
4020  masterCd->getDefColumn(),
4021  type,ClassDef::Class);
4022  usedCd->setUsedOnly(TRUE);
4023  usedCd->setLanguage(masterCd->getLanguage());
4024  Doxygen::hiddenClasses->append(type,usedCd);
4025  }
4026  if (usedCd)
4027  {
4028  if (isArtificial) usedCd->setArtificial(TRUE);
4029  Debug::print(Debug::Classes,0," Adding used class '%s' (3)\n", qPrint(usedCd->name()));
4030  instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4031  usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4032  }
4033  }
4034  }
4035  }
4036  }
4037  }
4038  else
4039  {
4040  //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4041  }
4042 }
4043 
4045  const Entry *root,
4046  Definition *context,
4047  ClassDef *masterCd,
4048  ClassDef *instanceCd,
4050  bool isArtificial,
4051  const ArgumentList &actualArgs=ArgumentList(),
4052  QDict<int> *templateNames=0
4053  )
4054 {
4055  //if (masterCd->visited) return;
4056  masterCd->setVisited(TRUE);
4057  // The base class could ofcouse also be a non-nested class
4058  const ArgumentList &formalArgs = masterCd->templateArguments();
4059  for (const BaseInfo &bi : root->extends)
4060  {
4061  //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4062  // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4063  bool delTempNames=FALSE;
4064  if (templateNames==0)
4065  {
4066  templateNames = getTemplateArgumentsInName(formalArgs,bi.name);
4067  delTempNames=TRUE;
4068  }
4069  BaseInfo tbi = bi;
4070  tbi.name = substituteTemplateArgumentsInString(bi.name,formalArgs,actualArgs);
4071  //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4072 
4073  if (mode==DocumentedOnly)
4074  {
4075  // find a documented base class in the correct scope
4076  if (!findClassRelation(root,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4077  {
4078  // 1.8.2: decided to show inheritance relations even if not documented,
4079  // we do make them artificial, so they do not appear in the index
4080  //if (!Config_getBool(HIDE_UNDOC_RELATIONS))
4081  bool b = Config_getBool(HIDE_UNDOC_RELATIONS) ? TRUE : isArtificial;
4082  //{
4083  // no documented base class -> try to find an undocumented one
4084  findClassRelation(root,context,instanceCd,&tbi,templateNames,Undocumented,b);
4085  //}
4086  }
4087  }
4088  else if (mode==TemplateInstances)
4089  {
4090  findClassRelation(root,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4091  }
4092  if (delTempNames)
4093  {
4094  delete templateNames;
4095  templateNames=0;
4096  }
4097  }
4098 }
4099 
4100 //----------------------------------------------------------------------
4101 
4102 static bool findTemplateInstanceRelation(const Entry *root,
4103  Definition *context,
4104  ClassDef *templateClass,const QCString &templSpec,
4105  QDict<int> *templateNames,
4106  bool isArtificial)
4107 {
4108  Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n",
4109  qPrint(templateClass->name()),qPrint(templSpec));
4110  //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4111  // templateClass->name().data(),templSpec.data());
4112  //if (templateNames)
4113  //{
4114  // QDictIterator<int> qdi(*templateNames);
4115  // int *tempArgIndex;
4116  // for (;(tempArgIndex=qdi.current());++qdi)
4117  // {
4118  // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4119  // }
4120  //}
4121  //printf("\n");
4122 
4123  bool existingClass = (templSpec ==
4124  tempArgListToString(templateClass->templateArguments(),root->lang)
4125  );
4126  if (existingClass) return TRUE;
4127 
4128  bool freshInstance=FALSE;
4129  ClassDef *instanceClass = templateClass->insertTemplateInstance(
4130  root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4131  if (isArtificial) instanceClass->setArtificial(TRUE);
4132  instanceClass->setLanguage(root->lang);
4133 
4134  if (freshInstance)
4135  {
4136  Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",qPrint(instanceClass->name()));
4137  Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4138  instanceClass->setTemplateBaseClassNames(templateNames);
4139 
4140  // search for new template instances caused by base classes of
4141  // instanceClass
4142  auto it = g_classEntries.find(templateClass->name().data());
4143  if (it!=g_classEntries.end())
4144  {
4145  const Entry *templateRoot = it->second;
4146  Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",
4147  qPrint(templateRoot->name),qPrint(templSpec));
4148  ArgumentList templArgs;
4149  stringToArgumentList(root->lang,templSpec,templArgs);
4150  findBaseClassesForClass(templateRoot,context,templateClass,instanceClass,
4151  TemplateInstances,isArtificial,templArgs,templateNames);
4152 
4153  findUsedClassesForClass(templateRoot,context,templateClass,instanceClass,
4154  isArtificial,templArgs,templateNames);
4155  }
4156  else
4157  {
4158  Debug::print(Debug::Classes,0," no template root entry found!\n");
4159  // TODO: what happened if we get here?
4160  }
4161 
4162  //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data());
4163  //ArgumentList *tl = templateClass->templateArguments();
4164  }
4165  else
4166  {
4167  Debug::print(Debug::Classes,0," instance already exists!\n");
4168  }
4169  return TRUE;
4170 }
4171 
4172 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4173 {
4174  QCString n=name;
4175  int index=n.find('<');
4176  if (index!=-1)
4177  {
4178  n=n.left(index);
4179  }
4180  bool result = rightScopeMatch(scope,n);
4181  return result;
4182 }
4183 
4197 static int findEndOfTemplate(const QCString &s,int startPos)
4198 {
4199  // locate end of template
4200  int e=startPos;
4201  int brCount=1;
4202  int roundCount=0;
4203  int len = s.length();
4204  bool insideString=FALSE;
4205  bool insideChar=FALSE;
4206  char pc = 0;
4207  while (e<len && brCount!=0)
4208  {
4209  char c=s.at(e);
4210  switch(c)
4211  {
4212  case '<':
4213  if (!insideString && !insideChar)
4214  {
4215  if (e<len-1 && s.at(e+1)=='<')
4216  e++;
4217  else if (roundCount==0)
4218  brCount++;
4219  }
4220  break;
4221  case '>':
4222  if (!insideString && !insideChar)
4223  {
4224  if (e<len-1 && s.at(e+1)=='>')
4225  e++;
4226  else if (roundCount==0)
4227  brCount--;
4228  }
4229  break;
4230  case '(':
4231  if (!insideString && !insideChar)
4232  roundCount++;
4233  break;
4234  case ')':
4235  if (!insideString && !insideChar)
4236  roundCount--;
4237  break;
4238  case '"':
4239  if (!insideChar)
4240  {
4241  if (insideString && pc!='\\')
4242  insideString=FALSE;
4243  else
4244  insideString=TRUE;
4245  }
4246  break;
4247  case '\'':
4248  if (!insideString)
4249  {
4250  if (insideChar && pc!='\\')
4251  insideChar=FALSE;
4252  else
4253  insideChar=TRUE;
4254  }
4255  break;
4256  }
4257  pc = c;
4258  e++;
4259  }
4260  return brCount==0 ? e : -1;
4261 }
4262 
4263 static bool findClassRelation(
4264  const Entry *root,
4265  Definition *context,
4266  ClassDef *cd,
4267  const BaseInfo *bi,
4268  QDict<int> *templateNames,
4270  bool isArtificial
4271  )
4272 {
4273  //printf("findClassRelation(class=%s base=%s templateNames=",
4274  // cd->name().data(),bi->name.data());
4275  //if (templateNames)
4276  //{
4277  // QDictIterator<int> qdi(*templateNames);
4278  // int *tempArgIndex;
4279  // for (;(tempArgIndex=qdi.current());++qdi)
4280  // {
4281  // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4282  // }
4283  //}
4284  //printf("\n");
4285 
4286  QCString biName=bi->name;
4287  bool explicitGlobalScope=FALSE;
4288  //printf("findClassRelation: biName='%s'\n",biName.data());
4289  if (biName.left(2)=="::") // explicit global scope
4290  {
4291  biName=biName.right(biName.length()-2);
4292  explicitGlobalScope=TRUE;
4293  }
4294 
4295  Entry *parentNode=root->parent();
4296  bool lastParent=FALSE;
4297  do // for each parent scope, starting with the largest scope
4298  // (in case of nested classes)
4299  {
4300  QCString scopeName= parentNode ? parentNode->name.data() : "";
4301  int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4302  do // try all parent scope prefixes, starting with the largest scope
4303  {
4304  //printf("scopePrefix='%s' biName='%s'\n",
4305  // scopeName.left(scopeOffset).data(),biName.data());
4306 
4307  QCString baseClassName=biName;
4308  if (scopeOffset>0)
4309  {
4310  baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4311  }
4312  //QCString stripped;
4313  //baseClassName=stripTemplateSpecifiersFromScope
4314  // (removeRedundantWhiteSpace(baseClassName),TRUE,
4315  // &stripped);
4316  const MemberDef *baseClassTypeDef=0;
4317  QCString templSpec;
4318  ClassDef *baseClass=const_cast<ClassDef*>(
4319  getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4320  cd->getFileDef(),
4321  baseClassName,
4322  &baseClassTypeDef,
4323  &templSpec,
4324  mode==Undocumented,
4325  TRUE
4326  ));
4327  //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4328  // baseClassName.data(),baseClass,cd,explicitGlobalScope);
4329  //printf(" scope='%s' baseClassName='%s' baseClass=%s templSpec=%s\n",
4330  // cd ? cd->name().data():"<none>",
4331  // baseClassName.data(),
4332  // baseClass?baseClass->name().data():"<none>",
4333  // templSpec.data()
4334  // );
4335  //if (baseClassName.left(root->name.length())!=root->name ||
4336  // baseClassName.at(root->name.length())!='<'
4337  // ) // Check for base class with the same name.
4338  // // If found then look in the outer scope for a match
4339  // // and prevent recursion.
4340  if (!isRecursiveBaseClass(root->name,baseClassName)
4341  || explicitGlobalScope
4342  // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4343  // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4344  || (root->lang==SrcLangExt_IDL &&
4347  {
4348  Debug::print(
4349  Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4350  qPrint(baseClassName),
4351  qPrint(root->name),
4352  (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4353  (bi->virt==Normal)?"normal":"virtual",
4354  qPrint(templSpec)
4355  );
4356 
4357  int i=baseClassName.find('<');
4358  int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4359  if (si==-1) si=0;
4360  if (baseClass==0 && (root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java))
4361  {
4362  // for Java/C# strip the template part before looking for matching
4363  baseClass = Doxygen::genericsDict->find(baseClassName.left(i));
4364  //printf("looking for '%s' result=%p\n",baseClassName.data(),baseClass);
4365  }
4366  if (baseClass==0 && i!=-1)
4367  // base class has template specifiers
4368  {
4369  // TODO: here we should try to find the correct template specialization
4370  // but for now, we only look for the unspecialized base class.
4371  int e=findEndOfTemplate(baseClassName,i+1);
4372  //printf("baseClass==0 i=%d e=%d\n",i,e);
4373  if (e!=-1) // end of template was found at e
4374  {
4375  templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4376  baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4377  baseClass=const_cast<ClassDef*>(
4378  getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4379  cd->getFileDef(),
4380  baseClassName,
4381  &baseClassTypeDef,
4382  0, //&templSpec,
4383  mode==Undocumented,
4384  TRUE
4385  ));
4386  //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4387  // baseClass,baseClassName.data(),templSpec.data());
4388  }
4389  }
4390  else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4391  // know it is a template, so see if
4392  // we can also link to the explicit
4393  // instance (for instance if a class
4394  // derived from a template argument)
4395  {
4396  //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4397  ClassDef *templClass=getClass(baseClass->name()+templSpec);
4398  if (templClass)
4399  {
4400  // use the template instance instead of the template base.
4401  baseClass = templClass;
4402  templSpec.resize(0);
4403  }
4404  }
4405 
4406  //printf("cd=%p baseClass=%p\n",cd,baseClass);
4407  bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4408  //printf("1. found=%d\n",found);
4409  if (!found && si!=-1)
4410  {
4411  QCString tmpTemplSpec;
4412  // replace any namespace aliases
4413  replaceNamespaceAliases(baseClassName,si);
4414  baseClass=const_cast<ClassDef*>(
4415  getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4416  cd->getFileDef(),
4417  baseClassName,
4418  &baseClassTypeDef,
4419  &tmpTemplSpec,
4420  mode==Undocumented,
4421  TRUE
4422  ));
4423  found=baseClass!=0 && baseClass!=cd;
4424  if (found) templSpec = tmpTemplSpec;
4425  }
4426  //printf("2. found=%d\n",found);
4427 
4428  //printf("root->name=%s biName=%s baseClassName=%s\n",
4429  // root->name.data(),biName.data(),baseClassName.data());
4430  //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4431  //{
4432  // baseClassName+="-g";
4433  //}
4434 
4435  if (!found)
4436  {
4437  baseClass=findClassWithinClassContext(context,cd,baseClassName);
4438  //printf("findClassWithinClassContext(%s,%s)=%p\n",
4439  // cd->name().data(),baseClassName.data(),baseClass);
4440  found = baseClass!=0 && baseClass!=cd;
4441 
4442  }
4443  if (!found)
4444  {
4445  // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4446  // the class name also in the alias mapping.
4447  QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4448  if (aliasName) // see if it is indeed a class.
4449  {
4450  baseClass=getClass(*aliasName);
4451  found = baseClass!=0 && baseClass!=cd;
4452  }
4453  }
4454  bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4455  // make templSpec canonical
4456  // warning: the following line doesn't work for Mixin classes (see bug 560623)
4457  // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4458 
4459  //printf("3. found=%d\n",found);
4460  if (found)
4461  {
4462  Debug::print(Debug::Classes,0," Documented base class '%s' templSpec=%s\n",qPrint(biName),qPrint(templSpec));
4463  // add base class to this class
4464 
4465  // if templSpec is not empty then we should "instantiate"
4466  // the template baseClass. A new ClassDef should be created
4467  // to represent the instance. To be able to add the (instantiated)
4468  // members and documentation of a template class
4469  // (inserted in that template class at a later stage),
4470  // the template should know about its instances.
4471  // the instantiation process, should be done in a recursive way,
4472  // since instantiating a template may introduce new inheritance
4473  // relations.
4474  if (!templSpec.isEmpty() && mode==TemplateInstances)
4475  {
4476  // if baseClass is actually a typedef then we should not
4477  // instantiate it, since typedefs are in a different namespace
4478  // see bug531637 for an example where this would otherwise hang
4479  // doxygen
4480  if (baseClassTypeDef==0)
4481  {
4482  //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4483  findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4484  }
4485  }
4486  else if (mode==DocumentedOnly || mode==Undocumented)
4487  {
4488  //printf(" => insert base class\n");
4489  QCString usedName;
4490  if (baseClassTypeDef || cd->isCSharp())
4491  {
4492  usedName=biName;
4493  //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4494  }
4495  Protection prot = bi->prot;
4496  if (Config_getBool(SIP_SUPPORT)) prot=Public;
4497  if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4498  {
4499  cd->insertBaseClass(baseClass,usedName,prot,bi->virt,templSpec);
4500  // add this class as super class to the base class
4501  baseClass->insertSubClass(cd,prot,bi->virt,templSpec);
4502  }
4503  else
4504  {
4505  warn(root->fileName,root->startLine,
4506  "Detected potential recursive class relation "
4507  "between class %s and base class %s!",
4508  cd->name().data(),baseClass->name().data()
4509  );
4510  }
4511  }
4512  return TRUE;
4513  }
4514  else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4515  {
4517  " New undocumented base class '%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4518  qPrint(biName),qPrint(baseClassName),qPrint(templSpec),isArtificial
4519  );
4520  baseClass=0;
4521  if (isATemplateArgument)
4522  {
4523  baseClass=Doxygen::hiddenClasses->find(baseClassName);
4524  if (baseClass==0)
4525  {
4526  baseClass=createClassDef(root->fileName,root->startLine,root->startColumn,
4527  baseClassName,
4528  ClassDef::Class);
4529  Doxygen::hiddenClasses->append(baseClassName,baseClass);
4530  if (isArtificial) baseClass->setArtificial(TRUE);
4531  baseClass->setLanguage(root->lang);
4532  }
4533  }
4534  else
4535  {
4536  baseClass=Doxygen::classSDict->find(baseClassName);
4537  //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4538  // baseClassName.data(),baseClass,biName.data(),templSpec.data());
4539  if (baseClass==0)
4540  {
4541  baseClass=createClassDef(root->fileName,root->startLine,root->startColumn,
4542  baseClassName,
4543  ClassDef::Class);
4544  Doxygen::classSDict->append(baseClassName,baseClass);
4545  if (isArtificial) baseClass->setArtificial(TRUE);
4546  baseClass->setLanguage(root->lang);
4547  si = baseClassName.findRev("::");
4548  if (si!=-1) // class is nested
4549  {
4550  Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,root->tagInfo());
4551  if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4552  {
4553  baseClass->setArtificial(TRUE); // see bug678139
4554  }
4555  }
4556  }
4557  }
4558  if (biName.right(2)=="-p")
4559  {
4560  biName="<"+biName.left(biName.length()-2)+">";
4561  }
4562  // add base class to this class
4563  cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4564  // add this class as super class to the base class
4565  baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4566  // the undocumented base was found in this file
4567  baseClass->insertUsedFile(root->fileDef());
4568  baseClass->setOuterScope(Doxygen::globalScope);
4569  if (baseClassName.right(2)=="-p")
4570  {
4571  baseClass->setCompoundType(ClassDef::Protocol);
4572  }
4573  return TRUE;
4574  }
4575  else
4576  {
4577  Debug::print(Debug::Classes,0," Base class '%s' not found\n",qPrint(biName));
4578  }
4579  }
4580  else
4581  {
4582  if (mode!=TemplateInstances)
4583  {
4584  warn(root->fileName,root->startLine,
4585  "Detected potential recursive class relation "
4586  "between class %s and base class %s!\n",
4587  root->name.data(),baseClassName.data()
4588  );
4589  }
4590  // for mode==TemplateInstance this case is quite common and
4591  // indicates a relation between a template class and a template
4592  // instance with the same name.
4593  }
4594  if (scopeOffset==0)
4595  {
4596  scopeOffset=-1;
4597  }
4598  else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4599  {
4600  scopeOffset=0;
4601  }
4602  //printf("new scopeOffset='%d'",scopeOffset);
4603  } while (scopeOffset>=0);
4604 
4605  if (parentNode==0)
4606  {
4607  lastParent=TRUE;
4608  }
4609  else
4610  {
4611  parentNode=parentNode->parent();
4612  }
4613  } while (lastParent);
4614 
4615  return FALSE;
4616 }
4617 
4618 //----------------------------------------------------------------------
4619 // Computes the base and super classes for each class in the tree
4620 
4621 static bool isClassSection(const Entry *root)
4622 {
4623  if ( !root->name.isEmpty() )
4624  {
4625  if (root->section & Entry::COMPOUND_MASK)
4626  // is it a compound (class, struct, union, interface ...)
4627  {
4628  return TRUE;
4629  }
4630  else if (root->section & Entry::COMPOUNDDOC_MASK)
4631  // is it a documentation block with inheritance info.
4632  {
4633  bool hasExtends = !root->extends.empty();
4634  if (hasExtends) return TRUE;
4635  }
4636  }
4637  return FALSE;
4638 }
4639 
4640 
4643 static void findClassEntries(const Entry *root)
4644 {
4645  if (isClassSection(root))
4646  {
4647  g_classEntries.insert({root->name.data(),root});
4648  }
4649  for (const auto &e : root->children()) findClassEntries(e.get());
4650 }
4651 
4652 static QCString extractClassName(const Entry *root)
4653 {
4654  // strip any anonymous scopes first
4656  bName=stripTemplateSpecifiersFromScope(bName);
4657  int i;
4658  if ((root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java) &&
4659  (i=bName.find('<'))!=-1)
4660  {
4661  // a Java/C# generic class looks like a C++ specialization, so we need to strip the
4662  // template part before looking for matches
4663  bName=bName.left(i);
4664  }
4665  return bName;
4666 }
4667 
4674 {
4676  for (cli.toFirst();cli.current();++cli) cli.current()->setVisited(FALSE);
4677  for (const auto &kv : g_classEntries)
4678  {
4679  const Entry *root = kv.second;
4680  ClassDef *cd;
4681  QCString bName = extractClassName(root);
4682  Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",qPrint(bName));
4683  if ((cd=getClass(bName)))
4684  {
4685  //printf("Class %s %d\n",cd->name().data(),root->extends->count());
4687  }
4688  }
4689 }
4690 
4692 {
4694  for (cli.toFirst();cli.current();++cli) cli.current()->setVisited(FALSE);
4695  for (const auto &kv : g_classEntries)
4696  {
4697  const Entry *root = kv.second;
4698  ClassDef *cd;
4699  QCString bName = extractClassName(root);
4700  Debug::print(Debug::Classes,0," Usage: Class %s : \n",qPrint(bName));
4701  if ((cd=getClass(bName)))
4702  {
4703  findUsedClassesForClass(root,cd,cd,cd,TRUE);
4704  cd->addTypeConstraints();
4705  }
4706  }
4707 }
4708 
4710 {
4712  for (cli.toFirst();cli.current();++cli) cli.current()->setVisited(FALSE);
4713  for (const auto &kv : g_classEntries)
4714  {
4715  const Entry *root = kv.second;
4716  ClassDef *cd;
4717 
4718  QCString bName = extractClassName(root);
4719  Debug::print(Debug::Classes,0," Relations: Class %s : \n",qPrint(bName));
4720  if ((cd=getClass(bName)))
4721  {
4723  }
4724  int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
4725  if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
4726  bName.right(2)!="::")
4727  {
4728  if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
4730  Config_getBool(EXTRACT_LOCAL_CLASSES)) && // not defined in source file
4731  protectionLevelVisible(root->protection) && // hidden by protection
4732  !Config_getBool(HIDE_UNDOC_CLASSES) // undocumented class are visible
4733  )
4734  warn_undoc(
4735  root->fileName,root->startLine,
4736  "Compound %s is not documented.",
4737  root->name.data()
4738  );
4739  }
4740  }
4741 }
4742 
4744 {
4745  for (const auto &kv : g_classEntries)
4746  {
4747  const Entry *root = kv.second;
4749  bName=stripTemplateSpecifiersFromScope(bName);
4750  ClassDef *cd=getClass(bName);
4751  // strip any anonymous scopes first
4752  QDict<ClassDef> *templInstances = 0;
4753  if (cd && (templInstances=cd->getTemplateInstances()))
4754  {
4755  Debug::print(Debug::Classes,0," Template class %s : \n",qPrint(cd->name()));
4756  QDictIterator<ClassDef> tdi(*templInstances);
4757  ClassDef *tcd;
4758  for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
4759  {
4760  Debug::print(Debug::Classes,0," Template instance %s : \n",qPrint(tcd->name()));
4761  QCString templSpec = tdi.currentKey();
4762  ArgumentList templArgs;
4763  stringToArgumentList(tcd->getLanguage(),templSpec,templArgs);
4764  for (const BaseInfo &bi : root->extends)
4765  {
4766  // check if the base class is a template argument
4767  BaseInfo tbi = bi;
4768  const ArgumentList &tl = cd->templateArguments();
4769  if (!tl.empty())
4770  {
4771  QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
4772  QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi.name);
4773  // for each template name that we inherit from we need to
4774  // substitute the formal with the actual arguments
4775  QDict<int> *actualTemplateNames = new QDict<int>(17);
4776  actualTemplateNames->setAutoDelete(TRUE);
4777  QDictIterator<int> qdi(*templateNames);
4778  for (qdi.toFirst();qdi.current();++qdi)
4779  {
4780  int templIndex = *qdi.current();
4781  Argument actArg;
4782  bool hasActArg=FALSE;
4783  if (templIndex<(int)templArgs.size())
4784  {
4785  actArg=templArgs.at(templIndex);
4786  hasActArg=TRUE;
4787  }
4788  if (hasActArg &&
4789  baseClassNames!=0 &&
4790  baseClassNames->find(actArg.type)!=0 &&
4791  actualTemplateNames->find(actArg.type)==0
4792  )
4793  {
4794  actualTemplateNames->insert(actArg.type,new int(templIndex));
4795  }
4796  }
4797  delete templateNames;
4798 
4799  tbi.name = substituteTemplateArgumentsInString(bi.name,tl,templArgs);
4800  // find a documented base class in the correct scope
4801  if (!findClassRelation(root,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
4802  {
4803  // no documented base class -> try to find an undocumented one
4804  findClassRelation(root,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
4805  }
4806  delete actualTemplateNames;
4807  }
4808  }
4809  } // class has no base classes
4810  }
4811  }
4812 }
4813 
4814 //-----------------------------------------------------------------------
4815 // compute the references (anchors in HTML) for each function in the file
4816 
4818 {
4820  ClassDef *cd=0;
4821  for (cli.toFirst();(cd=cli.current());++cli)
4822  {
4823  cd->computeAnchors();
4824  }
4825  for (const auto &fn : *Doxygen::inputNameLinkedMap)
4826  {
4827  for (const auto &fd : *fn)
4828  {
4829  fd->computeAnchors();
4830  }
4831  }
4833  NamespaceDef *nd=0;
4834  for (nli.toFirst();(nd=nli.current());++nli)
4835  {
4836  nd->computeAnchors();
4837  }
4839  GroupDef *gd;
4840  for (gli.toFirst();(gd=gli.current());++gli)
4841  {
4842  gd->computeAnchors();
4843  }
4844 }
4845 
4846 //----------------------------------------------------------------------
4847 
4848 static void addListReferences()
4849 {
4851  ClassDef *cd=0;
4852  for (cli.toFirst();(cd=cli.current());++cli)
4853  {
4854  if (!cd->isAlias())
4855  {
4856  cd->addListReferences();
4857  }
4858  }
4859 
4860  for (const auto &fn : *Doxygen::inputNameLinkedMap)
4861  {
4862  for (const auto &fd : *fn)
4863  {
4864  fd->addListReferences();
4865  }
4866  }
4867 
4869  NamespaceDef *nd=0;
4870  for (nli.toFirst();(nd=nli.current());++nli)
4871  {
4872  if (!nd->isAlias())
4873  {
4874  nd->addListReferences();
4875  }
4876  }
4877 
4879  GroupDef *gd;
4880  for (gli.toFirst();(gd=gli.current());++gli)
4881  {
4882  gd->addListReferences();
4883  }
4884 
4886  PageDef *pd=0;
4887  for (pdi.toFirst();(pd=pdi.current());++pdi)
4888  {
4889  QCString name = pd->getOutputFileBase();
4890  if (pd->getGroupDef())
4891  {
4892  name = pd->getGroupDef()->getOutputFileBase();
4893  }
4894  {
4895  const std::vector<RefItem*> &xrefItems = pd->xrefListItems();
4896  addRefItem(xrefItems,
4897  name,
4899  name,pd->title(),0,0);
4900  }
4901  }
4902 
4904  DirDef *dd = 0;
4905  for (ddi.toFirst();(dd=ddi.current());++ddi)
4906  {
4907  QCString name = dd->getOutputFileBase();
4908  //if (dd->getGroupDef())
4909  //{
4910  // name = dd->getGroupDef()->getOutputFileBase();
4911  //}
4912  const std::vector<RefItem*> &xrefItems = dd->xrefListItems();
4913  addRefItem(xrefItems,
4914  name,
4916  name,dd->displayName(),0,0);
4917  }
4918 }
4919 
4920 //----------------------------------------------------------------------
4921 
4922 static void generateXRefPages()
4923 {
4925  {
4926  rl->generatePage();
4927  }
4928 }
4929 
4930 //----------------------------------------------------------------------
4931 // Copy the documentation in entry 'root' to member definition 'md' and
4932 // set the function declaration of the member to 'funcDecl'. If the boolean
4933 // over_load is set the standard overload text is added.
4934 
4935 static void addMemberDocs(const Entry *root,
4936  MemberDef *md, const char *funcDecl,
4937  const ArgumentList *al,
4938  bool over_load,
4939  uint64 spec
4940  )
4941 {
4942  //printf("addMemberDocs: '%s'::'%s' '%s' funcDecl='%s' mSpec=%lld\n",
4943  // root->parent()->name.data(),md->name().data(),md->argsString(),funcDecl,spec);
4944  QCString fDecl=funcDecl;
4945  // strip extern specifier
4946  fDecl.stripPrefix("extern ");
4947  md->setDefinition(fDecl);
4948  md->enableCallGraph(root->callGraph);
4949  md->enableCallerGraph(root->callerGraph);
4952  ClassDef *cd=md->getClassDef();
4953  const NamespaceDef *nd=md->getNamespaceDef();
4954  QCString fullName;
4955  if (cd)
4956  fullName = cd->name();
4957  else if (nd)
4958  fullName = nd->name();
4959 
4960  if (!fullName.isEmpty()) fullName+="::";
4961  fullName+=md->name();
4962  FileDef *rfd=root->fileDef();
4963 
4964  // TODO determine scope based on root not md
4965  Definition *rscope = md->getOuterScope();
4966 
4967  ArgumentList &mdAl = md->argumentList();
4968  if (al)
4969  {
4970  ArgumentList mergedAl = *al;
4971  //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
4972  mergeArguments(mdAl,mergedAl,!root->doc.isEmpty());
4973  }
4974  else
4975  {
4976  if (
4977  matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4978  rscope,rfd,root->argList,
4979  TRUE
4980  )
4981  )
4982  {
4983  //printf("merging arguments (2)\n");
4984  ArgumentList mergedArgList = root->argList;
4985  mergeArguments(mdAl,mergedArgList,!root->doc.isEmpty());
4986  }
4987  }
4988  if (over_load) // the \overload keyword was used
4989  {
4990  QCString doc=getOverloadDocs();
4991  if (!root->doc.isEmpty())
4992  {
4993  doc+="<p>";
4994  doc+=root->doc;
4995  }
4996  md->setDocumentation(doc,root->docFile,root->docLine);
4997  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
4998  md->setDocsForDefinition(!root->proto);
4999  }
5000  else
5001  {
5002  //printf("overwrite!\n");
5003  md->setDocumentation(root->doc,root->docFile,root->docLine);
5004  md->setDocsForDefinition(!root->proto);
5005 
5006  //printf("overwrite!\n");
5007  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5008 
5009  if (
5010  (md->inbodyDocumentation().isEmpty() ||
5011  !root->parent()->name.isEmpty()
5012  ) && !root->inbodyDocs.isEmpty()
5013  )
5014  {
5015  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5016  }
5017  }
5018 
5019  //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5020  // md->initializer().data(),md->initializer().isEmpty(),
5021  // root->initializer.data(),root->initializer.isEmpty()
5022  // );
5023  if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5024  {
5025  //printf("setInitializer\n");
5026  md->setInitializer(root->initializer);
5027  }
5028 
5029  md->setMaxInitLines(root->initLines);
5030 
5031  if (rfd)
5032  {
5033  if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5034  )
5035  {
5036  //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5037  md->setBodySegment(root->startLine,root->bodyLine,root->endBodyLine);
5038  md->setBodyDef(rfd);
5039  }
5040 
5041  md->setRefItems(root->sli);
5042  }
5043 
5044  md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5045  md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5048 
5049  md->mergeMemberSpecifiers(spec);
5050  md->addSectionsToDefinition(root->anchors);
5051  addMemberToGroups(root,md);
5052  if (cd) cd->insertUsedFile(rfd);
5053  //printf("root->mGrpId=%d\n",root->mGrpId);
5054  if (root->mGrpId!=-1)
5055  {
5056  if (md->getMemberGroupId()!=-1)
5057  {
5058  if (md->getMemberGroupId()!=root->mGrpId)
5059  {
5060  warn(
5061  root->fileName,root->startLine,
5062  "member %s belongs to two different groups. The second "
5063  "one found here will be ignored.",
5064  md->name().data()
5065  );
5066  }
5067  }
5068  else // set group id
5069  {
5070  //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5071  md->setMemberGroupId(root->mGrpId);
5072  }
5073  }
5074 }
5075 
5076 //----------------------------------------------------------------------
5077 // find a class definition given the scope name and (optionally) a
5078 // template list specifier
5079 
5081  const char *scopeName)
5082 {
5083  const ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5084  return tcd;
5085 }
5086 
5087 
5088 //----------------------------------------------------------------------
5089 // Adds the documentation contained in 'root' to a global function
5090 // with name 'name' and argument list 'args' (for overloading) and
5091 // function declaration 'decl' to the corresponding member definition.
5092 
5093 static bool findGlobalMember(const Entry *root,
5094  const QCString &namespaceName,
5095  const char *type,
5096  const char *name,
5097  const char *tempArg,
5098  const char *,
5099  const char *decl,
5100  uint64 spec)
5101 {
5103  "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5104  qPrint(namespaceName),qPrint(type),qPrint(name),qPrint(tempArg),qPrint(decl));
5105  QCString n=name;
5106  if (n.isEmpty()) return FALSE;
5107  if (n.find("::")!=-1) return FALSE; // skip undefined class members
5108  MemberName *mn=Doxygen::functionNameLinkedMap->find(n+tempArg); // look in function dictionary
5109  if (mn==0)
5110  {
5111  mn=Doxygen::functionNameLinkedMap->find(n); // try without template arguments
5112  }
5113  if (mn) // function name defined
5114  {
5115  Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5116  //int count=0;
5117  bool found=FALSE;
5118  for (const auto &md : *mn)
5119  {
5120  const NamespaceDef *nd=0;
5121  if (md->isAlias() && md->getOuterScope() &&
5122  md->getOuterScope()->definitionType()==Definition::TypeNamespace)
5123  {
5124  nd = dynamic_cast<const NamespaceDef *>(md->getOuterScope());
5125  }
5126  else
5127  {
5128  nd = md->getNamespaceDef();
5129  }
5130  //const Definition *scope=md->getOuterScope();
5131  //md = md->resolveAlias();
5132 
5133  const FileDef *fd=root->fileDef();
5134  //printf("File %s\n",fd ? fd->name().data() : "<none>");
5135  NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5136  //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0;
5137  //printf("NamespaceList %p\n",nl);
5138 
5139  // search in the list of namespaces that are imported via a
5140  // using declaration
5141  bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5142 
5143  if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
5144  (nd && nd->name()==namespaceName) || // or in the same namespace
5145  viaUsingDirective // member in 'using' namespace
5146  )
5147  {
5148  Debug::print(Debug::FindMembers,0,"4. Try to add member '%s' to scope '%s'\n",
5149  qPrint(md->name()),qPrint(namespaceName));
5150 
5151  NamespaceDef *rnd = 0;
5152  if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5153 
5154  const ArgumentList &mdAl = const_cast<const MemberDef *>(md.get())->argumentList();
5155  bool matching=
5156  (mdAl.empty() && root->argList.empty()) ||
5157  md->isVariable() || md->isTypedef() || /* in case of function pointers */
5158  matchArguments2(md->getOuterScope(),const_cast<const MemberDef *>(md.get())->getFileDef(),mdAl,
5159  rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5160  FALSE);
5161 
5162  // for template members we need to check if the number of
5163  // template arguments is the same, otherwise we are dealing with
5164  // different functions.
5165  if (matching && !root->tArgLists.empty())
5166  {
5167  const ArgumentList &mdTempl = md->templateArguments();
5168  if (root->tArgLists.back().size()!=mdTempl.size())
5169  {
5170  matching=FALSE;
5171  }
5172  }
5173 
5174  //printf("%s<->%s\n",
5175  // argListToString(md->argumentList()).data(),
5176  // argListToString(root->argList).data());
5177 
5178  // for static members we also check if the comment block was found in
5179  // the same file. This is needed because static members with the same
5180  // name can be in different files. Thus it would be wrong to just
5181  // put the comment block at the first syntactically matching member.
5182  if (matching && md->isStatic() &&
5183  md->getDefFileName()!=root->fileName &&
5184  mn->size()>1)
5185  {
5186  matching = FALSE;
5187  }
5188 
5189  // for template member we also need to check the return type
5190  if (!md->templateArguments().empty() && !root->tArgLists.empty())
5191  {
5192  //printf("Comparing return types '%s'<->'%s'\n",
5193  // md->typeString(),type);
5194  if (md->templateArguments().size()!=root->tArgLists.back().size() ||
5195  qstrcmp(md->typeString(),type)!=0)
5196  {
5197  //printf(" ---> no matching\n");
5198  matching = FALSE;
5199  }
5200  }
5201 
5202  if (matching) // add docs to the member
5203  {
5204  Debug::print(Debug::FindMembers,0,"5. Match found\n");
5205  addMemberDocs(root,md->resolveAlias(),decl,&root->argList,FALSE,root->spec);
5206  found=TRUE;
5207  break;
5208  }
5209  }
5210  }
5211  if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5212  {
5213  QCString fullFuncDecl=decl;
5214  if (!root->argList.empty()) fullFuncDecl+=argListToString(root->argList,TRUE);
5215  QCString warnMsg =
5216  QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5217  if (mn->size()>0)
5218  {
5219  warnMsg+="\nPossible candidates:\n";
5220  for (const auto &md : *mn)
5221  {
5222  warnMsg+=" '";
5223  warnMsg+=substitute(md->declaration(),"%","%%");
5224  warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5225  " of file "+md->getDefFileName()+"\n";
5226  }
5227  }
5228  warn(root->fileName,root->startLine, "%s", warnMsg.data());
5229  }
5230  }
5231  else // got docs for an undefined member!
5232  {
5233  if (root->type!="friend class" &&
5234  root->type!="friend struct" &&
5235  root->type!="friend union" &&
5236  root->type!="friend" &&
5237  (!Config_getBool(TYPEDEF_HIDES_STRUCT) ||
5238  root->type.find("typedef ")==-1)
5239  )
5240  {
5241  warn(root->fileName,root->startLine,
5242  "documented symbol '%s' was not declared or defined.",decl
5243  );
5244  }
5245  }
5246  return TRUE;
5247 }
5248 
5249 static bool isSpecialization(
5250  const std::vector<ArgumentList> &srcTempArgLists,
5251  const std::vector<ArgumentList> &dstTempArgLists
5252  )
5253 {
5254  auto srcIt = srcTempArgLists.begin();
5255  auto dstIt = dstTempArgLists.begin();
5256  while (srcIt!=srcTempArgLists.end() && dstIt!=dstTempArgLists.end())
5257  {
5258  if ((*srcIt).size()!=(*dstIt).size()) return TRUE;
5259  ++srcIt;
5260  ++dstIt;
5261  }
5262  return FALSE;
5263 }
5264 
5265 static bool scopeIsTemplate(const Definition *d)
5266 {
5267  bool result=FALSE;
5268  if (d && d->definitionType()==Definition::TypeClass)
5269  {
5270  result = !(dynamic_cast<const ClassDef*>(d))->templateArguments().empty() ||
5272  }
5273  return result;
5274 }
5275 
5277  const std::vector<ArgumentList> &srcTempArgLists,
5278  const std::vector<ArgumentList> &dstTempArgLists,
5279  const QCString &src
5280  )
5281 {
5282  QCString dst;
5283  QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5284  //printf("type=%s\n",sa->type.data());
5285  int i,p=0,l;
5286  while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5287  {
5288  bool found=FALSE;
5289  dst+=src.mid(p,i-p);
5290  QCString name=src.mid(i,l);
5291 
5292  auto srcIt = srcTempArgLists.begin();
5293  auto dstIt = dstTempArgLists.begin();
5294  while (srcIt!=srcTempArgLists.end() && !found)
5295  {
5296  const ArgumentList *tdAli = 0;
5297  std::vector<Argument>::const_iterator tdaIt;
5298  if (dstIt!=dstTempArgLists.end())
5299  {
5300  tdAli = &(*dstIt);
5301  tdaIt = tdAli->begin();
5302  ++dstIt;
5303  }
5304 
5305  const ArgumentList &tsaLi = *srcIt;
5306  for (auto tsaIt = tsaLi.begin(); tsaIt!=tsaLi.end() && !found; ++tsaIt)
5307  {
5308  Argument tsa = *tsaIt;
5309  const Argument *tda = 0;
5310  if (tdAli && tdaIt!=tdAli->end())
5311  {
5312  tda = &(*tdaIt);
5313  ++tdaIt;
5314  }
5315  //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5316  // tsa.type.data(),tsa.name.data(),
5317  // tda->type.data(),tda->name.data());
5318  if (name==tsa.name)
5319  {
5320  if (tda && tda->name.isEmpty())
5321  {
5322  QCString tdaName = tda->name;
5323  QCString tdaType = tda->type;
5324  int vc=0;
5325  if (tdaType.left(6)=="class ") vc=6;
5326  else if (tdaType.left(9)=="typename ") vc=9;
5327  if (vc>0) // convert type=="class T" to type=="class" name=="T"
5328  {
5329  tdaName = tdaType.mid(vc);
5330  }
5331  if (!tdaName.isEmpty())
5332  {
5333  name=tdaName; // substitute
5334  found=TRUE;
5335  }
5336  }
5337  }
5338  }
5339 
5340  //printf(" srcList='%s' dstList='%s faList='%s'\n",
5341  // argListToString(srclali.current()).data(),
5342  // argListToString(dstlali.current()).data(),
5343  // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5344  ++srcIt;
5345  }
5346  dst+=name;
5347  p=i+l;
5348  }
5349  dst+=src.right(src.length()-p);
5350  //printf(" substituteTemplatesInString(%s)=%s\n",
5351  // src.data(),dst.data());
5352  return dst;
5353 }
5354 
5356  const std::vector<ArgumentList> &srcTempArgLists,
5357  const std::vector<ArgumentList> &dstTempArgLists,
5358  const ArgumentList &src,
5359  ArgumentList &dst
5360  )
5361 {
5362  auto dstIt = dst.begin();
5363  for (const Argument &sa : src)
5364  {
5365  QCString dstType = substituteTemplatesInString(srcTempArgLists,dstTempArgLists,sa.type);
5366  QCString dstArray = substituteTemplatesInString(srcTempArgLists,dstTempArgLists,sa.array);
5367  if (dstIt == dst.end())
5368  {
5369  Argument da = sa;
5370  da.type = dstType;
5371  da.array = dstArray;
5372  dst.push_back(da);
5373  dstIt = dst.end();
5374  }
5375  else
5376  {
5377  Argument da = *dstIt;
5378  da.type = dstType;
5379  da.array = dstArray;
5380  ++dstIt;
5381  }
5382  }
5383  dst.constSpecifier = src.constSpecifier;
5384  dst.volatileSpecifier = src.volatileSpecifier;
5385  dst.pureSpecifier = src.pureSpecifier;
5387  srcTempArgLists,dstTempArgLists,
5388  src.trailingReturnType);
5389  //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5390  // argListToString(src).data(),argListToString(dst).data()
5391  // );
5392 }
5393 
5394 //-------------------------------------------------------------------------------------------
5395 
5396 static void addLocalObjCMethod(const Entry *root,
5397  const QCString &scopeName,
5398  const QCString &funcType,const QCString &funcName,const QCString &funcArgs,
5399  const QCString &exceptions,const QCString &funcDecl,
5400  uint64 spec)
5401 {
5402  //printf("scopeName='%s' className='%s'\n",scopeName.data(),className.data());
5403  ClassDef *cd=0;
5404  if (