My Project
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
doxygen.cpp
Go to the documentation of this file.
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2015 by Dimitri van Heesch.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation under the terms of the GNU General Public License is hereby
7  * granted. No representations are made about the suitability of this software
8  * for any purpose. It is provided "as is" without express or implied warranty.
9  * See the GNU General Public License for more details.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15 
16 #include <locale.h>
17 
18 #include <qfileinfo.h>
19 #include <qfile.h>
20 #include <qdir.h>
21 #include <qdict.h>
22 #include <qregexp.h>
23 #include <qstrlist.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/stat.h>
27 #include <qtextcodec.h>
28 #include <errno.h>
29 #include <qptrdict.h>
30 #include <qtextstream.h>
31 
32 #include "version.h"
33 #include "doxygen.h"
34 #include "scanner.h"
35 #include "entry.h"
36 #include "index.h"
37 #include "logos.h"
38 #include "message.h"
39 #include "config.h"
40 #include "util.h"
41 #include "pre.h"
42 #include "tagreader.h"
43 #include "dot.h"
44 #include "msc.h"
45 #include "docparser.h"
46 #include "dirdef.h"
47 #include "outputlist.h"
48 #include "declinfo.h"
49 #include "htmlgen.h"
50 #include "latexgen.h"
51 #include "mangen.h"
52 #include "language.h"
53 #include "debug.h"
54 #include "htmlhelp.h"
55 #include "qhp.h"
56 #include "ftvhelp.h"
57 #include "defargs.h"
58 #include "rtfgen.h"
59 #include "sqlite3gen.h"
60 #include "xmlgen.h"
61 #include "docbookgen.h"
62 #include "defgen.h"
63 #include "perlmodgen.h"
64 #include "reflist.h"
65 #include "pagedef.h"
66 #include "bufstr.h"
67 #include "commentcnv.h"
68 #include "cmdmapper.h"
69 #include "searchindex.h"
70 #include "parserintf.h"
71 #include "htags.h"
72 #include "pyscanner.h"
73 #include "fortranscanner.h"
74 #include "xmlscanner.h"
75 #include "tclscanner.h"
76 #include "code.h"
77 #include "objcache.h"
78 #include "store.h"
79 #include "marshal.h"
80 #include "portable.h"
81 #include "vhdljjparser.h"
82 #include "vhdldocgen.h"
83 #include "eclipsehelp.h"
84 #include "cite.h"
85 #include "filestorage.h"
86 #include "markdown.h"
87 #include "arguments.h"
88 #include "memberlist.h"
89 #include "layout.h"
90 #include "groupdef.h"
91 #include "classlist.h"
92 #include "namespacedef.h"
93 #include "filename.h"
94 #include "membername.h"
95 #include "membergroup.h"
96 #include "docsets.h"
97 #include "formula.h"
98 #include "settings.h"
99 #include "context.h"
100 #include "fileparser.h"
101 
102 // provided by the generated file resources.cpp
103 extern void initResources();
104 
105 #define RECURSE_ENTRYTREE(func,var) \
106  do { if (var->children()) { \
107  EntryNavListIterator eli(*var->children()); \
108  for (;eli.current();++eli) func(eli.current()); \
109  } } while(0)
110 
111 
112 #if !defined(_WIN32) || defined(__CYGWIN__)
113 #include <signal.h>
114 #define HAS_SIGNALS
115 #endif
116 
117 // globally accessible variables
123 FileNameList *Doxygen::inputNameList = 0; // all input files
126 FormulaList *Doxygen::formulaList = 0; // all formulas
127 FormulaDict *Doxygen::formulaDict = 0; // all formulas
128 FormulaDict *Doxygen::formulaNameDict = 0; // the label name of all formulas
131 SectionDict *Doxygen::sectionDict = 0; // all page sections
132 CiteDict *Doxygen::citeDict=0; // database of bibliographic references
133 StringDict Doxygen::aliasDict(257); // aliases
134 QDict<void> Doxygen::inputPaths(1009);
135 FileNameDict *Doxygen::includeNameDict = 0; // include names
136 FileNameDict *Doxygen::exampleNameDict = 0; // examples
137 FileNameDict *Doxygen::imageNameDict = 0; // images
138 FileNameDict *Doxygen::dotFileNameDict = 0; // dot files
139 FileNameDict *Doxygen::mscFileNameDict = 0; // msc files
140 FileNameDict *Doxygen::diaFileNameDict = 0; // dia files
141 StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases
142 StringDict Doxygen::tagDestinationDict(257); // all tag locations
143 QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
144 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
146 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
148 QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
149 bool Doxygen::parseSourcesNeeded = FALSE;
152 QDict<DefinitionIntf> *Doxygen::symbolMap = 0;
153 QDict<Definition> *Doxygen::clangUsrMap = 0;
154 bool Doxygen::outputToWizard=FALSE;
155 QDict<int> * Doxygen::htmlDirMap = 0;
156 QCache<LookupInfo> *Doxygen::lookupCache;
161 bool Doxygen::suppressDocWarnings = FALSE;
163 QCString Doxygen::objDBFileName;
164 QCString Doxygen::entryDBFileName;
165 bool Doxygen::gatherDefines = TRUE;
168 bool Doxygen::userComments = FALSE;
169 QCString Doxygen::spaces;
170 bool Doxygen::generatingXmlOutput = FALSE;
171 bool Doxygen::markdownSupport = TRUE;
173 
174 // locally accessible globals
175 static QDict<EntryNav> g_classEntries(1009);
177 static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds
178 static OutputList *g_outputList = 0; // list of output generating objects
179 static QDict<FileDef> g_usingDeclarations(1009); // used classes
180 static FileStorage *g_storage = 0;
181 static bool g_successfulRun = FALSE;
182 static bool g_dumpSymbolMap = FALSE;
183 static bool g_useOutputTemplate = FALSE;
184 
185 void clearAll()
186 {
187  g_inputFiles.clear();
188  //g_excludeNameDict.clear();
189  //delete g_outputList; g_outputList=0;
190 
191  Doxygen::classSDict->clear();
192  Doxygen::namespaceSDict->clear();
193  Doxygen::pageSDict->clear();
194  Doxygen::exampleSDict->clear();
195  Doxygen::inputNameList->clear();
196  Doxygen::formulaList->clear();
197  Doxygen::sectionDict->clear();
198  Doxygen::inputNameDict->clear();
199  Doxygen::includeNameDict->clear();
200  Doxygen::exampleNameDict->clear();
201  Doxygen::imageNameDict->clear();
202  Doxygen::dotFileNameDict->clear();
203  Doxygen::mscFileNameDict->clear();
204  Doxygen::diaFileNameDict->clear();
205  Doxygen::formulaDict->clear();
206  Doxygen::formulaNameDict->clear();
208  delete Doxygen::citeDict;
209  delete Doxygen::mainPage; Doxygen::mainPage=0;
210 }
211 
213 {
214  public:
215  Statistics() { stats.setAutoDelete(TRUE); }
216  void begin(const char *name)
217  {
218  msg(name);
219  stat *entry= new stat(name,0);
220  stats.append(entry);
221  time.restart();
222  }
223  void end()
224  {
225  stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
226  }
227  void print()
228  {
229  bool restore=FALSE;
231  {
232  Debug::clearFlag("time");
233  restore=TRUE;
234  }
235  msg("----------------------\n");
236  QListIterator<stat> sli(stats);
237  stat *s;
238  for ( sli.toFirst(); (s=sli.current()); ++sli )
239  {
240  msg("Spent %.3f seconds in %s",s->elapsed,s->name);
241  }
242  if (restore) Debug::setFlag("time");
243  }
244  private:
245  struct stat
246  {
247  const char *name;
248  double elapsed;
249  stat() : name(NULL),elapsed(0) {}
250  stat(const char *n, double el) : name(n),elapsed(el) {}
251  };
252  QList<stat> stats;
253  QTime time;
254 } g_s;
255 
256 
258 {
259  fprintf(stderr,"--- inputNameDict stats ----\n");
260  Doxygen::inputNameDict->statistics();
261  fprintf(stderr,"--- includeNameDict stats ----\n");
262  Doxygen::includeNameDict->statistics();
263  fprintf(stderr,"--- exampleNameDict stats ----\n");
264  Doxygen::exampleNameDict->statistics();
265  fprintf(stderr,"--- imageNameDict stats ----\n");
266  Doxygen::imageNameDict->statistics();
267  fprintf(stderr,"--- dotFileNameDict stats ----\n");
268  Doxygen::dotFileNameDict->statistics();
269  fprintf(stderr,"--- mscFileNameDict stats ----\n");
270  Doxygen::mscFileNameDict->statistics();
271  fprintf(stderr,"--- diaFileNameDict stats ----\n");
272  Doxygen::diaFileNameDict->statistics();
273  //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
274  //g_excludeNameDict.statistics();
275  fprintf(stderr,"--- aliasDict stats ----\n");
276  Doxygen::aliasDict.statistics();
277  fprintf(stderr,"--- typedefDict stats ----\n");
278  fprintf(stderr,"--- namespaceAliasDict stats ----\n");
279  Doxygen::namespaceAliasDict.statistics();
280  fprintf(stderr,"--- formulaDict stats ----\n");
281  Doxygen::formulaDict->statistics();
282  fprintf(stderr,"--- formulaNameDict stats ----\n");
283  Doxygen::formulaNameDict->statistics();
284  fprintf(stderr,"--- tagDestinationDict stats ----\n");
285  Doxygen::tagDestinationDict.statistics();
286  fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
287  g_compoundKeywordDict.statistics();
288  fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
289  Doxygen::expandAsDefinedDict.statistics();
290  fprintf(stderr,"--- memGrpInfoDict stats ----\n");
291  Doxygen::memGrpInfoDict.statistics();
292 }
293 
294 
295 
296 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
297  ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
298 static void findMember(EntryNav *rootNav,
299  QCString funcDecl,
300  bool overloaded,
301  bool isFunc
302  );
303 
305 {
309 };
310 
311 static bool findClassRelation(
312  EntryNav *rootNav,
313  Definition *context,
314  ClassDef *cd,
315  BaseInfo *bi,
316  QDict<int> *templateNames,
317  /*bool insertUndocumented*/
319  bool isArtificial
320  );
321 
323 struct STLInfo
324 {
325  const char *className;
326  const char *baseClass1;
327  const char *baseClass2;
328  const char *templType1;
329  const char *templName1;
330  const char *templType2;
331  const char *templName2;
333  bool iterators;
334 };
335 
336 static STLInfo g_stlinfo[] =
337 {
338  // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators
339  { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
340  { "array", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, // C++11
341  { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // deprecated
342  { "smart_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
343  { "unique_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
344  { "weak_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
345  { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
346  { "error_code", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
347  { "error_category", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
348  { "system_error", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
349  { "error_condition", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
350  { "thread", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
351  { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE },
352  { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
353  { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
354  { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE },
355  { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
356  { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
357  { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
358  { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
359  { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
360  { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
361  { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
362  { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
363  { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
364  { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
365  { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
366  { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
367  { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
368  { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
369  { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
370  { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
371  { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
372  { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
373  { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
374  { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
375  { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
376  { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
377  { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
378  { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
379  { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE },
380  { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE },
381  { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE },
382  { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
383  { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE },
384  { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
385  { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
386  { "forward_list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, // C++11
387  { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
388  { "unordered_map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
389  { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
390  { "unordered_multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
391  { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
392  { "unordered_set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
393  { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
394  { "unordered_multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
395  { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
396  { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
397  { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
398  { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
399  { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
400  { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
401  { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
402  { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
403  { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
404  { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
405  { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
406  { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
407  { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
408  { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
409  { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
410  { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
411  { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
412  { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
413  { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
414  { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
415  { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE }
416 };
417 
418 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
419 {
420  Entry *memEntry = new Entry;
421  memEntry->name = name;
422  memEntry->type = type;
423  memEntry->protection = Public;
424  memEntry->section = Entry::VARIABLE_SEC;
425  memEntry->brief = "STL member";
426  memEntry->hidden = FALSE;
427  memEntry->artificial = TRUE;
428  //memEntry->parent = root;
429  //root->addSubEntry(memEntry);
430  EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
431  memEntryNav->setEntry(memEntry);
432  rootNav->addChild(memEntryNav);
433 }
434 
435 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
436 {
437  Entry *iteratorClassEntry = new Entry;
438  iteratorClassEntry->fileName = "[STL]";
439  iteratorClassEntry->startLine = 1;
440  iteratorClassEntry->name = name;
441  iteratorClassEntry->section = Entry::CLASS_SEC;
442  iteratorClassEntry->brief = "STL iterator class";
443  iteratorClassEntry->hidden = FALSE;
444  iteratorClassEntry->artificial= TRUE;
445  EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
446  iteratorClassEntryNav->setEntry(iteratorClassEntry);
447  classEntryNav->addChild(iteratorClassEntryNav);
448 }
449 
450 
451 static void addSTLClasses(EntryNav *rootNav)
452 {
453  Entry *namespaceEntry = new Entry;
454  namespaceEntry->fileName = "[STL]";
455  namespaceEntry->startLine = 1;
456  //namespaceEntry->parent = rootNav->entry();
457  namespaceEntry->name = "std";
458  namespaceEntry->section = Entry::NAMESPACE_SEC;
459  namespaceEntry->brief = "STL namespace";
460  namespaceEntry->hidden = FALSE;
461  namespaceEntry->artificial= TRUE;
462  //root->addSubEntry(namespaceEntry);
463  EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
464  namespaceEntryNav->setEntry(namespaceEntry);
465  rootNav->addChild(namespaceEntryNav);
466 
467  STLInfo *info = g_stlinfo;
468  while (info->className)
469  {
470  //printf("Adding STL class %s\n",info->className);
471  QCString fullName = info->className;
472  fullName.prepend("std::");
473 
474  // add fake Entry for the class
475  Entry *classEntry = new Entry;
476  classEntry->fileName = "[STL]";
477  classEntry->startLine = 1;
478  classEntry->name = fullName;
479  //classEntry->parent = namespaceEntry;
480  classEntry->section = Entry::CLASS_SEC;
481  classEntry->brief = "STL class";
482  classEntry->hidden = FALSE;
483  classEntry->artificial= TRUE;
484  //namespaceEntry->addSubEntry(classEntry);
485  EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
486  classEntryNav->setEntry(classEntry);
487  namespaceEntryNav->addChild(classEntryNav);
488 
489  // add template arguments to class
490  if (info->templType1)
491  {
492  ArgumentList *al = new ArgumentList;
493  Argument *a=new Argument;
494  a->type="typename";
495  a->name=info->templType1;
496  al->append(a);
497  if (info->templType2) // another template argument
498  {
499  a=new Argument;
500  a->type="typename";
501  a->name=info->templType2;
502  al->append(a);
503  }
504  classEntry->tArgLists = new QList<ArgumentList>;
505  classEntry->tArgLists->setAutoDelete(TRUE);
506  classEntry->tArgLists->append(al);
507  }
508  // add member variables
509  if (info->templName1)
510  {
511  addSTLMember(classEntryNav,info->templType1,info->templName1);
512  }
513  if (info->templName2)
514  {
515  addSTLMember(classEntryNav,info->templType2,info->templName2);
516  }
517  if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
518  fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
519  {
520  Entry *memEntry = new Entry;
521  memEntry->name = "operator->";
522  memEntry->args = "()";
523  memEntry->type = "T*";
524  memEntry->protection = Public;
525  memEntry->section = Entry::FUNCTION_SEC;
526  memEntry->brief = "STL member";
527  memEntry->hidden = FALSE;
528  memEntry->artificial = FALSE;
529  EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
530  memEntryNav->setEntry(memEntry);
531  classEntryNav->addChild(memEntryNav);
532  }
533  if (info->baseClass1)
534  {
535  classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
536  }
537  if (info->baseClass2)
538  {
539  classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
540  }
541  if (info->iterators)
542  {
543  // add iterator class
544  addSTLIterator(classEntryNav,fullName+"::iterator");
545  addSTLIterator(classEntryNav,fullName+"::const_iterator");
546  addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
547  addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
548  }
549  info++;
550  }
551 }
552 
553 //----------------------------------------------------------------------------
554 
555 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
556  FileDef *fileScope,TagInfo *tagInfo);
557 
558 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
559 {
560  if (rootNav->parent()) // add the page to it's scope
561  {
562  QCString scope = rootNav->parent()->name();
563  if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
564  {
565  scope=substitute(scope,".","::");
566  }
567  scope = stripAnonymousNamespaceScope(scope);
568  scope+="::"+pd->name();
569  Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
570  if (d)
571  {
572  pd->setPageScope(d);
573  }
574  }
575 }
576 
577 static void addRelatedPage(EntryNav *rootNav)
578 {
579  Entry *root = rootNav->entry();
580  GroupDef *gd=0;
581  QListIterator<Grouping> gli(*root->groups);
582  Grouping *g;
583  for (;(g=gli.current());++gli)
584  {
585  if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
586  }
587  //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
588  QCString doc;
589  if (root->brief.isEmpty())
590  {
591  doc=root->doc+root->inbodyDocs;
592  }
593  else
594  {
595  doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
596  }
597  PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
598  root->docFile,root->docLine,
599  root->sli,
600  gd,rootNav->tagInfo(),
601  root->lang
602  );
603  if (pd)
604  {
605  pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
606  pd->addSectionsToDefinition(root->anchors);
607  pd->setShowToc(root->stat);
608  addPageToContext(pd,rootNav);
609  }
610 }
611 
612 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
613 {
614  if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
615  ((!includeExternal && rootNav->tagInfo()==0) ||
616  ( includeExternal && rootNav->tagInfo()!=0))
617  )
618  {
619  rootNav->loadEntry(g_storage);
620  Entry *root = rootNav->entry();
621 
622  if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
623  (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
624  {
625  GroupDef *gd = Doxygen::groupSDict->find(root->name);
626  //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
627  // root->type.data(),root->name.data(),additional,includeExternal,gd);
628 
629  if (gd)
630  {
631  if ( !gd->hasGroupTitle() )
632  {
633  gd->setGroupTitle( root->type );
634  }
635  else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
636  {
637  warn( root->fileName,root->startLine,
638  "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
639  qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
640  }
641  gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
642  gd->setDocumentation( root->doc, root->docFile, root->docLine );
643  gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
644  gd->addSectionsToDefinition(root->anchors);
645  gd->setRefItems(root->sli);
646  gd->setLanguage(root->lang);
647  }
648  else
649  {
650  if (rootNav->tagInfo())
651  {
652  gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
653  gd->setReference(rootNav->tagInfo()->tagName);
654  }
655  else
656  {
657  gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
658  }
659  gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
660  // allow empty docs for group
661  gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
662  gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
663  gd->addSectionsToDefinition(root->anchors);
664  Doxygen::groupSDict->append(root->name,gd);
665  gd->setRefItems(root->sli);
666  gd->setLanguage(root->lang);
667  }
668  }
669 
670  rootNav->releaseEntry();
671  }
672  if (rootNav->children())
673  {
674  EntryNavListIterator eli(*rootNav->children());
675  EntryNav *e;
676  for (;(e=eli.current());++eli)
677  {
678  buildGroupListFiltered(e,additional,includeExternal);
679  }
680  }
681 }
682 
683 static void buildGroupList(EntryNav *rootNav)
684 {
685  // --- first process only local groups
686  // first process the @defgroups blocks
687  buildGroupListFiltered(rootNav,FALSE,FALSE);
688  // then process the @addtogroup, @weakgroup blocks
689  buildGroupListFiltered(rootNav,TRUE,FALSE);
690 
691  // --- then also process external groups
692  // first process the @defgroups blocks
693  buildGroupListFiltered(rootNav,FALSE,TRUE);
694  // then process the @addtogroup, @weakgroup blocks
695  buildGroupListFiltered(rootNav,TRUE,TRUE);
696 }
697 
698 static void findGroupScope(EntryNav *rootNav)
699 {
700  if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
701  rootNav->parent() && !rootNav->parent()->name().isEmpty())
702  {
703  GroupDef *gd;
704  if ((gd=Doxygen::groupSDict->find(rootNav->name())))
705  {
706  QCString scope = rootNav->parent()->name();
707  if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
708  {
709  scope=substitute(scope,".","::");
710  }
711  scope = stripAnonymousNamespaceScope(scope);
712  scope+="::"+gd->name();
713  Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
714  if (d)
715  {
716  gd->setGroupScope(d);
717  }
718  }
719  }
721 }
722 
723 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
724 {
725  if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
726  {
727  rootNav->loadEntry(g_storage);
728  Entry *root = rootNav->entry();
729 
730  if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
731  (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
732  {
733  GroupDef *gd;
734  if ((gd=Doxygen::groupSDict->find(root->name)))
735  {
736  //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
737  addGroupToGroups(root,gd);
738  }
739  }
740 
741  rootNav->releaseEntry();
742  }
743  if (rootNav->children())
744  {
745  EntryNavListIterator eli(*rootNav->children());
746  EntryNav *e;
747  for (;(e=eli.current());++eli)
748  {
749  organizeSubGroupsFiltered(e,additional);
750  }
751  }
752 }
753 
754 static void organizeSubGroups(EntryNav *rootNav)
755 {
756  //printf("Defining groups\n");
757  // first process the @defgroups blocks
758  organizeSubGroupsFiltered(rootNav,FALSE);
759  //printf("Additional groups\n");
760  // then process the @addtogroup, @weakgroup blocks
761  organizeSubGroupsFiltered(rootNav,TRUE);
762 }
763 
764 //----------------------------------------------------------------------
765 
766 static void buildFileList(EntryNav *rootNav)
767 {
768  if (((rootNav->section()==Entry::FILEDOC_SEC) ||
769  ((rootNav->section() & Entry::FILE_MASK) && Config_getBool(EXTRACT_ALL))) &&
770  !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
771  )
772  {
773  rootNav->loadEntry(g_storage);
774  Entry *root = rootNav->entry();
775 
776  bool ambig;
777  FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
778  //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
779  if (fd && !ambig)
780  {
781 #if 0
782  if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
783  (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
784  {
785  warn(
786  root->fileName,root->startLine,
787  "file %s already documented. "
788  "Skipping documentation.",
789  root->name.data()
790  );
791  }
792  else
793 #endif
794  {
795  //printf("Adding documentation!\n");
796  // using FALSE in setDocumentation is small hack to make sure a file
797  // is documented even if a \file command is used without further
798  // documentation
799  fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
800  fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
801  fd->addSectionsToDefinition(root->anchors);
802  fd->setRefItems(root->sli);
803  QListIterator<Grouping> gli(*root->groups);
804  Grouping *g;
805  for (;(g=gli.current());++gli)
806  {
807  GroupDef *gd=0;
808  if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
809  {
810  gd->addFile(fd);
811  fd->makePartOfGroup(gd);
812  //printf("File %s: in group %s\n",fd->name().data(),s->data());
813  }
814  }
815  }
816  }
817  else
818  {
819  const char *fn = root->fileName.data();
820  QCString text(4096);
821  text.sprintf("the name `%s' supplied as "
822  "the second argument in the \\file statement ",
823  qPrint(root->name));
824  if (ambig) // name is ambiguous
825  {
826  text+="matches the following input files:\n";
827  text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
828  text+="Please use a more specific name by "
829  "including a (larger) part of the path!";
830  }
831  else // name is not an input file
832  {
833  text+="is not an input file";
834  }
835  warn(fn,root->startLine,text);
836  }
837 
838  rootNav->releaseEntry();
839  }
841 }
842 
843 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
844 {
845  if (
846  (!root->doc.stripWhiteSpace().isEmpty() ||
847  !root->brief.stripWhiteSpace().isEmpty() ||
848  Config_getBool(EXTRACT_ALL)
849  ) && root->protection!=Private
850  )
851  {
852  //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
853 
854  bool local=Config_getBool(FORCE_LOCAL_INCLUDES);
855  QCString includeFile = root->includeFile;
856  if (!includeFile.isEmpty() && includeFile.at(0)=='"')
857  {
858  local = TRUE;
859  includeFile=includeFile.mid(1,includeFile.length()-2);
860  }
861  else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
862  {
863  local = FALSE;
864  includeFile=includeFile.mid(1,includeFile.length()-2);
865  }
866 
867  bool ambig;
868  FileDef *fd=0;
869  // see if we need to include a verbatim copy of the header file
870  //printf("root->includeFile=%s\n",root->includeFile.data());
871  if (!includeFile.isEmpty() &&
872  (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
873  )
874  { // explicit request
875  QCString text;
876  text.sprintf("the name `%s' supplied as "
877  "the argument of the \\class, \\struct, \\union, or \\include command ",
878  qPrint(includeFile)
879  );
880  if (ambig) // name is ambiguous
881  {
882  text+="matches the following input files:\n";
883  text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
884  text+="Please use a more specific name by "
885  "including a (larger) part of the path!";
886  }
887  else // name is not an input file
888  {
889  text+="is not an input file";
890  }
891  warn(root->fileName,root->startLine,text);
892  }
893  else if (includeFile.isEmpty() && ifd &&
894  // see if the file extension makes sense
896  { // implicit assumption
897  fd=ifd;
898  }
899 
900  // if a file is found, we mark it as a source file.
901  if (fd)
902  {
903  QCString iName = !root->includeName.isEmpty() ?
904  root->includeName : includeFile;
905  if (!iName.isEmpty()) // user specified include file
906  {
907  if (iName.at(0)=='<') local=FALSE; // explicit override
908  else if (iName.at(0)=='"') local=TRUE;
909  if (iName.at(0)=='"' || iName.at(0)=='<')
910  {
911  iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
912  }
913  if (iName.isEmpty())
914  {
915  iName=fd->name();
916  }
917  }
918  else if (!Config_getList(STRIP_FROM_INC_PATH).isEmpty())
919  {
920  iName=stripFromIncludePath(fd->absFilePath());
921  }
922  else // use name of the file containing the class definition
923  {
924  iName=fd->name();
925  }
926  if (fd->generateSourceFile()) // generate code for header
927  {
928  cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
929  }
930  else // put #include in the class documentation without link
931  {
932  cd->setIncludeFile(0,iName,local,TRUE);
933  }
934  }
935  }
936 }
937 
938 #if 0
939 static bool addNamespace(Entry *root,ClassDef *cd)
940 {
941  // see if this class is defined inside a namespace
942  if (root->section & Entry::COMPOUND_MASK)
943  {
944  Entry *e = root->parent;
945  while (e)
946  {
948  {
949  NamespaceDef *nd=0;
950  QCString nsName = stripAnonymousNamespaceScope(e->name);
951  //printf("addNameSpace() trying: %s\n",nsName.data());
952  if (!nsName.isEmpty() && nsName.at(0)!='@' &&
953  (nd=getResolvedNamespace(nsName))
954  )
955  {
956  cd->setNamespace(nd);
957  cd->setOuterScope(nd);
958  nd->insertClass(cd);
959  return TRUE;
960  }
961  }
962  e=e->parent;
963  }
964  }
965  return FALSE;
966 }
967 #endif
968 
969 #if 0
970 static Definition *findScope(Entry *root,int level=0)
971 {
972  if (root==0) return 0;
973  //printf("start findScope name=%s\n",root->name.data());
974  Definition *result=0;
975  if (root->section&Entry::SCOPE_MASK)
976  {
977  result = findScope(root->parent,level+1); // traverse to the root of the tree
978  if (result)
979  {
980  //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
981  // TODO: look at template arguments
982  result = result->findInnerCompound(root->name);
983  }
984  else // reached the global scope
985  {
986  // TODO: look at template arguments
987  result = Doxygen::globalScope->findInnerCompound(root->name);
988  //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
989  }
990  }
991  //printf("end findScope(%s,%d)=%s\n",root->name.data(),
992  // level,result==0 ? "<none>" : result->name().data());
993  return result;
994 }
995 #endif
996 
1001 static Definition *buildScopeFromQualifiedName(const QCString name,
1002  int level,SrcLangExt lang,TagInfo *tagInfo)
1003 {
1004  //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
1005  int i=0;
1006  int p=0,l;
1007  Definition *prevScope=Doxygen::globalScope;
1008  QCString fullScope;
1009  while (i<level)
1010  {
1011  int idx=getScopeFragment(name,p,&l);
1012  if (idx==-1) return prevScope;
1013  QCString nsName = name.mid(idx,l);
1014  if (nsName.isEmpty()) return prevScope;
1015  if (!fullScope.isEmpty()) fullScope+="::";
1016  fullScope+=nsName;
1017  NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
1018  Definition *innerScope = nd;
1019  ClassDef *cd=0;
1020  if (nd==0) cd = getClass(fullScope);
1021  if (nd==0 && cd) // scope is a class
1022  {
1023  innerScope = cd;
1024  }
1025  else if (nd==0 && cd==0 && fullScope.find('<')==-1) // scope is not known and could be a namespace!
1026  {
1027  // introduce bogus namespace
1028  //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
1029  nd=new NamespaceDef(
1030  "[generated]",1,1,fullScope,
1031  tagInfo?tagInfo->tagName:QCString(),
1032  tagInfo?tagInfo->fileName:QCString());
1033  nd->setLanguage(lang);
1034 
1035  // add namespace to the list
1036  Doxygen::namespaceSDict->inSort(fullScope,nd);
1037  innerScope = nd;
1038  }
1039  else // scope is a namespace
1040  {
1041  }
1042  if (innerScope)
1043  {
1044  // make the parent/child scope relation
1045  prevScope->addInnerCompound(innerScope);
1046  innerScope->setOuterScope(prevScope);
1047  }
1048  else // current scope is a class, so return only the namespace part...
1049  {
1050  return prevScope;
1051  }
1052  // proceed to the next scope fragment
1053  p=idx+l+2;
1054  prevScope=innerScope;
1055  i++;
1056  }
1057  return prevScope;
1058 }
1059 
1060 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
1061  FileDef *fileScope,TagInfo *tagInfo)
1062 {
1063  //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
1064  Definition *resultScope=startScope;
1065  if (resultScope==0) resultScope=Doxygen::globalScope;
1066  QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
1067  int l1=0,i1;
1068  i1=getScopeFragment(scope,0,&l1);
1069  if (i1==-1)
1070  {
1071  //printf(">no fragments!\n");
1072  return resultScope;
1073  }
1074  int p=i1+l1,l2=0,i2;
1075  while ((i2=getScopeFragment(scope,p,&l2))!=-1)
1076  {
1077  QCString nestedNameSpecifier = scope.mid(i1,l1);
1078  Definition *orgScope = resultScope;
1079  //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
1080  resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
1081  //printf(" resultScope=%p\n",resultScope);
1082  if (resultScope==0)
1083  {
1084  NamespaceSDict *usedNamespaces;
1085  if (orgScope==Doxygen::globalScope && fileScope &&
1086  (usedNamespaces = fileScope->getUsedNamespaces()))
1087  // also search for used namespaces
1088  {
1089  NamespaceSDict::Iterator ni(*usedNamespaces);
1090  NamespaceDef *nd;
1091  for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
1092  {
1093  // restart search within the used namespace
1094  resultScope = findScopeFromQualifiedName(nd,n,fileScope,tagInfo);
1095  }
1096  if (resultScope)
1097  {
1098  // for a nested class A::I in used namespace N, we get
1099  // N::A::I while looking for A, so we should compare
1100  // resultScope->name() against scope.left(i2+l2)
1101  //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1102  if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1103  {
1104  break;
1105  }
1106  goto nextFragment;
1107  }
1108  }
1109 
1110  // also search for used classes. Complication: we haven't been able
1111  // to put them in the right scope yet, because we are still resolving
1112  // the scope relations!
1113  // Therefore loop through all used classes and see if there is a right
1114  // scope match between the used class and nestedNameSpecifier.
1115  QDictIterator<FileDef> ui(g_usingDeclarations);
1116  FileDef *usedFd;
1117  for (ui.toFirst();(usedFd=ui.current());++ui)
1118  {
1119  //printf("Checking using class %s\n",ui.currentKey());
1120  if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1121  {
1122  // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1123  // so use this instead.
1124  QCString fqn = QCString(ui.currentKey())+
1125  scope.right(scope.length()-p);
1126  resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),
1127  startScope->getLanguage(),0);
1128  //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1129  if (resultScope)
1130  {
1131  //printf("> Match! resultScope=%s\n",resultScope->name().data());
1132  return resultScope;
1133  }
1134  }
1135  }
1136 
1137  //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1138  return 0;
1139  }
1140  nextFragment:
1141  i1=i2;
1142  l1=l2;
1143  p=i2+l2;
1144  }
1145  //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1146  return resultScope;
1147 }
1148 
1150  const QCString &name,
1151  const QList<ArgumentList> *tArgLists)
1152 {
1153  if (tArgLists==0) return 0;
1154 
1155  QListIterator<ArgumentList> ali(*tArgLists);
1156  // for each scope fragment, check if it is a template and advance through
1157  // the list if so.
1158  int i,p=0;
1159  while ((i=name.find("::",p))!=-1)
1160  {
1161  NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1162  if (nd==0)
1163  {
1164  ClassDef *cd = getClass(name.left(i));
1165  if (cd)
1166  {
1167  if (cd->templateArguments())
1168  {
1169  ++ali;
1170  }
1171  }
1172  }
1173  p=i+2;
1174  }
1175  return ali.current();
1176 }
1177 
1178 static
1179 ClassDef::CompoundType convertToCompoundType(int section,uint64 specifier)
1180 {
1182  if (specifier&Entry::Struct)
1183  sec=ClassDef::Struct;
1184  else if (specifier&Entry::Union)
1185  sec=ClassDef::Union;
1186  else if (specifier&Entry::Category)
1187  sec=ClassDef::Category;
1188  else if (specifier&Entry::Interface)
1189  sec=ClassDef::Interface;
1190  else if (specifier&Entry::Protocol)
1191  sec=ClassDef::Protocol;
1192  else if (specifier&Entry::Exception)
1193  sec=ClassDef::Exception;
1194  else if (specifier&Entry::Service)
1195  sec=ClassDef::Service;
1196  else if (specifier&Entry::Singleton)
1197  sec=ClassDef::Singleton;
1198 
1199  switch(section)
1200  {
1201  //case Entry::UNION_SEC:
1202  case Entry::UNIONDOC_SEC:
1203  sec=ClassDef::Union;
1204  break;
1205  //case Entry::STRUCT_SEC:
1206  case Entry::STRUCTDOC_SEC:
1207  sec=ClassDef::Struct;
1208  break;
1209  //case Entry::INTERFACE_SEC:
1211  sec=ClassDef::Interface;
1212  break;
1213  //case Entry::PROTOCOL_SEC:
1215  sec=ClassDef::Protocol;
1216  break;
1217  //case Entry::CATEGORY_SEC:
1219  sec=ClassDef::Category;
1220  break;
1221  //case Entry::EXCEPTION_SEC:
1223  sec=ClassDef::Exception;
1224  break;
1225  case Entry::SERVICEDOC_SEC:
1226  sec=ClassDef::Service;
1227  break;
1229  sec=ClassDef::Singleton;
1230  break;
1231  }
1232  return sec;
1233 }
1234 
1235 
1236 static void addClassToContext(EntryNav *rootNav)
1237 {
1238  //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1239  rootNav->loadEntry(g_storage);
1240  Entry *root = rootNav->entry();
1241 
1242  //NamespaceDef *nd = 0;
1243  FileDef *fd = rootNav->fileDef();
1244 
1245  QCString scName;
1246  if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1247  {
1248  scName=rootNav->parent()->name();
1249  }
1250  // name without parent's scope
1251  QCString fullName = root->name;
1252 
1253  // strip off any template parameters (but not those for specializations)
1254  fullName=stripTemplateSpecifiersFromScope(fullName);
1255 
1256  // name with scope (if not present already)
1257  QCString qualifiedName = fullName;
1258  if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1259  {
1260  qualifiedName.prepend(scName+"::");
1261  }
1262 
1263  // see if we already found the class before
1264  ClassDef *cd = getClass(qualifiedName);
1265 
1266  Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1267  cd ? qPrint(cd->name()) : qPrint(root->name), qPrint(qualifiedName),cd);
1268 
1269  if (cd)
1270  {
1271  fullName=cd->name();
1272  Debug::print(Debug::Classes,0," Existing class %s!\n",qPrint(cd->name()));
1273  //if (cd->templateArguments()==0)
1274  //{
1275  // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1276  // cd->setTemplateArguments(tArgList);
1277  //}
1278 
1279  cd->setDocumentation(root->doc,root->docFile,root->docLine);
1280  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1281 
1282  if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1283  {
1284  cd->setBodySegment(root->bodyLine,root->endBodyLine);
1285  cd->setBodyDef(fd);
1286  }
1287  //cd->setName(fullName); // change name to match docs
1288 
1289  if (cd->templateArguments()==0 || (cd->isForwardDeclared() && (root->spec&Entry::ForwardDecl)==0))
1290  {
1291  // this happens if a template class declared with @class is found
1292  // before the actual definition or if a forward declaration has different template
1293  // parameter names.
1294  ArgumentList *tArgList =
1296  cd->setTemplateArguments(tArgList);
1297  }
1298 
1300  }
1301  else // new class
1302  {
1304 
1305  QCString className;
1306  QCString namespaceName;
1307  extractNamespaceName(fullName,className,namespaceName);
1308 
1309  //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1310  // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1311 
1312  QCString tagName;
1313  QCString refFileName;
1314  TagInfo *tagInfo = rootNav->tagInfo();
1315  int i;
1316  if (tagInfo)
1317  {
1318  tagName = tagInfo->tagName;
1319  refFileName = tagInfo->fileName;
1320  if (fullName.find("::")!=-1)
1321  // symbols imported via tag files may come without the parent scope,
1322  // so we artificially create it here
1323  {
1324  buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1325  }
1326  }
1327  ArgumentList *tArgList = 0;
1328  if ((root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java) && (i=fullName.find('<'))!=-1)
1329  {
1330  // a Java/C# generic class looks like a C++ specialization, so we need to split the
1331  // name and template arguments here
1332  tArgList = new ArgumentList;
1333  stringToArgumentList(fullName.mid(i),tArgList);
1334  fullName=fullName.left(i);
1335  }
1336  else
1337  {
1338  tArgList = getTemplateArgumentsFromName(fullName,root->tArgLists);
1339  }
1340  cd=new ClassDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn,
1341  fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1342  Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1343  qPrint(fullName),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
1344  cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1345  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1346  cd->setLanguage(root->lang);
1347  cd->setId(root->id);
1348  cd->setHidden(root->hidden);
1349  cd->setArtificial(root->artificial);
1350  cd->setClassSpecifier(root->spec);
1351  cd->setTypeConstraints(root->typeConstr);
1352  //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1353 
1354  //printf("class %s template args=%s\n",fullName.data(),
1355  // tArgList ? tempArgListToString(tArgList,root->lang).data() : "<none>");
1356  cd->setTemplateArguments(tArgList);
1357  cd->setProtection(root->protection);
1358  cd->setIsStatic(root->stat);
1359 
1360  // file definition containing the class cd
1361  cd->setBodySegment(root->bodyLine,root->endBodyLine);
1362  cd->setBodyDef(fd);
1363 
1364  // see if the class is found inside a namespace
1365  //bool found=addNamespace(root,cd);
1366 
1367  cd->insertUsedFile(fd);
1368 
1369  // add class to the list
1370  //printf("ClassDict.insert(%s)\n",fullName.data());
1371  Doxygen::classSDict->append(fullName,cd);
1372 
1373  if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1374  {
1375  //printf("inserting generic '%s' cd=%p\n",fullName.data(),cd);
1376  Doxygen::genericsDict->insert(fullName,cd);
1377  }
1378  }
1379 
1380  cd->addSectionsToDefinition(root->anchors);
1381  if (!root->subGrouping) cd->setSubGrouping(FALSE);
1382  if (cd->hasDocumentation())
1383  {
1384  addIncludeFile(cd,fd,root);
1385  }
1386  if (fd && (root->section & Entry::COMPOUND_MASK))
1387  {
1388  //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1389  // cd->name().data(),
1390  // fd->name().data(),
1391  // root->fileName.data()
1392  // );
1393  cd->setFileDef(fd);
1394  fd->insertClass(cd);
1395  }
1396  addClassToGroups(root,cd);
1397  cd->setRefItems(root->sli);
1398 
1399  rootNav->releaseEntry();
1400 }
1401 
1402 //----------------------------------------------------------------------
1403 // build a list of all classes mentioned in the documentation
1404 // and all classes that have a documentation block before their definition.
1405 static void buildClassList(EntryNav *rootNav)
1406 {
1407  if (
1408  ((rootNav->section() & Entry::COMPOUND_MASK) ||
1409  rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1410  )
1411  {
1412  addClassToContext(rootNav);
1413  }
1415 }
1416 
1417 static void buildClassDocList(EntryNav *rootNav)
1418 {
1419  if (
1420  (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1421  )
1422  {
1423  addClassToContext(rootNav);
1424  }
1426 }
1427 
1429 {
1430  ClassSDict::Iterator cli(*Doxygen::classSDict);
1431  for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1432 
1433  bool done=FALSE;
1434  int iteration=0;
1435  while (!done)
1436  {
1437  done=TRUE;
1438  ++iteration;
1439  ClassDef *cd=0;
1440  for (cli.toFirst();(cd=cli.current());++cli)
1441  {
1442  if (!cd->visited)
1443  {
1444  QCString name = stripAnonymousNamespaceScope(cd->name());
1445  //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1446  // also add class to the correct structural context
1447  Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1448  name,cd->getFileDef(),0);
1449  if (d)
1450  {
1451  //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1452  d->addInnerCompound(cd);
1453  cd->setOuterScope(d);
1454  cd->visited=TRUE;
1455  done=FALSE;
1456  }
1457  //else
1458  //{
1459  // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1460  //}
1461  }
1462  }
1463  }
1464 
1465  //give warnings for unresolved compounds
1466  ClassDef *cd=0;
1467  for (cli.toFirst();(cd=cli.current());++cli)
1468  {
1469  if (!cd->visited)
1470  {
1471  QCString name = stripAnonymousNamespaceScope(cd->name());
1472  //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1474  // anyway, so we can at least relate scopes properly.
1475  Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1476  if (d!=cd && !cd->getDefFileName().isEmpty())
1477  // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1478  // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1479  // also avoid warning for stuff imported via a tagfile.
1480  {
1481  d->addInnerCompound(cd);
1482  cd->setOuterScope(d);
1483  warn(cd->getDefFileName(),cd->getDefLine(),
1484  "Internal inconsistency: scope for class %s not "
1485  "found!",name.data()
1486  );
1487  }
1488  }
1489  }
1490 }
1491 
1493 {
1494  //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
1495  //if (!inlineGroupedClasses) return;
1496  //printf("** distributeClassGroupRelations()\n");
1497 
1498  ClassSDict::Iterator cli(*Doxygen::classSDict);
1499  for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1500 
1501  ClassDef *cd;
1502  for (cli.toFirst();(cd=cli.current());++cli)
1503  {
1504  //printf("Checking %s\n",cd->name().data());
1505  // distribute the group to nested classes as well
1506  if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1507  {
1508  //printf(" Candidate for merging\n");
1509  ClassSDict::Iterator ncli(*cd->getClassSDict());
1510  ClassDef *ncd;
1511  GroupDef *gd = cd->partOfGroups()->at(0);
1512  for (ncli.toFirst();(ncd=ncli.current());++ncli)
1513  {
1514  if (ncd->partOfGroups()==0)
1515  {
1516  //printf(" Adding %s to group '%s'\n",ncd->name().data(),
1517  // gd->groupTitle());
1518  ncd->makePartOfGroup(gd);
1519  gd->addClass(ncd);
1520  }
1521  }
1522  cd->visited=TRUE; // only visit every class once
1523  }
1524  }
1525 }
1526 
1527 //----------------------------
1528 
1529 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1530 {
1531  QCString fullName = removeAnonymousScopes(templ->name());
1532  if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1533  fullName+="."+fieldName;
1534  ClassDef *cd = new ClassDef(templ->getDefFileName(),
1535  templ->getDefLine(),
1536  templ->getDefColumn(),
1537  fullName,
1538  templ->compoundType());
1539  cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1540  cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1541  cd->setLanguage(templ->getLanguage());
1542  cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1543  cd->setBodyDef(templ->getBodyDef());
1544 
1545  cd->setOuterScope(rootCd->getOuterScope());
1546  if (rootCd->getOuterScope()!=Doxygen::globalScope)
1547  {
1548  rootCd->getOuterScope()->addInnerCompound(cd);
1549  }
1550 
1551  FileDef *fd = templ->getFileDef();
1552  if (fd)
1553  {
1554  cd->setFileDef(fd);
1555  fd->insertClass(cd);
1556  }
1557  GroupList *groups = rootCd->partOfGroups();
1558  if ( groups!=0 )
1559  {
1560  GroupListIterator gli(*groups);
1561  GroupDef *gd;
1562  for (gli.toFirst();(gd=gli.current());++gli)
1563  {
1564  cd->makePartOfGroup(gd);
1565  gd->addClass(cd);
1566  }
1567  }
1568  //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1569  Doxygen::classSDict->append(fullName,cd);
1570 
1572  if (ml)
1573  {
1574  MemberListIterator li(*ml);
1575  MemberDef *md;
1576  for (li.toFirst();(md=li.current());++li)
1577  {
1578  //printf(" Member %s type=%s\n",md->name().data(),md->typeString());
1579  MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1580  md->typeString(),md->name(),md->argsString(),md->excpString(),
1581  md->protection(),md->virtualness(),md->isStatic(),Member,
1582  md->memberType(),
1583  0,0);
1584  imd->setMemberClass(cd);
1585  imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1586  imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1589  imd->setMemberGroupId(md->getMemberGroupId());
1590  imd->setInitializer(md->initializer());
1591  imd->setMaxInitLines(md->initializerLines());
1592  imd->setBitfields(md->bitfieldString());
1593  imd->setLanguage(md->getLanguage());
1594  cd->insertMember(imd);
1595  }
1596  }
1597  return cd;
1598 }
1599 
1609 static void processTagLessClasses(ClassDef *rootCd,
1610  ClassDef *cd,
1611  ClassDef *tagParentCd,
1612  const QCString &prefix,int count)
1613 {
1614  //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1615  //printf("checking members for %s\n",cd->name().data());
1616  if (cd->getClassSDict())
1617  {
1619  if (ml)
1620  {
1621  MemberListIterator li(*ml);
1622  MemberDef *md;
1623  for (li.toFirst();(md=li.current());++li)
1624  {
1625  QCString type = md->typeString();
1626  if (type.find("::@")!=-1) // member of tag less struct/union
1627  {
1629  ClassDef *icd;
1630  for (it.toFirst();(icd=it.current());++it)
1631  {
1632  //printf(" member %s: type='%s'\n",md->name().data(),type.data());
1633  //printf(" comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1634  if (type.find(icd->name())!=-1) // matching tag less struct/union
1635  {
1636  QCString name = md->name();
1637  if (name.at(0)=='@') name = "__unnamed__";
1638  if (!prefix.isEmpty()) name.prepend(prefix+".");
1639  //printf(" found %s for class %s\n",name.data(),cd->name().data());
1640  ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1641  processTagLessClasses(rootCd,icd,ncd,name,count+1);
1642  //printf(" addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1643  tagParentCd->addTaggedInnerClass(ncd);
1644  ncd->setTagLessReference(icd);
1645 
1646  // replace tag-less type for generated/original member
1647  // by newly created class name.
1648  // note the difference between changing cd and tagParentCd.
1649  // for the initial call this is the same pointer, but for
1650  // recursive calls cd is the original tag-less struct (of which
1651  // there is only one instance) and tagParentCd is the newly
1652  // generated tagged struct of which there can be multiple instances!
1653  MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1654  if (pml)
1655  {
1656  MemberListIterator pli(*pml);
1657  MemberDef *pmd;
1658  for (pli.toFirst();(pmd=pli.current());++pli)
1659  {
1660  if (pmd->name()==md->name())
1661  {
1662  pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1663  //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1664  }
1665  }
1666  }
1667  }
1668  }
1669  }
1670  }
1671  }
1672  }
1673 }
1674 
1676 {
1677  if (cd->getClassSDict())
1678  {
1680  ClassDef *icd;
1681  for (it.toFirst();(icd=it.current());++it)
1682  {
1683  if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1684  {
1685  findTagLessClasses(icd);
1686  }
1687  }
1688  }
1689 
1690  processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1691 }
1692 
1693 static void findTagLessClasses()
1694 {
1695  ClassSDict::Iterator cli(*Doxygen::classSDict);
1696  ClassDef *cd;
1697  for (cli.toFirst();(cd=cli.current());++cli) // for each class
1698  {
1699  Definition *scope = cd->getOuterScope();
1700  if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1701  {
1702  findTagLessClasses(cd);
1703  }
1704  }
1705 }
1706 
1707 
1708 //----------------------------------------------------------------------
1709 // build a list of all namespaces mentioned in the documentation
1710 // and all namespaces that have a documentation block before their definition.
1711 static void buildNamespaceList(EntryNav *rootNav)
1712 {
1713  if (
1714  (rootNav->section()==Entry::NAMESPACE_SEC ||
1715  rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1716  rootNav->section()==Entry::PACKAGEDOC_SEC
1717  ) &&
1718  !rootNav->name().isEmpty()
1719  )
1720  {
1721  rootNav->loadEntry(g_storage);
1722  Entry *root = rootNav->entry();
1723 
1724  //printf("** buildNamespaceList(%s)\n",root->name.data());
1725 
1726  QCString fName = root->name;
1727  if (root->section==Entry::PACKAGEDOC_SEC)
1728  {
1729  fName=substitute(fName,".","::");
1730  }
1731 
1732  QCString fullName = stripAnonymousNamespaceScope(fName);
1733  if (!fullName.isEmpty())
1734  {
1735  //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1736  // root->fileName.data(), root->startLine);
1737  NamespaceDef *nd;
1738  if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1739  {
1740  nd->setDocumentation(root->doc,root->docFile,root->docLine);
1741  nd->setName(fullName); // change name to match docs
1742  nd->addSectionsToDefinition(root->anchors);
1743  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1744  if (nd->getLanguage()==SrcLangExt_Unknown)
1745  {
1746  nd->setLanguage(root->lang);
1747  }
1748  if (rootNav->tagInfo()==0) // if we found the namespace in a tag file
1749  // and also in a project file, then remove
1750  // the tag file reference
1751  {
1752  nd->setReference("");
1753  nd->setFileName(fullName);
1754  }
1755 
1756  // file definition containing the namespace nd
1757  FileDef *fd=rootNav->fileDef();
1758  // insert the namespace in the file definition
1759  if (fd) fd->insertNamespace(nd);
1760  addNamespaceToGroups(root,nd);
1761  nd->setRefItems(root->sli);
1762  }
1763  else // fresh namespace
1764  {
1765  QCString tagName;
1766  QCString tagFileName;
1767  TagInfo *tagInfo = rootNav->tagInfo();
1768  if (tagInfo)
1769  {
1770  tagName = tagInfo->tagName;
1771  tagFileName = tagInfo->fileName;
1772  }
1773  //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1774  NamespaceDef *nd=new NamespaceDef(tagInfo?tagName:root->fileName,root->startLine,
1775  root->startColumn,fullName,tagName,tagFileName,
1776  root->type,root->spec&Entry::Published);
1777  nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1778  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1779  nd->addSectionsToDefinition(root->anchors);
1780  nd->setHidden(root->hidden);
1781  nd->setArtificial(root->artificial);
1782  nd->setLanguage(root->lang);
1783  nd->setId(root->id);
1784 
1785  //printf("Adding namespace to group\n");
1786  addNamespaceToGroups(root,nd);
1787  nd->setRefItems(root->sli);
1788 
1789  // file definition containing the namespace nd
1790  FileDef *fd=rootNav->fileDef();
1791  // insert the namespace in the file definition
1792  if (fd) fd->insertNamespace(nd);
1793 
1794  // the empty string test is needed for extract all case
1795  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1796  nd->insertUsedFile(fd);
1797  nd->setBodySegment(root->bodyLine,root->endBodyLine);
1798  nd->setBodyDef(fd);
1799  // add class to the list
1800  Doxygen::namespaceSDict->inSort(fullName,nd);
1801 
1802  // also add namespace to the correct structural context
1803  Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName,0,tagInfo);
1804  //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1805  if (d==0) // we didn't find anything, create the scope artificially
1806  // anyway, so we can at least relate scopes properly.
1807  {
1808  Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1809  d->addInnerCompound(nd);
1810  nd->setOuterScope(d);
1811  // TODO: Due to the order in which the tag file is written
1812  // a nested class can be found before its parent!
1813  }
1814  else
1815  {
1816  d->addInnerCompound(nd);
1817  nd->setOuterScope(d);
1818  }
1819  }
1820  }
1821 
1822  rootNav->releaseEntry();
1823  }
1825 }
1826 
1827 //----------------------------------------------------------------------
1828 
1830  const QCString &name)
1831 {
1832  NamespaceDef *usingNd =0;
1833  if (unl)
1834  {
1835  //printf("Found namespace dict %d\n",unl->count());
1836  NamespaceSDict::Iterator unli(*unl);
1837  NamespaceDef *und;
1838  for (unli.toFirst();(und=unli.current());++unli)
1839  {
1840  QCString uScope=und->name()+"::";
1841  usingNd = getResolvedNamespace(uScope+name);
1842  //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1843  }
1844  }
1845  return usingNd;
1846 }
1847 
1848 static void findUsingDirectives(EntryNav *rootNav)
1849 {
1850  if (rootNav->section()==Entry::USINGDIR_SEC)
1851  {
1852  rootNav->loadEntry(g_storage);
1853  Entry *root = rootNav->entry();
1854 
1855  //printf("Found using directive %s at line %d of %s\n",
1856  // root->name.data(),root->startLine,root->fileName.data());
1857  QCString name=substitute(root->name,".","::");
1858  if (name.right(2)=="::")
1859  {
1860  name=name.left(name.length()-2);
1861  }
1862  if (!name.isEmpty())
1863  {
1864  NamespaceDef *usingNd = 0;
1865  NamespaceDef *nd = 0;
1866  FileDef *fd = rootNav->fileDef();
1867  QCString nsName;
1868 
1869  // see if the using statement was found inside a namespace or inside
1870  // the global file scope.
1871  if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1872  (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1873  )
1874  {
1875  nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1876  if (!nsName.isEmpty())
1877  {
1878  nd = getResolvedNamespace(nsName);
1879  }
1880  }
1881 
1882  // find the scope in which the `using' namespace is defined by prepending
1883  // the possible scopes in which the using statement was found, starting
1884  // with the most inner scope and going to the most outer scope (i.e.
1885  // file scope).
1886  int scopeOffset = nsName.length();
1887  do
1888  {
1889  QCString scope=scopeOffset>0 ?
1890  nsName.left(scopeOffset)+"::" : QCString();
1891  usingNd = getResolvedNamespace(scope+name);
1892  //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1893  if (scopeOffset==0)
1894  {
1895  scopeOffset=-1;
1896  }
1897  else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1898  {
1899  scopeOffset=0;
1900  }
1901  } while (scopeOffset>=0 && usingNd==0);
1902 
1903  if (usingNd==0 && nd) // not found, try used namespaces in this scope
1904  // or in one of the parent namespace scopes
1905  {
1906  NamespaceDef *pnd = nd;
1907  while (pnd && usingNd==0)
1908  {
1909  // also try with one of the used namespaces found earlier
1910  usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1911 
1912  // goto the parent
1913  Definition *s = pnd->getOuterScope();
1914  if (s && s->definitionType()==Definition::TypeNamespace)
1915  {
1916  pnd = (NamespaceDef*)s;
1917  }
1918  else
1919  {
1920  pnd = 0;
1921  }
1922  }
1923  }
1924  if (usingNd==0 && fd) // still nothing, also try used namespace in the
1925  // global scope
1926  {
1927  usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1928  }
1929 
1930  //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1931 
1932  // add the namespace the correct scope
1933  if (usingNd)
1934  {
1935  //printf("using fd=%p nd=%p\n",fd,nd);
1936  if (nd)
1937  {
1938  //printf("Inside namespace %s\n",nd->name().data());
1939  nd->addUsingDirective(usingNd);
1940  }
1941  else if (fd)
1942  {
1943  //printf("Inside file %s\n",fd->name().data());
1944  fd->addUsingDirective(usingNd);
1945  }
1946  }
1947  else // unknown namespace, but add it anyway.
1948  {
1949  //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1950  NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1951  nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1952  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1953  nd->addSectionsToDefinition(root->anchors);
1954  //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1955  nd->setHidden(root->hidden);
1956  nd->setArtificial(TRUE);
1957  nd->setLanguage(root->lang);
1958  nd->setId(root->id);
1959 
1960  QListIterator<Grouping> gli(*root->groups);
1961  Grouping *g;
1962  for (;(g=gli.current());++gli)
1963  {
1964  GroupDef *gd=0;
1965  if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1966  gd->addNamespace(nd);
1967  }
1968 
1969  // insert the namespace in the file definition
1970  if (fd)
1971  {
1972  fd->insertNamespace(nd);
1973  fd->addUsingDirective(nd);
1974  }
1975 
1976  // the empty string test is needed for extract all case
1977  nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1978  nd->insertUsedFile(fd);
1979  // add class to the list
1980  Doxygen::namespaceSDict->inSort(name,nd);
1981  nd->setRefItems(root->sli);
1982  }
1983  }
1984 
1985  rootNav->releaseEntry();
1986  }
1988 }
1989 
1990 //----------------------------------------------------------------------
1991 
1992 static void buildListOfUsingDecls(EntryNav *rootNav)
1993 {
1994  if (rootNav->section()==Entry::USINGDECL_SEC &&
1995  !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1996  )
1997  {
1998  rootNav->loadEntry(g_storage);
1999  Entry *root = rootNav->entry();
2000 
2001  QCString name = substitute(root->name,".","::");
2002 
2003  if (g_usingDeclarations.find(name)==0)
2004  {
2005  FileDef *fd = rootNav->fileDef();
2006  if (fd)
2007  {
2008  g_usingDeclarations.insert(name,fd);
2009  }
2010  }
2011 
2012  rootNav->releaseEntry();
2013  }
2015 }
2016 
2017 
2018 static void findUsingDeclarations(EntryNav *rootNav)
2019 {
2020  if (rootNav->section()==Entry::USINGDECL_SEC &&
2021  !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2022  )
2023  {
2024  rootNav->loadEntry(g_storage);
2025  Entry *root = rootNav->entry();
2026 
2027  //printf("Found using declaration %s at line %d of %s inside section %x\n",
2028  // root->name.data(),root->startLine,root->fileName.data(),
2029  // rootNav->parent()->section());
2030  if (!root->name.isEmpty())
2031  {
2032  ClassDef *usingCd = 0;
2033  NamespaceDef *nd = 0;
2034  FileDef *fd = rootNav->fileDef();
2035  QCString scName;
2036 
2037  // see if the using statement was found inside a namespace or inside
2038  // the global file scope.
2039  if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
2040  {
2041  scName=rootNav->parent()->name();
2042  if (!scName.isEmpty())
2043  {
2044  nd = getResolvedNamespace(scName);
2045  }
2046  }
2047 
2048  // Assume the using statement was used to import a class.
2049  // Find the scope in which the `using' namespace is defined by prepending
2050  // the possible scopes in which the using statement was found, starting
2051  // with the most inner scope and going to the most outer scope (i.e.
2052  // file scope).
2053 
2054  QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2055  usingCd = getResolvedClass(nd,fd,name);
2056  if (usingCd==0)
2057  {
2058  usingCd = Doxygen::hiddenClasses->find(name);
2059  }
2060 
2061  //printf("%s -> %p\n",root->name.data(),usingCd);
2062  if (usingCd==0) // definition not in the input => add an artificial class
2063  {
2064  Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
2065  qPrint(name),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
2066  usingCd = new ClassDef(
2067  "<using>",1,1,
2068  name,
2069  ClassDef::Class);
2070  Doxygen::hiddenClasses->append(root->name,usingCd);
2071  usingCd->setArtificial(TRUE);
2072  usingCd->setLanguage(root->lang);
2073  }
2074  else
2075  {
2076  Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",
2077  qPrint(usingCd->name()),
2078  nd?qPrint(nd->name()):
2079  fd?qPrint(fd->name()):
2080  "<unknown>");
2081  }
2082 
2083  if (nd)
2084  {
2085  //printf("Inside namespace %s\n",nd->name().data());
2086  nd->addUsingDeclaration(usingCd);
2087  }
2088  else if (fd)
2089  {
2090  //printf("Inside file %s\n",fd->name().data());
2091  fd->addUsingDeclaration(usingCd);
2092  }
2093  }
2094 
2095  rootNav->releaseEntry();
2096  }
2098 }
2099 
2100 //----------------------------------------------------------------------
2101 
2102 static void findUsingDeclImports(EntryNav *rootNav)
2103 {
2104  if (rootNav->section()==Entry::USINGDECL_SEC &&
2105  (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
2106  )
2107  {
2108  //printf("Found using declaration %s at line %d of %s inside section %x\n",
2109  // root->name.data(),root->startLine,root->fileName.data(),
2110  // root->parent->section);
2111  QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
2112  fullName=stripAnonymousNamespaceScope(fullName);
2113  fullName=stripTemplateSpecifiersFromScope(fullName);
2114  ClassDef *cd = getClass(fullName);
2115  if (cd)
2116  {
2117  //printf("found class %s\n",cd->name().data());
2118  int i=rootNav->name().find("::");
2119  if (i!=-1)
2120  {
2121  QCString scope=rootNav->name().left(i);
2122  QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
2123  ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2124  if (bcd)
2125  {
2126  //printf("found class %s\n",bcd->name().data());
2128  if (mndict)
2129  {
2130  MemberNameInfo *mni = mndict->find(memName);
2131  if (mni)
2132  {
2133  MemberNameInfoIterator mnii(*mni);
2134  MemberInfo *mi;
2135  for ( ; (mi=mnii.current()) ; ++mnii )
2136  {
2137  MemberDef *md = mi->memberDef;
2138  if (md && md->protection()!=Private)
2139  {
2140 
2141  rootNav->loadEntry(g_storage);
2142  Entry *root = rootNav->entry();
2143 
2144  //printf("found member %s\n",mni->memberName());
2145  MemberDef *newMd = 0;
2146  {
2147  QCString fileName = root->fileName;
2148  if (fileName.isEmpty() && rootNav->tagInfo())
2149  {
2150  fileName = rootNav->tagInfo()->tagName;
2151  }
2152  ArgumentList *templAl = md->templateArguments();
2153  ArgumentList *al = md->templateArguments();
2154  newMd = new MemberDef(
2155  fileName,root->startLine,root->startColumn,
2156  md->typeString(),memName,md->argsString(),
2157  md->excpString(),root->protection,root->virt,
2158  md->isStatic(),Member,md->memberType(),
2159  templAl,al
2160  );
2161  }
2162  newMd->setMemberClass(cd);
2163  cd->insertMember(newMd);
2164  if (!root->doc.isEmpty() || !root->brief.isEmpty())
2165  {
2166  newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2167  newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2168  newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2169  }
2170  else
2171  {
2172  newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2173  newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2175  }
2176  newMd->setDefinition(md->definition());
2177  newMd->enableCallGraph(root->callGraph);
2178  newMd->enableCallerGraph(root->callerGraph);
2179  newMd->setBitfields(md->bitfieldString());
2180  newMd->addSectionsToDefinition(root->anchors);
2181  newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2182  newMd->setBodyDef(md->getBodyDef());
2183  newMd->setInitializer(md->initializer());
2184  newMd->setMaxInitLines(md->initializerLines());
2185  newMd->setMemberGroupId(root->mGrpId);
2187  newMd->setLanguage(root->lang);
2188  newMd->setId(root->id);
2189 
2190  rootNav->releaseEntry();
2191  }
2192  }
2193  }
2194  }
2195  }
2196  }
2197  }
2198 
2199  }
2201 }
2202 
2203 //----------------------------------------------------------------------
2204 
2206 {
2207  // first mark all files as not visited
2208  FileNameListIterator fnli(*Doxygen::inputNameList);
2209  FileName *fn;
2210  for (fnli.toFirst();(fn=fnli.current());++fnli)
2211  {
2212  FileNameIterator fni(*fn);
2213  FileDef *fd;
2214  for (;(fd=fni.current());++fni)
2215  {
2216  fd->visited=FALSE;
2217  }
2218  }
2219  // then recursively add using directives found in #include files
2220  // to files that have not been visited.
2221  for (fnli.toFirst();(fn=fnli.current());++fnli)
2222  {
2223  FileNameIterator fni(*fn);
2224  FileDef *fd;
2225  for (fni.toFirst();(fd=fni.current());++fni)
2226  {
2227  if (!fd->visited)
2228  {
2229  //printf("----- adding using directives for file %s\n",fd->name().data());
2231  }
2232  }
2233  }
2234 }
2235 
2236 //----------------------------------------------------------------------
2237 
2239  EntryNav *rootNav,
2240  ClassDef *cd,
2241  MemberType mtype,
2242  const QCString &name,
2243  bool fromAnnScope,
2244  MemberDef *fromAnnMemb,
2245  Protection prot,
2246  Relationship related)
2247 {
2248  Entry *root = rootNav->entry();
2249 
2250  QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2251  QCString scopeSeparator="::";
2252  SrcLangExt lang = cd->getLanguage();
2253  if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2254  {
2255  qualScope = substitute(qualScope,"::",".");
2256  scopeSeparator=".";
2257  }
2259  " class variable:\n"
2260  " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2261  qPrint(root->type),
2262  qPrint(qualScope),
2263  qPrint(name),
2264  qPrint(root->args),
2265  root->protection,
2266  fromAnnScope,
2267  qPrint(root->initializer)
2268  );
2269 
2270  QCString def;
2271  if (!root->type.isEmpty())
2272  {
2273  if (related || mtype==MemberType_Friend || Config_getBool(HIDE_SCOPE_NAMES))
2274  {
2275  if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2276  {
2277  def="using "+name+" = "+root->type.mid(7);
2278  }
2279  else
2280  {
2281  def=root->type+" "+name+root->args;
2282  }
2283  }
2284  else
2285  {
2286  if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2287  {
2288  def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2289  }
2290  else
2291  {
2292  def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2293  }
2294  }
2295  }
2296  else
2297  {
2298  if (Config_getBool(HIDE_SCOPE_NAMES))
2299  {
2300  def=name+root->args;
2301  }
2302  else
2303  {
2304  def=qualScope+scopeSeparator+name+root->args;
2305  }
2306  }
2307  def.stripPrefix("static ");
2308 
2309  // see if the member is already found in the same scope
2310  // (this may be the case for a static member that is initialized
2311  // outside the class)
2312  MemberName *mn=Doxygen::memberNameSDict->find(name);
2313  if (mn)
2314  {
2315  MemberNameIterator mni(*mn);
2316  MemberDef *md;
2317  for (mni.toFirst();(md=mni.current());++mni)
2318  {
2319  //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2320  // md->getClassDef(),cd,root->type.data(),md->typeString());
2321  if (md->getClassDef()==cd &&
2323  // member already in the scope
2324  {
2325 
2326  if (root->lang==SrcLangExt_ObjC &&
2327  root->mtype==Property &&
2329  { // Objective-C 2.0 property
2330  // turn variable into a property
2331  md->setProtection(root->protection);
2333  }
2334  addMemberDocs(rootNav,md,def,0,FALSE);
2335  //printf(" Member already found!\n");
2336  return md;
2337  }
2338  }
2339  }
2340 
2341  QCString fileName = root->fileName;
2342  if (fileName.isEmpty() && rootNav->tagInfo())
2343  {
2344  fileName = rootNav->tagInfo()->tagName;
2345  }
2346 
2347  // new member variable, typedef or enum value
2348  MemberDef *md=new MemberDef(
2349  fileName,root->startLine,root->startColumn,
2350  root->type,name,root->args,root->exception,
2351  prot,Normal,root->stat,related,
2352  mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2353  md->setTagInfo(rootNav->tagInfo());
2354  md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2355  //md->setDefFile(root->fileName);
2356  //md->setDefLine(root->startLine);
2357  md->setDocumentation(root->doc,root->docFile,root->docLine);
2358  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2359  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2360  md->setDefinition(def);
2361  md->setBitfields(root->bitfields);
2362  md->addSectionsToDefinition(root->anchors);
2363  md->setFromAnonymousScope(fromAnnScope);
2364  md->setFromAnonymousMember(fromAnnMemb);
2365  //md->setIndentDepth(indentDepth);
2366  md->setBodySegment(root->bodyLine,root->endBodyLine);
2367  md->setInitializer(root->initializer);
2368  md->setMaxInitLines(root->initLines);
2369  md->setMemberGroupId(root->mGrpId);
2370  md->setMemberSpecifiers(root->spec);
2371  md->setReadAccessor(root->read);
2372  md->setWriteAccessor(root->write);
2373  md->enableCallGraph(root->callGraph);
2374  md->enableCallerGraph(root->callerGraph);
2375  md->setHidden(root->hidden);
2376  md->setArtificial(root->artificial);
2377  md->setLanguage(root->lang);
2378  md->setId(root->id);
2379  addMemberToGroups(root,md);
2380  //if (root->mGrpId!=-1)
2381  //{
2382  // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2383  // md->setMemberGroup(memberGroupDict[root->mGrpId]);
2384  //
2385  md->setBodyDef(rootNav->fileDef());
2386 
2387  //printf(" Adding member=%s\n",md->name().data());
2388  // add the member to the global list
2389  if (mn)
2390  {
2391  mn->append(md);
2392  }
2393  else // new variable name
2394  {
2395  mn = new MemberName(name);
2396  mn->append(md);
2397  //printf("Adding memberName=%s\n",mn->memberName());
2398  //Doxygen::memberNameDict.insert(name,mn);
2399  //Doxygen::memberNameList.append(mn);
2400  Doxygen::memberNameSDict->append(name,mn);
2401  // add the member to the class
2402  }
2403  //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd);
2404  cd->insertMember(md);
2405  md->setRefItems(root->sli);
2406 
2407  //TODO: insert FileDef instead of filename strings.
2408  cd->insertUsedFile(rootNav->fileDef());
2409  rootNav->changeSection(Entry::EMPTY_SEC);
2410  return md;
2411 }
2412 
2413 //----------------------------------------------------------------------
2414 
2416  EntryNav *rootNav,
2417  MemberType mtype,
2418  const QCString &scope,
2419  const QCString &name,
2420  bool fromAnnScope,
2421  /*int indentDepth,*/
2422  MemberDef *fromAnnMemb)
2423 {
2424  Entry *root = rootNav->entry();
2426  " global variable:\n"
2427  " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2428  qPrint(root->type),
2429  qPrint(scope),
2430  qPrint(name),
2431  qPrint(root->args),
2432  root->protection,
2433  mtype,
2434  root->lang
2435  );
2436 
2437  FileDef *fd = rootNav->fileDef();
2438 
2439  // see if we have a typedef that should hide a struct or union
2440  if (mtype==MemberType_Typedef && Config_getBool(TYPEDEF_HIDES_STRUCT))
2441  {
2442  QCString type = root->type;
2443  type.stripPrefix("typedef ");
2444  if (type.left(7)=="struct " || type.left(6)=="union ")
2445  {
2446  type.stripPrefix("struct ");
2447  type.stripPrefix("union ");
2448  static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2449  int l,s;
2450  s = re.match(type,0,&l);
2451  if (s>=0)
2452  {
2453  QCString typeValue = type.mid(s,l);
2454  ClassDef *cd = getClass(typeValue);
2455  if (cd)
2456  {
2457  // this typedef should hide compound name cd, so we
2458  // change the name that is displayed from cd.
2459  cd->setClassName(name);
2460  cd->setDocumentation(root->doc,root->docFile,root->docLine);
2461  cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2462  return 0;
2463  }
2464  }
2465  }
2466  }
2467 
2468  // see if the function is inside a namespace
2469  NamespaceDef *nd = 0;
2470  if (!scope.isEmpty())
2471  {
2472  if (scope.find('@')!=-1) return 0; // anonymous scope!
2473  //nscope=removeAnonymousScopes(scope);
2474  //if (!nscope.isEmpty())
2475  //{
2476  nd = getResolvedNamespace(scope);
2477  //}
2478  }
2479  QCString def;
2480 
2481  // determine the definition of the global variable
2482  if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' &&
2483  !Config_getBool(HIDE_SCOPE_NAMES)
2484  )
2485  // variable is inside a namespace, so put the scope before the name
2486  {
2487  SrcLangExt lang = nd->getLanguage();
2488  QCString sep=getLanguageSpecificSeparator(lang);
2489 
2490  if (!root->type.isEmpty())
2491  {
2492  if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2493  {
2494  def="using "+nd->name()+sep+name+" = "+root->type;
2495  }
2496  else // normal member
2497  {
2498  def=root->type+" "+nd->name()+sep+name+root->args;
2499  }
2500  }
2501  else
2502  {
2503  def=nd->name()+sep+name+root->args;
2504  }
2505  }
2506  else
2507  {
2508  if (!root->type.isEmpty() && !root->name.isEmpty())
2509  {
2510  if (name.at(0)=='@') // dummy variable representing anonymous union
2511  {
2512  def=root->type;
2513  }
2514  else
2515  {
2516  if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2517  {
2518  def="using "+root->name+" = "+root->type.mid(7);
2519  }
2520  else // normal member
2521  {
2522  def=root->type+" "+name+root->args;
2523  }
2524  }
2525  }
2526  else
2527  {
2528  def=name+root->args;
2529  }
2530  }
2531  def.stripPrefix("static ");
2532 
2533  MemberName *mn=Doxygen::functionNameSDict->find(name);
2534  if (mn)
2535  {
2536  //QCString nscope=removeAnonymousScopes(scope);
2537  //NamespaceDef *nd=0;
2538  //if (!nscope.isEmpty())
2539  if (!scope.isEmpty())
2540  {
2541  nd = getResolvedNamespace(scope);
2542  }
2543  MemberNameIterator mni(*mn);
2544  MemberDef *md;
2545  for (mni.toFirst();(md=mni.current());++mni)
2546  {
2547  if (
2548  ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2549  root->fileName==md->getFileDef()->absFilePath()
2550  ) // both variable names in the same file
2551  || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2552  )
2553  && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2554  && !md->isEnumerate() // in C# an enum value and enum can have the same name
2555  )
2556  // variable already in the scope
2557  {
2558  bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2559  md->argsString()!=root->args &&
2560  root->args.find('[')!=-1;
2561  bool staticsInDifferentFiles =
2562  root->stat && md->isStatic() &&
2563  root->fileName!=md->getDefFileName();
2564 
2565  if (md->getFileDef() &&
2566  !isPHPArray && // not a php array
2567  !staticsInDifferentFiles
2568  )
2569  // not a php array variable
2570  {
2571 
2573  " variable already found: scope=%s\n",qPrint(md->getOuterScope()->name()));
2574  addMemberDocs(rootNav,md,def,0,FALSE);
2575  md->setRefItems(root->sli);
2576  return md;
2577  }
2578  }
2579  }
2580  }
2581 
2582  QCString fileName = root->fileName;
2583  if (fileName.isEmpty() && rootNav->tagInfo())
2584  {
2585  fileName = rootNav->tagInfo()->tagName;
2586  }
2587 
2589  " new variable, nd=%s!\n",nd?qPrint(nd->name()):"<global>");
2590  // new global variable, enum value or typedef
2591  MemberDef *md=new MemberDef(
2592  fileName,root->startLine,root->startColumn,
2593  root->type,name,root->args,0,
2594  root->protection, Normal,root->stat,Member,
2595  mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2596  md->setTagInfo(rootNav->tagInfo());
2597  md->setMemberSpecifiers(root->spec);
2598  md->setDocumentation(root->doc,root->docFile,root->docLine);
2599  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2600  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2601  md->addSectionsToDefinition(root->anchors);
2602  md->setFromAnonymousScope(fromAnnScope);
2603  md->setFromAnonymousMember(fromAnnMemb);
2604  md->setInitializer(root->initializer);
2605  md->setMaxInitLines(root->initLines);
2606  md->setMemberGroupId(root->mGrpId);
2607  md->setDefinition(def);
2608  md->setLanguage(root->lang);
2609  md->setId(root->id);
2610  md->enableCallGraph(root->callGraph);
2611  md->enableCallerGraph(root->callerGraph);
2613  //md->setOuterScope(fd);
2614  if (!root->explicitExternal)
2615  {
2616  md->setBodySegment(root->bodyLine,root->endBodyLine);
2617  md->setBodyDef(fd);
2618  }
2619  addMemberToGroups(root,md);
2620 
2621  md->setRefItems(root->sli);
2622  if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2623  {
2624  md->setNamespace(nd);
2625  nd->insertMember(md);
2626  }
2627 
2628  // add member to the file (we do this even if we have already inserted
2629  // it into the namespace.
2630  if (fd)
2631  {
2632  md->setFileDef(fd);
2633  fd->insertMember(md);
2634  }
2635 
2636  // add member definition to the list of globals
2637  if (mn)
2638  {
2639  mn->append(md);
2640  }
2641  else
2642  {
2643  mn = new MemberName(name);
2644  mn->append(md);
2645  Doxygen::functionNameSDict->append(name,mn);
2646  }
2647  rootNav->changeSection(Entry::EMPTY_SEC);
2648  return md;
2649 }
2650 
2655 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2656 {
2657  if (lang == SrcLangExt_Fortran || lang == SrcLangExt_VHDL)
2658  {
2659  return -1; // Fortran and VHDL do not have function pointers
2660  }
2661  static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2662  int i=-1,l;
2663  int bb=type.find('<');
2664  int be=type.findRev('>');
2665  if (!type.isEmpty() && // return type is non-empty
2666  (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2667  type.find("operator")==-1 && // not an operator
2668  (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2669  // not a function pointer return type
2670  !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2671  )
2672  {
2673  if (pLength) *pLength=l;
2674  //printf("findFunctionPtr=%d\n",i);
2675  return i;
2676  }
2677  else
2678  {
2679  //printf("findFunctionPtr=%d\n",-1);
2680  return -1;
2681  }
2682 }
2683 
2684 
2688 static bool isVarWithConstructor(EntryNav *rootNav)
2689 {
2690  static QRegExp initChars("[0-9\"'&*!^]+");
2691  static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2692  bool result=FALSE;
2693  bool typeIsClass;
2694  QCString type;
2695  Definition *ctx = 0;
2696  FileDef *fd = 0;
2697  int ti;
2698 
2699  //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2700  rootNav->loadEntry(g_storage);
2701  Entry *root = rootNav->entry();
2702 
2703  if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2704  { // inside a class
2705  result=FALSE;
2706  goto done;
2707  }
2708  else if ((fd = rootNav->fileDef()) &&
2709  (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2710  )
2711  { // inside a .c file
2712  result=FALSE;
2713  goto done;
2714  }
2715  if (root->type.isEmpty())
2716  {
2717  result=FALSE;
2718  goto done;
2719  }
2720  if (!rootNav->parent()->name().isEmpty())
2721  {
2722  ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2723  }
2724  type = root->type;
2725  // remove qualifiers
2726  findAndRemoveWord(type,"const");
2727  findAndRemoveWord(type,"static");
2728  findAndRemoveWord(type,"volatile");
2729  //if (type.left(6)=="const ") type=type.right(type.length()-6);
2730  typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2731  if (!typeIsClass && (ti=type.find('<'))!=-1)
2732  {
2733  typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2734  }
2735  if (typeIsClass) // now we still have to check if the arguments are
2736  // types or values. Since we do not have complete type info
2737  // we need to rely on heuristics :-(
2738  {
2739  //printf("typeIsClass\n");
2740  ArgumentList *al = root->argList;
2741  if (al==0 || al->isEmpty())
2742  {
2743  result=FALSE; // empty arg list -> function prototype.
2744  goto done;
2745  }
2746  ArgumentListIterator ali(*al);
2747  Argument *a;
2748  for (ali.toFirst();(a=ali.current());++ali)
2749  {
2750  if (!a->name.isEmpty() || !a->defval.isEmpty())
2751  {
2752  if (a->name.find(initChars)==0)
2753  {
2754  result=TRUE;
2755  }
2756  else
2757  {
2758  result=FALSE; // arg has (type,name) pair -> function prototype
2759  }
2760  goto done;
2761  }
2762  if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0)
2763  {
2764  result=FALSE; // arg type is a known type
2765  goto done;
2766  }
2767  if (checkIfTypedef(ctx,fd,a->type))
2768  {
2769  //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2770  result=FALSE; // argument is a typedef
2771  goto done;
2772  }
2773  if (a->type.at(a->type.length()-1)=='*' ||
2774  a->type.at(a->type.length()-1)=='&')
2775  // type ends with * or & => pointer or reference
2776  {
2777  result=FALSE;
2778  goto done;
2779  }
2780  if (a->type.find(initChars)==0)
2781  {
2782  result=TRUE; // argument type starts with typical initializer char
2783  goto done;
2784  }
2785  QCString resType=resolveTypeDef(ctx,a->type);
2786  if (resType.isEmpty()) resType=a->type;
2787  int len;
2788  if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2789  {
2790  resType=resType.left(len);
2791  //printf("resType=%s\n",resType.data());
2792  if (resType=="int" || resType=="long" || resType=="float" ||
2793  resType=="double" || resType=="char" || resType=="signed" ||
2794  resType=="const" || resType=="unsigned" || resType=="void")
2795  {
2796  result=FALSE; // type keyword -> function prototype
2797  goto done;
2798  }
2799  }
2800  }
2801  result=TRUE;
2802  }
2803 
2804 done:
2805  //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2806  // root->type.data(),result);
2807  rootNav->releaseEntry();
2808  return result;
2809 }
2810 
2811 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2812 {
2813  rootNav->loadEntry(g_storage);
2814  Entry *root = rootNav->entry();
2815 
2817  "VARIABLE_SEC: \n"
2818  " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2819  qPrint(root->type),
2820  qPrint(root->name),
2821  qPrint(root->args),
2822  root->bodyLine,
2823  root->mGrpId,
2824  qPrint(root->relates)
2825  );
2826  //printf("root->parent->name=%s\n",root->parent->name.data());
2827 
2828  if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2829  (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2830  {
2831  // recover from parse error caused by redundant braces
2832  // like in "int *(var[10]);", which is parsed as
2833  // type="" name="int *" args="(var[10])"
2834 
2835  root->type=root->name;
2836  static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2837  int l=0;
2838  int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2839  if (i!=-1)
2840  {
2841  root->name=root->args.mid(i,l);
2842  root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2843  }
2844  //printf("new: type=`%s' name=`%s' args=`%s'\n",
2845  // root->type.data(),root->name.data(),root->args.data());
2846  }
2847  else
2848  {
2849  int i=isFuncPtr;
2850  if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2851  Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no");
2852  if (i!=-1) // function pointer
2853  {
2854  int ai = root->type.find('[',i);
2855  if (ai>i) // function pointer array
2856  {
2857  root->args.prepend(root->type.right(root->type.length()-ai));
2858  root->type=root->type.left(ai);
2859  }
2860  else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2861  {
2862  root->type=root->type.left(root->type.length()-1);
2863  root->args.prepend(") ");
2864  //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2865  }
2866  }
2867  else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
2868  {
2869  root->type=root->type.left(root->type.length()-1);
2870  root->args.prepend(") ");
2871  }
2872  }
2873 
2874  QCString scope,name=removeRedundantWhiteSpace(root->name);
2875 
2876  // find the scope of this variable
2877  EntryNav *p = rootNav->parent();
2878  while ((p->section() & Entry::SCOPE_MASK))
2879  {
2880  QCString scopeName = p->name();
2881  if (!scopeName.isEmpty())
2882  {
2883  scope.prepend(scopeName);
2884  break;
2885  }
2886  p=p->parent();
2887  }
2888 
2889  MemberType mtype;
2890  QCString type=root->type.stripWhiteSpace();
2891  ClassDef *cd=0;
2892  bool isRelated=FALSE;
2893  bool isMemberOf=FALSE;
2894 
2895  QCString classScope=stripAnonymousNamespaceScope(scope);
2896  classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2897  QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2898 
2899  if (root->name.findRev("::")!=-1)
2900  {
2901  if (root->type=="friend class" || root->type=="friend struct" ||
2902  root->type=="friend union")
2903  {
2904  cd=getClass(scope);
2905  if (cd)
2906  {
2907  addVariableToClass(rootNav, // entry
2908  cd, // class to add member to
2909  MemberType_Friend, // type of member
2910  name, // name of the member
2911  FALSE, // from Anonymous scope
2912  0, // anonymous member
2913  Public, // protection
2914  Member // related to a class
2915  );
2916  }
2917  }
2918  goto nextMember;
2919  /* skip this member, because it is a
2920  * static variable definition (always?), which will be
2921  * found in a class scope as well, but then we know the
2922  * correct protection level, so only then it will be
2923  * inserted in the correct list!
2924  */
2925  }
2926 
2927  if (type=="@")
2928  mtype=MemberType_EnumValue;
2929  else if (type.left(8)=="typedef ")
2930  mtype=MemberType_Typedef;
2931  else if (type.left(7)=="friend ")
2932  mtype=MemberType_Friend;
2933  else if (root->mtype==Property)
2934  mtype=MemberType_Property;
2935  else if (root->mtype==Event)
2936  mtype=MemberType_Event;
2937  else
2938  mtype=MemberType_Variable;
2939 
2940  if (!root->relates.isEmpty()) // related variable
2941  {
2942  isRelated=TRUE;
2943  isMemberOf=(root->relatesType == MemberOf);
2944  if (getClass(root->relates)==0 && !scope.isEmpty())
2945  scope=mergeScopes(scope,root->relates);
2946  else
2947  scope=root->relates;
2948  }
2949 
2950  cd=getClass(scope);
2951  if (cd==0 && classScope!=scope) cd=getClass(classScope);
2952  if (cd)
2953  {
2954  MemberDef *md=0;
2955 
2956  // if cd is an anonymous (=tag less) scope we insert the member
2957  // into a non-anonymous parent scope as well. This is needed to
2958  // be able to refer to it using \var or \fn
2959 
2960  //int indentDepth=0;
2961  int si=scope.find('@');
2962  //int anonyScopes = 0;
2963  //bool added=FALSE;
2964 
2965  static bool inlineSimpleStructs = Config_getBool(INLINE_SIMPLE_STRUCTS);
2966  if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2967  {
2968  QCString pScope;
2969  ClassDef *pcd=0;
2970  pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2971  if (!pScope.isEmpty())
2972  pScope.prepend(annScopePrefix);
2973  else if (annScopePrefix.length()>2)
2974  pScope=annScopePrefix.left(annScopePrefix.length()-2);
2975  if (name.at(0)!='@')
2976  {
2977  if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2978  {
2979  md=addVariableToClass(rootNav, // entry
2980  pcd, // class to add member to
2981  mtype, // member type
2982  name, // member name
2983  TRUE, // from anonymous scope
2984  0, // from anonymous member
2985  root->protection,
2986  isMemberOf ? Foreign : isRelated ? Related : Member
2987  );
2988  //added=TRUE;
2989  }
2990  else // anonymous scope inside namespace or file => put variable in the global scope
2991  {
2992  if (mtype==MemberType_Variable)
2993  {
2994  md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0);
2995  }
2996  //added=TRUE;
2997  }
2998  }
2999  }
3000 
3001  //printf("name=`%s' scope=%s scope.right=%s\n",
3002  // name.data(),scope.data(),
3003  // scope.right(scope.length()-si).data());
3004  addVariableToClass(rootNav, // entry
3005  cd, // class to add member to
3006  mtype, // member type
3007  name, // name of the member
3008  FALSE, // from anonymous scope
3009  md, // from anonymous member
3010  root->protection,
3011  isMemberOf ? Foreign : isRelated ? Related : Member);
3012  }
3013  else if (!name.isEmpty()) // global variable
3014  {
3015  //printf("Inserting member in global scope %s!\n",scope.data());
3016  addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
3017  }
3018 
3019 nextMember:
3020  rootNav->releaseEntry();
3021 }
3022 
3023 //----------------------------------------------------------------------
3024 // Searches the Entry tree for typedef documentation sections.
3025 // If found they are stored in their class or in the global list.
3026 static void buildTypedefList(EntryNav *rootNav)
3027 {
3028  //printf("buildVarList(%s)\n",rootNav->name().data());
3029  if (!rootNav->name().isEmpty() &&
3030  rootNav->section()==Entry::VARIABLE_SEC &&
3031  rootNav->type().find("typedef ")!=-1 // its a typedef
3032  )
3033  {
3034  addVariable(rootNav);
3035  }
3036  if (rootNav->children())
3037  {
3038  EntryNavListIterator eli(*rootNav->children());
3039  EntryNav *e;
3040  for (;(e=eli.current());++eli)
3041  {
3042  if (e->section()!=Entry::ENUM_SEC)
3043  {
3044  buildTypedefList(e);
3045  }
3046  }
3047  }
3048 }
3049 
3050 //----------------------------------------------------------------------
3051 // Searches the Entry tree for Variable documentation sections.
3052 // If found they are stored in their class or in the global list.
3053 
3054 static void buildVarList(EntryNav *rootNav)
3055 {
3056  //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
3057  int isFuncPtr=-1;
3058  if (!rootNav->name().isEmpty() &&
3059  (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
3060  (
3061  (rootNav->section()==Entry::VARIABLE_SEC // it's a variable
3062  ) ||
3063  (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable
3064  (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
3065  ) ||
3066  (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
3067  isVarWithConstructor(rootNav)
3068  )
3069  )
3070  ) // documented variable
3071  {
3072  addVariable(rootNav,isFuncPtr);
3073  }
3074  if (rootNav->children())
3075  {
3076  EntryNavListIterator eli(*rootNav->children());
3077  EntryNav *e;
3078  for (;(e=eli.current());++eli)
3079  {
3080  if (e->section()!=Entry::ENUM_SEC)
3081  {
3082  buildVarList(e);
3083  }
3084  }
3085  }
3086 }
3087 
3088 //----------------------------------------------------------------------
3089 // Searches the Entry tree for Interface sections (UNO IDL only).
3090 // If found they are stored in their service or in the global list.
3091 //
3092 
3094  EntryNav *const rootNav,
3095  ClassDef *const cd,
3096  QCString const& rname)
3097 {
3098  Entry *const root = rootNav->entry();
3099  FileDef *const fd = rootNav->fileDef();
3100  enum MemberType const type = (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC)
3103  QCString fileName = root->fileName;
3104  if (fileName.isEmpty() && rootNav->tagInfo())
3105  {
3106  fileName = rootNav->tagInfo()->tagName;
3107  }
3108  MemberDef *const md = new MemberDef(
3109  fileName, root->startLine, root->startColumn, root->type, rname,
3110  "", "", root->protection, root->virt, root->stat, Member,
3111  type, 0, root->argList);
3112  md->setTagInfo(rootNav->tagInfo());
3113  md->setMemberClass(cd);
3114  md->setDocumentation(root->doc,root->docFile,root->docLine);
3115  md->setDocsForDefinition(false);
3116  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3117  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3118  md->setBodySegment(root->bodyLine,root->endBodyLine);
3119  md->setMemberSpecifiers(root->spec);
3120  md->setMemberGroupId(root->mGrpId);
3121  md->setTypeConstraints(root->typeConstr);
3122  md->setLanguage(root->lang);
3123  md->setBodyDef(fd);
3124  md->setFileDef(fd);
3125  md->addSectionsToDefinition(root->anchors);
3126  QCString const def = root->type + " " + rname;
3127  md->setDefinition(def);
3128  md->enableCallGraph(root->callGraph);
3129  md->enableCallerGraph(root->callerGraph);
3130 
3132  " Interface Member:\n"
3133  " `%s' `%s' proto=%d\n"
3134  " def=`%s'\n",
3135  qPrint(root->type),
3136  qPrint(rname),
3137  root->proto,
3138  qPrint(def)
3139  );
3140 
3141  // add member to the global list of all members
3142  MemberName *mn;
3143  if ((mn=Doxygen::memberNameSDict->find(rname)))
3144  {
3145  mn->append(md);
3146  }
3147  else
3148  {
3149  mn = new MemberName(rname);
3150  mn->append(md);
3151  Doxygen::memberNameSDict->append(rname,mn);
3152  }
3153 
3154  // add member to the class cd
3155  cd->insertMember(md);
3156  // also add the member as a "base" (to get nicer diagrams)
3157  // "optional" interface/service get Protected which turns into dashed line
3158  BaseInfo base(rname,
3159  (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3160  findClassRelation(rootNav,cd,cd,&base,0,DocumentedOnly,true)
3161  || findClassRelation(rootNav,cd,cd,&base,0,Undocumented,true);
3162  // add file to list of used files
3163  cd->insertUsedFile(fd);
3164 
3165  addMemberToGroups(root,md);
3166  rootNav->changeSection(Entry::EMPTY_SEC);
3167  md->setRefItems(root->sli);
3168 }
3169 
3170 static void buildInterfaceAndServiceList(EntryNav *const rootNav)
3171 {
3172  if (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
3174  {
3175  rootNav->loadEntry(g_storage);
3176  Entry *const root = rootNav->entry();
3177 
3179  "EXPORTED_INTERFACE_SEC:\n"
3180  " `%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",
3181  qPrint(root->type),
3182  qPrint(rootNav->parent()->name()),
3183  qPrint(root->name),
3184  qPrint(root->args),
3185  qPrint(root->relates),
3186  root->relatesType,
3187  qPrint(root->fileName),
3188  root->startLine,
3189  root->bodyLine,
3190  root->tArgLists ? (int)root->tArgLists->count() : -1,
3191  root->mGrpId,
3192  root->spec,
3193  root->proto,
3194  qPrint(root->docFile)
3195  );
3196 
3197  QCString const rname = removeRedundantWhiteSpace(root->name);
3198 
3199  if (!rname.isEmpty())
3200  {
3201  QCString const scope = rootNav->parent()->name();
3202  ClassDef *const cd = getClass(scope);
3203  assert(cd);
3204  if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3205  (ClassDef::Service == cd->compoundType()) ||
3206  (ClassDef::Singleton == cd->compoundType())))
3207  {
3209  }
3210  else
3211  {
3212  assert(false); // was checked by scanner.l
3213  }
3214  }
3215  else if (rname.isEmpty())
3216  {
3217  warn(root->fileName,root->startLine,
3218  "Illegal member name found.");
3219  }
3220 
3221  rootNav->releaseEntry();
3222  }
3223  // can only have these in IDL anyway
3224  switch (rootNav->lang())
3225  {
3226  case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3227  case SrcLangExt_IDL:
3229  break;
3230  default:
3231  return; // nothing to do here
3232  }
3233 }
3234 
3235 
3236 //----------------------------------------------------------------------
3237 // Searches the Entry tree for Function sections.
3238 // If found they are stored in their class or in the global list.
3239 
3240 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
3241  const QCString &rname,bool isFriend)
3242 {
3243  Entry *root = rootNav->entry();
3244  FileDef *fd=rootNav->fileDef();
3245 
3246  int l;
3247  static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3248  int ts=root->type.find('<');
3249  int te=root->type.findRev('>');
3250  int i=re.match(root->type,0,&l);
3251  if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
3252  {
3253  i=-1;
3254  }
3255 
3256  if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3257  !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3258  {
3259  root->args+=root->type.right(root->type.length()-i-l);
3260  root->type=root->type.left(i+l);
3261  }
3262 
3263  QCString name=removeRedundantWhiteSpace(rname);
3264  if (name.left(2)=="::") name=name.right(name.length()-2);
3265 
3266  MemberType mtype;
3267  if (isFriend) mtype=MemberType_Friend;
3268  else if (root->mtype==Signal) mtype=MemberType_Signal;
3269  else if (root->mtype==Slot) mtype=MemberType_Slot;
3270  else if (root->mtype==DCOP) mtype=MemberType_DCOP;
3271  else mtype=MemberType_Function;
3272 
3273  // strip redundant template specifier for constructors
3274  if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3275  name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3276  {
3277  name=name.left(i);
3278  }
3279 
3280  QCString fileName = root->fileName;
3281  if (fileName.isEmpty() && rootNav->tagInfo())
3282  {
3283  fileName = rootNav->tagInfo()->tagName;
3284  }
3285 
3286  //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
3287  // root->name.data(),root->args.data(),argListToString(root->argList).data()
3288  // );
3289 
3290  // adding class member
3291  MemberDef *md=new MemberDef(
3292  fileName,root->startLine,root->startColumn,
3293  root->type,name,root->args,root->exception,
3294  root->protection,root->virt,
3295  root->stat && root->relatesType != MemberOf,
3296  root->relates.isEmpty() ? Member :
3297  root->relatesType == MemberOf ? Foreign : Related,
3298  mtype,root->tArgLists ? root->tArgLists->getLast() : 0,root->argList);
3299  md->setTagInfo(rootNav->tagInfo());
3300  md->setMemberClass(cd);
3301  md->setDocumentation(root->doc,root->docFile,root->docLine);
3302  md->setDocsForDefinition(!root->proto);
3303  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3304  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3305  md->setBodySegment(root->bodyLine,root->endBodyLine);
3306  md->setMemberSpecifiers(root->spec);
3307  md->setMemberGroupId(root->mGrpId);
3308  md->setTypeConstraints(root->typeConstr);
3309  md->setLanguage(root->lang);
3310  md->setId(root->id);
3311  md->setBodyDef(fd);
3312  md->setFileDef(fd);
3313  //md->setScopeTemplateArguments(root->tArgList);
3314  md->addSectionsToDefinition(root->anchors);
3315  QCString def;
3316  QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3317  SrcLangExt lang = cd->getLanguage();
3318  QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3319  if (scopeSeparator!="::")
3320  {
3321  qualScope = substitute(qualScope,"::",scopeSeparator);
3322  }
3323  if (lang==SrcLangExt_PHP)
3324  {
3325  // for PHP we use Class::method and Namespace\method
3326  scopeSeparator="::";
3327  }
3328  if (!root->relates.isEmpty() || isFriend || Config_getBool(HIDE_SCOPE_NAMES))
3329  {
3330  if (!root->type.isEmpty())
3331  {
3332  if (root->argList)
3333  {
3334  def=root->type+" "+name;
3335  }
3336  else
3337  {
3338  def=root->type+" "+name+root->args;
3339  }
3340  }
3341  else
3342  {
3343  if (root->argList)
3344  {
3345  def=name;
3346  }
3347  else
3348  {
3349  def=name+root->args;
3350  }
3351  }
3352  }
3353  else
3354  {
3355  if (!root->type.isEmpty())
3356  {
3357  if (root->argList)
3358  {
3359  def=root->type+" "+qualScope+scopeSeparator+name;
3360  }
3361  else
3362  {
3363  def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3364  }
3365  }
3366  else
3367  {
3368  if (root->argList)
3369  {
3370  def=qualScope+scopeSeparator+name;
3371  }
3372  else
3373  {
3374  def=qualScope+scopeSeparator+name+root->args;
3375  }
3376  }
3377  }
3378  if (def.left(7)=="friend ") def=def.right(def.length()-7);
3379  md->setDefinition(def);
3380  md->enableCallGraph(root->callGraph);
3381  md->enableCallerGraph(root->callerGraph);
3382 
3384  " Func Member:\n"
3385  " `%s' `%s'::`%s' `%s' proto=%d\n"
3386  " def=`%s'\n",
3387  qPrint(root->type),
3388  qPrint(qualScope),
3389  qPrint(rname),
3390  qPrint(root->args),
3391  root->proto,
3392  qPrint(def)
3393  );
3394 
3395  // add member to the global list of all members
3396  //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3397  MemberName *mn;
3398  if ((mn=Doxygen::memberNameSDict->find(name)))
3399  {
3400  mn->append(md);
3401  }
3402  else
3403  {
3404  mn = new MemberName(name);
3405  mn->append(md);
3406  Doxygen::memberNameSDict->append(name,mn);
3407  }
3408 
3409  // add member to the class cd
3410  cd->insertMember(md);
3411  // add file to list of used files
3412  cd->insertUsedFile(fd);
3413 
3414  addMemberToGroups(root,md);
3415  rootNav->changeSection(Entry::EMPTY_SEC);
3416  md->setRefItems(root->sli);
3417 }
3418 
3419 
3420 static void buildFunctionList(EntryNav *rootNav)
3421 {
3422  if (rootNav->section()==Entry::FUNCTION_SEC)
3423  {
3424  rootNav->loadEntry(g_storage);
3425  Entry *root = rootNav->entry();
3426 
3428  "FUNCTION_SEC:\n"
3429  " `%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",
3430  qPrint(root->type),
3431  qPrint(rootNav->parent()->name()),
3432  qPrint(root->name),
3433  qPrint(root->args),
3434  qPrint(root->relates),
3435  root->relatesType,
3436  qPrint(root->fileName),
3437  root->startLine,
3438  root->bodyLine,
3439  root->tArgLists ? (int)root->tArgLists->count() : -1,
3440  root->mGrpId,
3441  root->spec,
3442  root->proto,
3443  qPrint(root->docFile)
3444  );
3445 
3446  bool isFriend=root->type.find("friend ")!=-1;
3447  QCString rname = removeRedundantWhiteSpace(root->name);
3448  //printf("rname=%s\n",rname.data());
3449 
3450  QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3451  if (!rname.isEmpty() && scope.find('@')==-1)
3452  {
3453  ClassDef *cd=0;
3454  // check if this function's parent is a class
3455  scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3456 
3457  FileDef *rfd=rootNav->fileDef();
3458 
3459  int memIndex=rname.findRev("::");
3460 
3461  cd=getClass(scope);
3462  if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3463  {
3464  // strip scope from name
3465  rname=rname.right(rname.length()-rootNav->parent()->name().length()-2);
3466  }
3467 
3468  NamespaceDef *nd = 0;
3469  bool isMember=FALSE;
3470  if (memIndex!=-1)
3471  {
3472  int ts=rname.find('<');
3473  int te=rname.find('>');
3474  if (memIndex>0 && (ts==-1 || te==-1))
3475  {
3476  // note: the following code was replaced by inMember=TRUE to deal with a
3477  // function rname='X::foo' of class X inside a namespace also called X...
3478  // bug id 548175
3479  //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3480  //isMember = nd==0;
3481  //if (nd)
3482  //{
3483  // // strip namespace scope from name
3484  // scope=rname.left(memIndex);
3485  // rname=rname.right(rname.length()-memIndex-2);
3486  //}
3487  isMember = TRUE;
3488  }
3489  else
3490  {
3491  isMember=memIndex<ts || memIndex>te;
3492  }
3493  }
3494 
3495  static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3496  int ts=root->type.find('<');
3497  int te=root->type.findRev('>');
3498  int ti;
3499  if (!rootNav->parent()->name().isEmpty() &&
3500  (rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
3501  cd &&
3502  // do some fuzzy things to exclude function pointers
3503  (root->type.isEmpty() ||
3504  ((ti=root->type.find(re,0))==-1 || // type does not contain ..(..*
3505  (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3506  root->args.find(")[")!=-1) || // and args not )[.. -> function pointer
3507  root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3508  cd->getLanguage()!=SrcLangExt_Cpp // language other than C
3509  )
3510  )
3511  {
3512  Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
3513  qPrint(rname),qPrint(cd->name()));
3514  addMethodToClass(rootNav,cd,rname,isFriend);
3515  }
3516  else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK)
3517  || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3518  ) &&
3519  !isMember &&
3520  (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3521  root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3522  )
3523  // no member => unrelated function
3524  {
3525  /* check the uniqueness of the function name in the file.
3526  * A file could contain a function prototype and a function definition
3527  * or even multiple function prototypes.
3528  */
3529  bool found=FALSE;
3530  MemberName *mn;
3531  MemberDef *md=0;
3532  if ((mn=Doxygen::functionNameSDict->find(rname)))
3533  {
3534  Debug::print(Debug::Functions,0," --> function %s already found!\n",qPrint(rname));
3535  MemberNameIterator mni(*mn);
3536  for (mni.toFirst();(!found && (md=mni.current()));++mni)
3537  {
3538  NamespaceDef *mnd = md->getNamespaceDef();
3539  NamespaceDef *rnd = 0;
3540  //printf("root namespace=%s\n",rootNav->parent()->name().data());
3541  QCString fullScope = scope;
3542  QCString parentScope = rootNav->parent()->name();
3543  if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3544  {
3545  if (!scope.isEmpty()) fullScope.prepend("::");
3546  fullScope.prepend(parentScope);
3547  }
3548  //printf("fullScope=%s\n",fullScope.data());
3549  rnd = getResolvedNamespace(fullScope);
3550  FileDef *mfd = md->getFileDef();
3551  QCString nsName,rnsName;
3552  if (mnd) nsName = mnd->name().copy();
3553  if (rnd) rnsName = rnd->name().copy();
3554  //printf("matching arguments for %s%s %s%s\n",
3555  // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3556  ArgumentList *mdAl = md->argumentList();
3557  ArgumentList *mdTempl = md->templateArguments();
3558 
3559  // in case of template functions, we need to check if the
3560  // functions have the same number of template parameters
3561  bool sameNumTemplateArgs = TRUE;
3562  bool matchingReturnTypes = TRUE;
3563  if (mdTempl!=0 && root->tArgLists)
3564  {
3565  if (mdTempl->count()!=root->tArgLists->getLast()->count())
3566  {
3567  sameNumTemplateArgs = FALSE;
3568  }
3569  if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3570  {
3571  matchingReturnTypes = FALSE;
3572  }
3573  }
3574 
3575  bool staticsInDifferentFiles =
3576  root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3577 
3578  if (
3579  matchArguments2(md->getOuterScope(),mfd,mdAl,
3580  rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3581  FALSE) &&
3582  sameNumTemplateArgs &&
3583  matchingReturnTypes &&
3584  !staticsInDifferentFiles
3585  )
3586  {
3587  GroupDef *gd=0;
3588  if (root->groups->getFirst()!=0)
3589  {
3590  gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
3591  }
3592  //printf("match!\n");
3593  //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3594  // see if we need to create a new member
3595  found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace
3596  ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and
3597  mfd->absFilePath()==root->fileName // prototype in the same file
3598  )
3599  );
3600  // otherwise, allow a duplicate global member with the same argument list
3601  if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3602  {
3603  // member is already in the group, so we don't want to add it again.
3604  found=TRUE;
3605  }
3606 
3607  //printf("combining function with prototype found=%d in namespace %s\n",
3608  // found,nsName.data());
3609 
3610  if (found)
3611  {
3612  // merge argument lists
3613  mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
3614  // merge documentation
3615  if (md->documentation().isEmpty() && !root->doc.isEmpty())
3616  {
3617  ArgumentList *argList = new ArgumentList;
3618  stringToArgumentList(root->args,argList);
3619  if (root->proto)
3620  {
3621  //printf("setDeclArgumentList to %p\n",argList);
3622  md->setDeclArgumentList(argList);
3623  }
3624  else
3625  {
3626  md->setArgumentList(argList);
3627  }
3628  }
3629 
3630  md->setDocumentation(root->doc,root->docFile,root->docLine);
3631  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3632  md->setDocsForDefinition(!root->proto);
3633  if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3634  {
3635  md->setBodySegment(root->bodyLine,root->endBodyLine);
3636  md->setBodyDef(rfd);
3637  }
3638 
3639  if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3640  {
3641  md->setArgsString(root->args);
3642  }
3643  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3644 
3645  md->addSectionsToDefinition(root->anchors);
3646 
3647  md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3648  md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3649 
3650  // merge ingroup specifiers
3651  if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
3652  {
3653  addMemberToGroups(root,md);
3654  }
3655  else if (md->getGroupDef()!=0 && root->groups->count()==0)
3656  {
3657  //printf("existing member is grouped, new member not\n");
3658  root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3659  }
3660  else if (md->getGroupDef()!=0 && root->groups->getFirst()!=0)
3661  {
3662  //printf("both members are grouped\n");
3663  }
3664 
3665  // if md is a declaration and root is the corresponding
3666  // definition, then turn md into a definition.
3667  if (md->isPrototype() && !root->proto)
3668  {
3669  md->setPrototype(FALSE);
3670  }
3671  }
3672  }
3673  }
3674  }
3675  if (!found) /* global function is unique with respect to the file */
3676  {
3677  Debug::print(Debug::Functions,0," --> new function %s found!\n",qPrint(rname));
3678  //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3679  // root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3680 
3681  // new global function
3682  ArgumentList *tArgList = root->tArgLists ? root->tArgLists->getLast() : 0;
3683  QCString name=removeRedundantWhiteSpace(rname);
3684  md=new MemberDef(
3685  root->fileName,root->startLine,root->startColumn,
3686  root->type,name,root->args,root->exception,
3687  root->protection,root->virt,root->stat,Member,
3688  MemberType_Function,tArgList,root->argList);
3689 
3690  md->setTagInfo(rootNav->tagInfo());
3691  md->setLanguage(root->lang);
3692  md->setId(root->id);
3693  //md->setDefFile(root->fileName);
3694  //md->setDefLine(root->startLine);
3695  md->setDocumentation(root->doc,root->docFile,root->docLine);
3696  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3697  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3698  md->setPrototype(root->proto);
3699  md->setDocsForDefinition(!root->proto);
3700  md->setTypeConstraints(root->typeConstr);
3701  //md->setBody(root->body);
3702  md->setBodySegment(root->bodyLine,root->endBodyLine);
3703  FileDef *fd=rootNav->fileDef();
3704  md->setBodyDef(fd);
3705  md->addSectionsToDefinition(root->anchors);
3706  md->setMemberSpecifiers(root->spec);
3707  md->setMemberGroupId(root->mGrpId);
3708 
3709  // see if the function is inside a namespace that was not part of
3710  // the name already (in that case nd should be non-zero already)
3711  if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3712  {
3713  //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3714  QCString nscope=rootNav->parent()->name();
3715  if (!nscope.isEmpty())
3716  {
3717  nd = getResolvedNamespace(nscope);
3718  }
3719  }
3720 
3721  if (!scope.isEmpty())
3722  {
3723  QCString sep = getLanguageSpecificSeparator(root->lang);
3724  if (sep!="::")
3725  {
3726  scope = substitute(scope,"::",sep);
3727  }
3728  scope+=sep;
3729  }
3730 
3731  QCString def;
3732  if (!root->type.isEmpty())
3733  {
3734  if (root->argList)
3735  {
3736  def=root->type+" "+scope+name;
3737  }
3738  else
3739  {
3740  def=root->type+" "+scope+name+root->args;
3741  }
3742  }
3743  else
3744  {
3745  if (root->argList)
3746  {
3747  def=scope+name.copy();
3748  }
3749  else
3750  {
3751  def=scope+name+root->args;
3752  }
3753  }
3755  " Global Function:\n"
3756  " `%s' `%s'::`%s' `%s' proto=%d\n"
3757  " def=`%s'\n",
3758  qPrint(root->type),
3759  qPrint(rootNav->parent()->name()),
3760  qPrint(rname),
3761  qPrint(root->args),
3762  root->proto,
3763  qPrint(def)
3764  );
3765  md->setDefinition(def);
3766  md->enableCallGraph(root->callGraph);
3767  md->enableCallerGraph(root->callerGraph);
3768  //if (root->mGrpId!=-1)
3769  //{
3770  // md->setMemberGroup(memberGroupDict[root->mGrpId]);
3771  //}
3772 
3773  md->setRefItems(root->sli);
3774  if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3775  {
3776  // add member to namespace
3777  md->setNamespace(nd);
3778  nd->insertMember(md);
3779  }
3780  if (fd)
3781  {
3782  // add member to the file (we do this even if we have already
3783  // inserted it into the namespace)
3784  md->setFileDef(fd);
3785  fd->insertMember(md);
3786  }
3787 
3788  // add member to the list of file members
3789  //printf("Adding member=%s\n",md->name().data());
3790  MemberName *mn;
3791  if ((mn=Doxygen::functionNameSDict->find(name)))
3792  {
3793  mn->append(md);
3794  }
3795  else
3796  {
3797  mn = new MemberName(name);
3798  mn->append(md);
3799  Doxygen::functionNameSDict->append(name,mn);
3800  }
3801  addMemberToGroups(root,md);
3802  if (root->relatesType == Simple) // if this is a relatesalso command,
3803  // allow find Member to pick it up
3804  {
3805  rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished
3806  // with this entry.
3807 
3808  }
3809  }
3810  else
3811  {
3812  FileDef *fd=rootNav->fileDef();
3813  if (fd)
3814  {
3815  // add member to the file (we do this even if we have already
3816  // inserted it into the namespace)
3817  fd->insertMember(md);
3818  }
3819  }
3820 
3821  //printf("unrelated function %d `%s' `%s' `%s'\n",
3822  // root->parent->section,root->type.data(),rname.data(),root->args.data());
3823  }
3824  else
3825  {
3826  Debug::print(Debug::Functions,0," --> %s not processed!\n",qPrint(rname));
3827  }
3828  }
3829  else if (rname.isEmpty())
3830  {
3831  warn(root->fileName,root->startLine,
3832  "Illegal member name found."
3833  );
3834  }
3835 
3836  rootNav->releaseEntry();
3837  }
3839 }
3840 
3841 //----------------------------------------------------------------------
3842 
3843 static void findFriends()
3844 {
3845  //printf("findFriends()\n");
3846  MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3847  MemberName *fn;
3848  for (;(fn=fnli.current());++fnli) // for each global function name
3849  {
3850  //printf("Function name=`%s'\n",fn->memberName());
3851  MemberName *mn;
3852  if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3853  { // there are members with the same name
3854  //printf("Function name is also a member name\n");
3855  MemberNameIterator fni(*fn);
3856  MemberDef *fmd;
3857  for (;(fmd=fni.current());++fni) // for each function with that name
3858  {
3859  MemberNameIterator mni(*mn);
3860  MemberDef *mmd;
3861  for (;(mmd=mni.current());++mni) // for each member with that name
3862  {
3863  //printf("Checking for matching arguments
3864  // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3865  // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3866  ArgumentList *mmdAl = mmd->argumentList();
3867  ArgumentList *fmdAl = fmd->argumentList();
3868  if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3869  matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl,
3870  fmd->getOuterScope(), fmd->getFileDef(), fmdAl,
3871  TRUE
3872  )
3873 
3874  ) // if the member is related and the arguments match then the
3875  // function is actually a friend.
3876  {
3877  mergeArguments(mmdAl,fmdAl);
3878  if (!fmd->documentation().isEmpty())
3879  {
3880  mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3881  }
3882  else if (!mmd->documentation().isEmpty())
3883  {
3884  fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3885  }
3886  if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3887  {
3888  mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3889  }
3890  else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3891  {
3892  fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3893  }
3894  if (!fmd->inbodyDocumentation().isEmpty())
3895  {
3897  }
3898  else if (!mmd->inbodyDocumentation().isEmpty())
3899  {
3901  }
3902  //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3903  if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3904  {
3905  mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3906  mmd->setBodyDef(fmd->getBodyDef());
3907  //mmd->setBodyMember(fmd);
3908  }
3909  else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3910  {
3911  fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3912  fmd->setBodyDef(mmd->getBodyDef());
3913  //fmd->setBodyMember(mmd);
3914  }
3916 
3917  mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3918  mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3919  fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3920  fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3921  }
3922  }
3923  }
3924  }
3925  }
3926 }
3927 
3928 //----------------------------------------------------------------------
3929 
3931 {
3932  //printf("---- transferFunctionDocumentation()\n");
3933 
3934  // find matching function declaration and definitions.
3935  MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3936  MemberName *mn;
3937  for (;(mn=mnli.current());++mnli)
3938  {
3939  //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3940  MemberDef *mdef=0,*mdec=0;
3941  MemberNameIterator mni1(*mn);
3942  /* find a matching function declaration and definition for this function */
3943  for (;(mdec=mni1.current());++mni1)
3944  {
3945  if (mdec->isPrototype() ||
3946  (mdec->isVariable() && mdec->isExternal())
3947  )
3948  {
3949  MemberNameIterator mni2(*mn);
3950  for (;(mdef=mni2.current());++mni2)
3951  {
3953  }
3954  }
3955  }
3956  }
3957 }
3958 
3959 //----------------------------------------------------------------------
3960 
3962 {
3963  MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3964  MemberName *mn;
3965  for (;(mn=mnli.current());++mnli)
3966  {
3967  MemberDef *md,*mdef=0,*mdec=0;
3968  MemberNameIterator mni(*mn);
3969  /* find a matching function declaration and definition for this function */
3970  for (;(md=mni.current());++mni)
3971  {
3972  if (md->isPrototype())
3973  mdec=md;
3974  else if (md->isVariable() && md->isExternal())
3975  mdec=md;
3976 
3977  if (md->isFunction() && !md->isStatic() && !md->isPrototype())
3978  mdef=md;
3979  else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3980  mdef=md;
3981  }
3982  if (mdef && mdec)
3983  {
3984  ArgumentList *mdefAl = mdef->argumentList();
3985  ArgumentList *mdecAl = mdec->argumentList();
3986  if (
3987  matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
3988  mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
3989  TRUE
3990  )
3991  ) /* match found */
3992  {
3993  MemberSDict *defDict = mdef->getReferencesMembers();
3994  MemberSDict *decDict = mdec->getReferencesMembers();
3995  if (defDict!=0)
3996  {
3997  MemberSDict::IteratorDict msdi(*defDict);
3998  MemberDef *rmd;
3999  for (msdi.toFirst();(rmd=msdi.current());++msdi)
4000  {
4001  if (decDict==0 || decDict->find(rmd->name())==0)
4002  {
4003  mdec->addSourceReferences(rmd);
4004  }
4005  }
4006  }
4007  if (decDict!=0)
4008  {
4009  MemberSDict::IteratorDict msdi(*decDict);
4010  MemberDef *rmd;
4011  for (msdi.toFirst();(rmd=msdi.current());++msdi)
4012  {
4013  if (defDict==0 || defDict->find(rmd->name())==0)
4014  {
4015  mdef->addSourceReferences(rmd);
4016  }
4017  }
4018  }
4019 
4020  defDict = mdef->getReferencedByMembers();
4021  decDict = mdec->getReferencedByMembers();
4022  if (defDict!=0)
4023  {
4024  MemberSDict::IteratorDict msdi(*defDict);
4025  MemberDef *rmd;
4026  for (msdi.toFirst();(rmd=msdi.current());++msdi)
4027  {
4028  if (decDict==0 || decDict->find(rmd->name())==0)
4029  {
4030  mdec->addSourceReferencedBy(rmd);
4031  }
4032  }
4033  }
4034  if (decDict!=0)
4035  {
4036  MemberSDict::IteratorDict msdi(*decDict);
4037  MemberDef *rmd;
4038  for (msdi.toFirst();(rmd=msdi.current());++msdi)
4039  {
4040  if (defDict==0 || defDict->find(rmd->name())==0)
4041  {
4042  mdef->addSourceReferencedBy(rmd);
4043  }
4044  }
4045  }
4046  }
4047  }
4048  }
4049 }
4050 
4051 //----------------------------------------------------------------------
4052 
4054 {
4055  // find match between function declaration and definition for
4056  // related functions
4057  MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4058  MemberName *mn;
4059  for (mnli.toFirst();(mn=mnli.current());++mnli)
4060  {
4061  MemberDef *md;
4062  MemberNameIterator mni(*mn);
4063  /* find a matching function declaration and definition for this function */
4064  for (mni.toFirst();(md=mni.current());++mni) // for each global function
4065  {
4066  //printf(" Function `%s'\n",md->name().data());
4067  MemberName *rmn;
4068  if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
4069  {
4070  //printf(" Member name found\n");
4071  MemberDef *rmd;
4072  MemberNameIterator rmni(*rmn);
4073  for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
4074  {
4075  ArgumentList *mdAl = md->argumentList();
4076  ArgumentList *rmdAl = rmd->argumentList();
4077  //printf(" Member found: related=`%d'\n",rmd->isRelated());
4078  if ((rmd->isRelated() || rmd->isForeign()) && // related function
4079  matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4080  rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
4081  TRUE
4082  )
4083  )
4084  {
4085  //printf(" Found related member `%s'\n",md->name().data());
4086  if (rmd->relatedAlso())
4087  md->setRelatedAlso(rmd->relatedAlso());
4088  else if (rmd->isForeign())
4089  md->makeForeign();
4090  else
4091  md->makeRelated();
4092  }
4093  }
4094  }
4095  }
4096  }
4097 }
4098 
4099 //----------------------------------------------------------------------
4100 
4106 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
4107 {
4108  QDict<int> *templateNames = new QDict<int>(17);
4109  templateNames->setAutoDelete(TRUE);
4110  static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
4111  if (templateArguments)
4112  {
4113  ArgumentListIterator ali(*templateArguments);
4114  Argument *arg;
4115  int count=0;
4116  for (ali.toFirst();(arg=ali.current());++ali,count++)
4117  {
4118  int i,p=0,l;
4119  while ((i=re.match(name,p,&l))!=-1)
4120  {
4121  QCString n = name.mid(i,l);
4122  if (n==arg->name)
4123  {
4124  if (templateNames->find(n)==0)
4125  {
4126  templateNames->insert(n,new int(count));
4127  }
4128  }
4129  p=i+l;
4130  }
4131  }
4132  }
4133  return templateNames;
4134 }
4135 
4139 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
4140 {
4141  ClassDef *result=0;
4142  if (cd==0)
4143  {
4144  return result;
4145  }
4146  FileDef *fd=cd->getFileDef();
4147  if (context && cd!=context)
4148  {
4149  result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
4150  }
4151  if (result==0)
4152  {
4153  result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
4154  }
4155  if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4156  {
4157  result = getClass(name);
4158  }
4159  if (result==0 &&
4161  name.find('<')!=-1)
4162  {
4163  result = Doxygen::genericsDict->find(name);
4164  }
4165  //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4166  // name.data(),
4167  // context ? context->name().data() : "<none>",
4168  // cd ? cd->name().data() : "<none>",
4169  // result ? result->name().data() : "<none>",
4170  // Doxygen::classSDict->find(name)
4171  // );
4172  return result;
4173 }
4174 
4175 
4176 static void findUsedClassesForClass(EntryNav *rootNav,
4177  Definition *context,
4178  ClassDef *masterCd,
4179  ClassDef *instanceCd,
4180  bool isArtificial,
4181  ArgumentList *actualArgs=0,
4182  QDict<int> *templateNames=0
4183  )
4184 {
4185  masterCd->visited=TRUE;
4186  ArgumentList *formalArgs = masterCd->templateArguments();
4187  if (masterCd->memberNameInfoSDict())
4188  {
4190  MemberNameInfo *mni;
4191  for (;(mni=mnili.current());++mnili)
4192  {
4193  MemberNameInfoIterator mnii(*mni);
4194  MemberInfo *mi;
4195  for (mnii.toFirst();(mi=mnii.current());++mnii)
4196  {
4197  MemberDef *md=mi->memberDef;
4198  if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4199  {
4200  //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
4201  QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4202  QCString typedefValue = resolveTypeDef(masterCd,type);
4203  if (!typedefValue.isEmpty())
4204  {
4205  type = typedefValue;
4206  }
4207  int pos=0;
4208  QCString usedClassName;
4209  QCString templSpec;
4210  bool found=FALSE;
4211  // the type can contain template variables, replace them if present
4212  if (actualArgs)
4213  {
4214  type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4215  }
4216 
4217  //printf(" template substitution gives=%s\n",type.data());
4218  while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
4219  {
4220  // find the type (if any) that matches usedClassName
4221  ClassDef *typeCd = getResolvedClass(masterCd,
4222  masterCd->getFileDef(),
4223  usedClassName,
4224  0,0,
4225  FALSE,TRUE
4226  );
4227  //printf("====> usedClassName=%s -> typeCd=%s\n",
4228  // usedClassName.data(),typeCd?typeCd->name().data():"<none>");
4229  if (typeCd)
4230  {
4231  usedClassName = typeCd->name();
4232  }
4233 
4234  int sp=usedClassName.find('<');
4235  if (sp==-1) sp=0;
4236  int si=usedClassName.findRev("::",sp);
4237  if (si!=-1)
4238  {
4239  // replace any namespace aliases
4240  replaceNamespaceAliases(usedClassName,si);
4241  }
4242  // add any template arguments to the class
4243  QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4244  //printf(" usedName=%s\n",usedName.data());
4245 
4246  bool delTempNames=FALSE;
4247  if (templateNames==0)
4248  {
4249  templateNames = getTemplateArgumentsInName(formalArgs,usedName);
4250  delTempNames=TRUE;
4251  }
4252  BaseInfo bi(usedName,Public,Normal);
4253  findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
4254 
4255  if (masterCd->templateArguments())
4256  {
4257  ArgumentListIterator ali(*masterCd->templateArguments());
4258  Argument *arg;
4259  int count=0;
4260  for (ali.toFirst();(arg=ali.current());++ali,++count)
4261  {
4262  if (arg->name==usedName) // type is a template argument
4263  {
4264  found=TRUE;
4265  Debug::print(Debug::Classes,0," New used class `%s'\n", qPrint(usedName));
4266 
4267  ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
4268  if (usedCd==0)
4269  {
4270  usedCd = new ClassDef(
4271  masterCd->getDefFileName(),masterCd->getDefLine(),
4272  masterCd->getDefColumn(),
4273  usedName,
4274  ClassDef::Class);
4275  //printf("making %s a template argument!!!\n",usedCd->name().data());
4276  usedCd->makeTemplateArgument();
4277  usedCd->setUsedOnly(TRUE);
4278  usedCd->setLanguage(masterCd->getLanguage());
4279  Doxygen::hiddenClasses->append(usedName,usedCd);
4280  }
4281  if (isArtificial) usedCd->setArtificial(TRUE);
4282  Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", qPrint(usedCd->name()));
4283  instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4284  usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4285  }
4286  }
4287  }
4288 
4289  if (!found)
4290  {
4291  ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4292  //printf("Looking for used class %s: result=%s master=%s\n",
4293  // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
4294 
4295  if (usedCd)
4296  {
4297  found=TRUE;
4298  Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", qPrint(usedCd->name()));
4299  instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
4300  usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4301  }
4302  }
4303  if (delTempNames)
4304  {
4305  delete templateNames;
4306  templateNames=0;
4307  }
4308  }
4309  if (!found && !type.isEmpty()) // used class is not documented in any scope
4310  {
4311  ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4312  if (usedCd==0 && !Config_getBool(HIDE_UNDOC_RELATIONS))
4313  {
4314  if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4315  {
4316  type+=md->argsString();
4317  }
4318  Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", qPrint(type));
4319  usedCd = new ClassDef(
4320  masterCd->getDefFileName(),masterCd->getDefLine(),
4321  masterCd->getDefColumn(),
4322  type,ClassDef::Class);
4323  usedCd->setUsedOnly(TRUE);
4324  usedCd->setLanguage(masterCd->getLanguage());
4325  Doxygen::hiddenClasses->append(type,usedCd);
4326  }
4327  if (usedCd)
4328  {
4329  if (isArtificial) usedCd->setArtificial(TRUE);
4330  Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", qPrint(usedCd->name()));
4331  instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4332  usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4333  }
4334  }
4335  }
4336  }
4337  }
4338  }
4339  else
4340  {
4341  //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4342  }
4343 }
4344 
4346  EntryNav *rootNav,
4347  Definition *context,
4348  ClassDef *masterCd,
4349  ClassDef *instanceCd,
4351  bool isArtificial,
4352  ArgumentList *actualArgs=0,
4353  QDict<int> *templateNames=0
4354  )
4355 {
4356  Entry *root = rootNav->entry();
4357  //if (masterCd->visited) return;
4358  masterCd->visited=TRUE;
4359  // The base class could ofcouse also be a non-nested class
4360  ArgumentList *formalArgs = masterCd->templateArguments();
4361  QListIterator<BaseInfo> bii(*root->extends);
4362  BaseInfo *bi=0;
4363  for (bii.toFirst();(bi=bii.current());++bii)
4364  {
4365  //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4366  // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4367  bool delTempNames=FALSE;
4368  if (templateNames==0)
4369  {
4370  templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4371  delTempNames=TRUE;
4372  }
4373  BaseInfo tbi(bi->name,bi->prot,bi->virt);
4374  if (actualArgs) // substitute the formal template arguments of the base class
4375  {
4376  tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4377  }
4378  //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4379 
4380  if (mode==DocumentedOnly)
4381  {
4382  // find a documented base class in the correct scope
4383  if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4384  {
4385  // 1.8.2: decided to show inheritance relations even if not documented,
4386  // we do make them artificial, so they do not appear in the index
4387  //if (!Config_getBool(HIDE_UNDOC_RELATIONS))
4388  bool b = Config_getBool(HIDE_UNDOC_RELATIONS) ? TRUE : isArtificial;
4389  //{
4390  // no documented base class -> try to find an undocumented one
4391  findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4392  //}
4393  }
4394  }
4395  else if (mode==TemplateInstances)
4396  {
4397  findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4398  }
4399  if (delTempNames)
4400  {
4401  delete templateNames;
4402  templateNames=0;
4403  }
4404  }
4405 }
4406 
4407 //----------------------------------------------------------------------
4408 
4410  Definition *context,
4411  ClassDef *templateClass,const QCString &templSpec,
4412  QDict<int> *templateNames,
4413  bool isArtificial)
4414 {
4415  Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n",
4416  qPrint(templateClass->name()),qPrint(templSpec));
4417  //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4418  // templateClass->name().data(),templSpec.data());
4419  //if (templateNames)
4420  //{
4421  // QDictIterator<int> qdi(*templateNames);
4422  // int *tempArgIndex;
4423  // for (;(tempArgIndex=qdi.current());++qdi)
4424  // {
4425  // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4426  // }
4427  //}
4428  //printf("\n");
4429 
4430  bool existingClass = (templSpec ==
4431  tempArgListToString(templateClass->templateArguments(),root->lang)
4432  );
4433  if (existingClass) return TRUE;
4434 
4435  bool freshInstance=FALSE;
4436  ClassDef *instanceClass = templateClass->insertTemplateInstance(
4437  root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4438  if (isArtificial) instanceClass->setArtificial(TRUE);
4439  instanceClass->setLanguage(root->lang);
4440 
4441  if (freshInstance)
4442  {
4443  Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",qPrint(instanceClass->name()));
4444  Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4445  instanceClass->setTemplateBaseClassNames(templateNames);
4446 
4447  // search for new template instances caused by base classes of
4448  // instanceClass
4449  EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4450  if (templateRootNav)
4451  {
4452  bool unloadNeeded=FALSE;
4453  Entry *templateRoot = templateRootNav->entry();
4454  if (templateRoot==0) // not yet loaded
4455  {
4456  templateRootNav->loadEntry(g_storage);
4457  templateRoot = templateRootNav->entry();
4458  ASSERT(templateRoot!=0); // now it should really be loaded
4459  unloadNeeded=TRUE;
4460  }
4461 
4462  Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",
4463  qPrint(templateRoot->name),qPrint(templSpec));
4464  ArgumentList *templArgs = new ArgumentList;
4465  stringToArgumentList(templSpec,templArgs);
4466  findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4467  TemplateInstances,isArtificial,templArgs,templateNames);
4468 
4469  findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4470  isArtificial,templArgs,templateNames);
4471  delete templArgs;
4472 
4473  if (unloadNeeded) // still cleanup to do
4474  {
4475  templateRootNav->releaseEntry();
4476  }
4477  }
4478  else
4479  {
4480  Debug::print(Debug::Classes,0," no template root entry found!\n");
4481  // TODO: what happened if we get here?
4482  }
4483 
4484  //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data());
4485  //ArgumentList *tl = templateClass->templateArguments();
4486  }
4487  else
4488  {
4489  Debug::print(Debug::Classes,0," instance already exists!\n");
4490  }
4491  return TRUE;
4492 }
4493 
4494 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4495 {
4496  QCString n=name;
4497  int index=n.find('<');
4498  if (index!=-1)
4499  {
4500  n=n.left(index);
4501  }
4502  bool result = rightScopeMatch(scope,n);
4503  return result;
4504 }
4505 
4519 static int findEndOfTemplate(const QCString &s,int startPos)
4520 {
4521  // locate end of template
4522  int e=startPos;
4523  int brCount=1;
4524  int roundCount=0;
4525  int len = s.length();
4526  bool insideString=FALSE;
4527  bool insideChar=FALSE;
4528  char pc = 0;
4529  while (e<len && brCount!=0)
4530  {
4531  char c=s.at(e);
4532  switch(c)
4533  {
4534  case '<':
4535  if (!insideString && !insideChar)
4536  {
4537  if (e<len-1 && s.at(e+1)=='<')
4538  e++;
4539  else if (roundCount==0)
4540  brCount++;
4541  }
4542  break;
4543  case '>':
4544  if (!insideString && !insideChar)
4545  {
4546  if (e<len-1 && s.at(e+1)=='>')
4547  e++;
4548  else if (roundCount==0)
4549  brCount--;
4550  }
4551  break;
4552  case '(':
4553  if (!insideString && !insideChar)
4554  roundCount++;
4555  break;
4556  case ')':
4557  if (!insideString && !insideChar)
4558  roundCount--;
4559  break;
4560  case '"':
4561  if (!insideChar)
4562  {
4563  if (insideString && pc!='\\')
4564  insideString=FALSE;
4565  else
4566  insideString=TRUE;
4567  }
4568  break;
4569  case '\'':
4570  if (!insideString)
4571  {
4572  if (insideChar && pc!='\\')
4573  insideChar=FALSE;
4574  else
4575  insideChar=TRUE;
4576  }
4577  break;
4578  }
4579  pc = c;
4580  e++;
4581  }
4582  return brCount==0 ? e : -1;
4583 }
4584 
4585 static bool findClassRelation(
4586  EntryNav *rootNav,
4587  Definition *context,
4588  ClassDef *cd,
4589  BaseInfo *bi,
4590  QDict<int> *templateNames,
4592  bool isArtificial
4593  )
4594 {
4595  //printf("findClassRelation(class=%s base=%s templateNames=",
4596  // cd->name().data(),bi->name.data());
4597  //if (templateNames)
4598  //{
4599  // QDictIterator<int> qdi(*templateNames);
4600  // int *tempArgIndex;
4601  // for (;(tempArgIndex=qdi.current());++qdi)
4602  // {
4603  // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4604  // }
4605  //}
4606  //printf("\n");
4607 
4608  Entry *root = rootNav->entry();
4609 
4610  QCString biName=bi->name;
4611  bool explicitGlobalScope=FALSE;
4612  //printf("findClassRelation: biName=`%s'\n",biName.data());
4613  if (biName.left(2)=="::") // explicit global scope
4614  {
4615  biName=biName.right(biName.length()-2);
4616  explicitGlobalScope=TRUE;
4617  }
4618 
4619  EntryNav *parentNode=rootNav->parent();
4620  bool lastParent=FALSE;
4621  do // for each parent scope, starting with the largest scope
4622  // (in case of nested classes)
4623  {
4624  QCString scopeName= parentNode ? parentNode->name().data() : "";
4625  int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4626  do // try all parent scope prefixes, starting with the largest scope
4627  {
4628  //printf("scopePrefix=`%s' biName=`%s'\n",
4629  // scopeName.left(scopeOffset).data(),biName.data());
4630 
4631  QCString baseClassName=biName;
4632  if (scopeOffset>0)
4633  {
4634  baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4635  }
4636  //QCString stripped;
4637  //baseClassName=stripTemplateSpecifiersFromScope
4638  // (removeRedundantWhiteSpace(baseClassName),TRUE,
4639  // &stripped);
4640  MemberDef *baseClassTypeDef=0;
4641  QCString templSpec;
4642  ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4643  cd->getFileDef(),
4644  baseClassName,
4645  &baseClassTypeDef,
4646  &templSpec,
4647  mode==Undocumented,
4648  TRUE
4649  );
4650  //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4651  // baseClassName.data(),baseClass,cd,explicitGlobalScope);
4652  //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4653  // cd ? cd->name().data():"<none>",
4654  // baseClassName.data(),
4655  // baseClass?baseClass->name().data():"<none>",
4656  // templSpec.data()
4657  // );
4658  //if (baseClassName.left(root->name.length())!=root->name ||
4659  // baseClassName.at(root->name.length())!='<'
4660  // ) // Check for base class with the same name.
4661  // // If found then look in the outer scope for a match
4662  // // and prevent recursion.
4663  if (!isRecursiveBaseClass(rootNav->name(),baseClassName)
4664  || explicitGlobalScope
4665  // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4666  // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4667  || (rootNav->lang()==SrcLangExt_IDL &&
4668  (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
4669  rootNav->section()==Entry::INCLUDED_SERVICE_SEC)))
4670  {
4671  Debug::print(
4672  Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4673  qPrint(baseClassName),
4674  qPrint(rootNav->name()),
4675  (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4676  (bi->virt==Normal)?"normal":"virtual",
4677  qPrint(templSpec)
4678  );
4679 
4680  int i=baseClassName.find('<');
4681  int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4682  if (si==-1) si=0;
4683  if (baseClass==0 && (root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java))
4684  {
4685  // for Java/C# strip the template part before looking for matching
4686  baseClass = Doxygen::genericsDict->find(baseClassName.left(i));
4687  //printf("looking for '%s' result=%p\n",baseClassName.data(),baseClass);
4688  }
4689  if (baseClass==0 && i!=-1)
4690  // base class has template specifiers
4691  {
4692  // TODO: here we should try to find the correct template specialization
4693  // but for now, we only look for the unspecializated base class.
4694  int e=findEndOfTemplate(baseClassName,i+1);
4695  //printf("baseClass==0 i=%d e=%d\n",i,e);
4696  if (e!=-1) // end of template was found at e
4697  {
4698  templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4699  baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4700  baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4701  cd->getFileDef(),
4702  baseClassName,
4703  &baseClassTypeDef,
4704  0, //&templSpec,
4705  mode==Undocumented,
4706  TRUE
4707  );
4708  //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4709  // baseClass,baseClassName.data(),templSpec.data());
4710  }
4711  }
4712  else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4713  // know it is a template, so see if
4714  // we can also link to the explicit
4715  // instance (for instance if a class
4716  // derived from a template argument)
4717  {
4718  //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4719  ClassDef *templClass=getClass(baseClass->name()+templSpec);
4720  if (templClass)
4721  {
4722  // use the template instance instead of the template base.
4723  baseClass = templClass;
4724  templSpec.resize(0);
4725  }
4726  }
4727 
4728  //printf("cd=%p baseClass=%p\n",cd,baseClass);
4729  bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4730  //printf("1. found=%d\n",found);
4731  if (!found && si!=-1)
4732  {
4733  QCString tmpTemplSpec;
4734  // replace any namespace aliases
4735  replaceNamespaceAliases(baseClassName,si);
4736  baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4737  cd->getFileDef(),
4738  baseClassName,
4739  &baseClassTypeDef,
4740  &tmpTemplSpec,
4741  mode==Undocumented,
4742  TRUE
4743  );
4744  found=baseClass!=0 && baseClass!=cd;
4745  if (found) templSpec = tmpTemplSpec;
4746  }
4747  //printf("2. found=%d\n",found);
4748 
4749  //printf("root->name=%s biName=%s baseClassName=%s\n",
4750  // root->name.data(),biName.data(),baseClassName.data());
4751  //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4752  //{
4753  // baseClassName+="-g";
4754  //}
4755 
4756  if (!found)
4757  {
4758  baseClass=findClassWithinClassContext(context,cd,baseClassName);
4759  //printf("findClassWithinClassContext(%s,%s)=%p\n",
4760  // cd->name().data(),baseClassName.data(),baseClass);
4761  found = baseClass!=0 && baseClass!=cd;
4762 
4763  }
4764  if (!found)
4765  {
4766  // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4767  // the class name also in the alias mapping.
4768  QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4769  if (aliasName) // see if it is indeed a class.
4770  {
4771  baseClass=getClass(*aliasName);
4772  found = baseClass!=0 && baseClass!=cd;
4773  }
4774  }
4775  bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4776  // make templSpec canonical
4777  // warning: the following line doesn't work for Mixin classes (see bug 560623)
4778  // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4779 
4780  //printf("3. found=%d\n",found);
4781  if (found)
4782  {
4783  Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",qPrint(biName),qPrint(templSpec));
4784  // add base class to this class
4785 
4786  // if templSpec is not empty then we should "instantiate"
4787  // the template baseClass. A new ClassDef should be created
4788  // to represent the instance. To be able to add the (instantiated)
4789  // members and documentation of a template class
4790  // (inserted in that template class at a later stage),
4791  // the template should know about its instances.
4792  // the instantiation process, should be done in a recursive way,
4793  // since instantiating a template may introduce new inheritance
4794  // relations.
4795  if (!templSpec.isEmpty() && mode==TemplateInstances)
4796  {
4797  // if baseClass is actually a typedef then we should not
4798  // instantiate it, since typedefs are in a different namespace
4799  // see bug531637 for an example where this would otherwise hang
4800  // doxygen
4801  if (baseClassTypeDef==0)
4802  {
4803  //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4804  findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4805  }
4806  }
4807  else if (mode==DocumentedOnly || mode==Undocumented)
4808  {
4809  //printf(" => insert base class\n");
4810  QCString usedName;
4811  if (baseClassTypeDef || cd->isCSharp())
4812  {
4813  usedName=biName;
4814  //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4815  }
4816  static bool sipSupport = Config_getBool(SIP_SUPPORT);
4817  if (sipSupport) bi->prot=Public;
4818  if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4819  {
4820  cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4821  // add this class as super class to the base class
4822  baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4823  }
4824  else
4825  {
4826  warn(root->fileName,root->startLine,
4827  "Detected potential recursive class relation "
4828  "between class %s and base class %s!",
4829  cd->name().data(),baseClass->name().data()
4830  );
4831  }
4832  }
4833  return TRUE;
4834  }
4835  else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4836  {
4838  " New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4839  qPrint(biName),qPrint(baseClassName),qPrint(templSpec),isArtificial
4840  );
4841  baseClass=0;
4842  if (isATemplateArgument)
4843  {
4844  baseClass=Doxygen::hiddenClasses->find(baseClassName);
4845  if (baseClass==0)
4846  {
4847  baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4848  baseClassName,
4849  ClassDef::Class);
4850  Doxygen::hiddenClasses->append(baseClassName,baseClass);
4851  if (isArtificial) baseClass->setArtificial(TRUE);
4852  baseClass->setLanguage(root->lang);
4853  }
4854  }
4855  else
4856  {
4857  baseClass=Doxygen::classSDict->find(baseClassName);
4858  //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4859  // baseClassName.data(),baseClass,biName.data(),templSpec.data());
4860  if (baseClass==0)
4861  {
4862  baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4863  baseClassName,
4864  ClassDef::Class);
4865  Doxygen::classSDict->append(baseClassName,baseClass);
4866  if (isArtificial) baseClass->setArtificial(TRUE);
4867  baseClass->setLanguage(root->lang);
4868  int si = baseClassName.findRev("::");
4869  if (si!=-1) // class is nested
4870  {
4871  Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,rootNav->tagInfo());
4872  if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4873  {
4874  baseClass->setArtificial(TRUE); // see bug678139
4875  }
4876  }
4877  }
4878  }
4879  if (biName.right(2)=="-p")
4880  {
4881  biName="<"+biName.left(biName.length()-2)+">";
4882  }
4883  // add base class to this class
4884  cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4885  // add this class as super class to the base class
4886  baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4887  // the undocumented base was found in this file
4888  baseClass->insertUsedFile(rootNav->fileDef());
4889  baseClass->setOuterScope(Doxygen::globalScope);
4890  if (baseClassName.right(2)=="-p")
4891  {
4892  baseClass->setCompoundType(ClassDef::Protocol);
4893  }
4894  return TRUE;
4895  }
4896  else
4897  {
4898  Debug::print(Debug::Classes,0," Base class `%s' not found\n",qPrint(biName));
4899  }
4900  }
4901  else
4902  {
4903  if (mode!=TemplateInstances)
4904  {
4905  warn(root->fileName,root->startLine,
4906  "Detected potential recursive class relation "
4907  "between class %s and base class %s!\n",
4908  root->name.data(),baseClassName.data()
4909  );
4910  }
4911  // for mode==TemplateInstance this case is quite common and
4912  // indicates a relation between a template class and a template
4913  // instance with the same name.
4914  }
4915  if (scopeOffset==0)
4916  {
4917  scopeOffset=-1;
4918  }
4919  else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4920  {
4921  scopeOffset=0;
4922  }
4923  //printf("new scopeOffset=`%d'",scopeOffset);
4924  } while (scopeOffset>=0);
4925 
4926  if (parentNode==0)
4927  {
4928  lastParent=TRUE;
4929  }
4930  else
4931  {
4932  parentNode=parentNode->parent();
4933  }
4934  } while (lastParent);
4935 
4936  return FALSE;
4937 }
4938 
4939 //----------------------------------------------------------------------
4940 // Computes the base and super classes for each class in the tree
4941 
4942 static bool isClassSection(EntryNav *rootNav)
4943 {
4944  if ( !rootNav->name().isEmpty() )
4945  {
4946  if (rootNav->section() & Entry::COMPOUND_MASK)
4947  // is it a compound (class, struct, union, interface ...)
4948  {
4949  return TRUE;
4950  }
4951  else if (rootNav->section() & Entry::COMPOUNDDOC_MASK)
4952  // is it a documentation block with inheritance info.
4953  {
4954  rootNav->loadEntry(g_storage);
4955  Entry *root = rootNav->entry();
4956  bool extends = root->extends->count()>0;
4957  rootNav->releaseEntry();
4958  if (extends) return TRUE;
4959  }
4960  }
4961  return FALSE;
4962 }
4963 
4964 
4967 static void findClassEntries(EntryNav *rootNav)
4968 {
4969  if (isClassSection(rootNav))
4970  {
4971  g_classEntries.insert(rootNav->name(),rootNav);
4972  }
4974 }
4975 
4976 static QCString extractClassName(EntryNav *rootNav)
4977 {
4978  // strip any anonymous scopes first
4979  QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4980  bName=stripTemplateSpecifiersFromScope(bName);
4981  int i;
4982  if ((rootNav->lang()==SrcLangExt_CSharp || rootNav->lang()==SrcLangExt_Java) &&
4983  (i=bName.find('<'))!=-1)
4984  {
4985  // a Java/C# generic class looks like a C++ specialization, so we need to strip the
4986  // template part before looking for matches
4987  bName=bName.left(i);
4988  }
4989  return bName;
4990 }
4991 
4998 {
4999  ClassSDict::Iterator cli(*Doxygen::classSDict);
5000  for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5001  QDictIterator<EntryNav> edi(g_classEntries);
5002  EntryNav *rootNav;
5003  for (;(rootNav=edi.current());++edi)
5004  {
5005  ClassDef *cd;
5006  QCString bName = extractClassName(rootNav);
5007  Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",qPrint(bName));
5008  if ((cd=getClass(bName)))
5009  {
5010  rootNav->loadEntry(g_storage);
5011  //printf("Class %s %d\n",cd->name().data(),root->extends->count());
5012  findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
5013  rootNav->releaseEntry();
5014  }
5015  }
5016 }
5017 
5019 {
5020  ClassSDict::Iterator cli(*Doxygen::classSDict);
5021  for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5022  QDictIterator<EntryNav> edi(g_classEntries);
5023  EntryNav *rootNav;
5024  for (;(rootNav=edi.current());++edi)
5025  {
5026  ClassDef *cd;
5027  QCString bName = extractClassName(rootNav);
5028  Debug::print(Debug::Classes,0," Usage: Class %s : \n",qPrint(bName));
5029  if ((cd=getClass(bName)))
5030  {
5031  rootNav->loadEntry(g_storage);
5032  findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
5033  cd->addTypeConstraints();
5034  rootNav->releaseEntry();
5035  }
5036  }
5037 }
5038 
5040 {
5041  ClassSDict::Iterator cli(*Doxygen::classSDict);
5042  for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5043  QDictIterator<EntryNav> edi(g_classEntries);
5044  EntryNav *rootNav;
5045  for (;(rootNav=edi.current());++edi)
5046  {
5047  ClassDef *cd;
5048 
5049  rootNav->loadEntry(g_storage);
5050  Entry *root = rootNav->entry();
5051  QCString bName = extractClassName(rootNav);
5052  Debug::print(Debug::Classes,0," Relations: Class %s : \n",qPrint(bName));
5053  if ((cd=getClass(bName)))
5054  {
5055  findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
5056  }
5057  int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
5058  if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
5059  bName.right(2)!="::")
5060  {
5061  if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
5063  Config_getBool(EXTRACT_LOCAL_CLASSES)) && // not defined in source file
5064  protectionLevelVisible(root->protection) && // hidden by protection
5065  !Config_getBool(HIDE_UNDOC_CLASSES) // undocumented class are visible
5066  )
5067  warn_undoc(
5068  root->fileName,root->startLine,
5069  "Compound %s is not documented.",
5070  root->name.data()
5071  );
5072  }
5073 
5074  rootNav->releaseEntry();
5075  }
5076 }
5077 
5079 {
5080  QDictIterator<EntryNav> edi(g_classEntries);
5081  EntryNav *rootNav;
5082  for (;(rootNav=edi.current());++edi)
5083  {
5084  rootNav->loadEntry(g_storage);
5085  Entry *root = rootNav->entry();
5086 
5087  QCString bName=stripAnonymousNamespaceScope(root->name);
5088  bName=stripTemplateSpecifiersFromScope(bName);
5089  ClassDef *cd=getClass(bName);
5090  // strip any anonymous scopes first
5091  QDict<ClassDef> *templInstances = 0;
5092  if (cd && (templInstances=cd->getTemplateInstances()))
5093  {
5094  Debug::print(Debug::Classes,0," Template class %s : \n",qPrint(cd->name()));
5095  QDictIterator<ClassDef> tdi(*templInstances);
5096  ClassDef *tcd;
5097  for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
5098  {
5099  Debug::print(Debug::Classes,0," Template instance %s : \n",qPrint(tcd->name()));
5100  QCString templSpec = tdi.currentKey();
5101  ArgumentList *templArgs = new ArgumentList;
5102  stringToArgumentList(templSpec,templArgs);
5103  QList<BaseInfo> *baseList=root->extends;
5104  QListIterator<BaseInfo> it(*baseList);
5105  BaseInfo *bi;
5106  for (;(bi=it.current());++it) // for each base class of the template
5107  {
5108  // check if the base class is a template argument
5109  BaseInfo tbi(bi->name,bi->prot,bi->virt);
5110  ArgumentList *tl = cd->templateArguments();
5111  if (tl)
5112  {
5113  QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
5114  QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
5115  // for each template name that we inherit from we need to
5116  // substitute the formal with the actual arguments
5117  QDict<int> *actualTemplateNames = new QDict<int>(17);
5118  actualTemplateNames->setAutoDelete(TRUE);
5119  QDictIterator<int> qdi(*templateNames);
5120  for (qdi.toFirst();qdi.current();++qdi)
5121  {
5122  int templIndex = *qdi.current();
5123  Argument *actArg = 0;
5124  if (templIndex<(int)templArgs->count())
5125  {
5126  actArg=templArgs->at(templIndex);
5127  }
5128  if (actArg!=0 &&
5129  baseClassNames!=0 &&
5130  baseClassNames->find(actArg->type)!=0 &&
5131  actualTemplateNames->find(actArg->type)==0
5132  )
5133  {
5134  actualTemplateNames->insert(actArg->type,new int(templIndex));
5135  }
5136  }
5137  delete templateNames;
5138 
5139  tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
5140  // find a documented base class in the correct scope
5141  if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
5142  {
5143  // no documented base class -> try to find an undocumented one
5144  findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
5145  }
5146  delete actualTemplateNames;
5147  }
5148  }
5149  delete templArgs;
5150  } // class has no base classes
5151  }
5152 
5153  rootNav->releaseEntry();
5154  }
5155 }
5156 
5157 //-----------------------------------------------------------------------
5158 // compute the references (anchors in HTML) for each function in the file
5159 
5161 {
5162  ClassSDict::Iterator cli(*Doxygen::classSDict);
5163  ClassDef *cd=0;
5164  for (cli.toFirst();(cd=cli.current());++cli)
5165  {
5166  cd->computeAnchors();
5167  }
5168  FileNameListIterator fnli(*Doxygen::inputNameList);
5169  FileName *fn;
5170  for (fnli.toFirst();(fn=fnli.current());++fnli)
5171  {
5172  FileNameIterator fni(*fn);
5173  FileDef *fd;
5174  for (;(fd=fni.current());++fni)
5175  {
5176  fd->computeAnchors();
5177  }
5178  }
5179  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5180  NamespaceDef *nd=0;
5181  for (nli.toFirst();(nd=nli.current());++nli)
5182  {
5183  nd->computeAnchors();
5184  }
5185  GroupSDict::Iterator gli(*Doxygen::groupSDict);
5186  GroupDef *gd;
5187  for (gli.toFirst();(gd=gli.current());++gli)
5188  {
5189  gd->computeAnchors();
5190  }
5191 }
5192 
5193 //----------------------------------------------------------------------
5194 
5195 static void addListReferences()
5196 {
5197  MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
5198  MemberName *mn=0;
5199  for (mnli.toFirst();(mn=mnli.current());++mnli)
5200  {
5201  MemberNameIterator mni(*mn);
5202  MemberDef *md=0;
5203  for (mni.toFirst();(md=mni.current());++mni)
5204  {
5205  md->visited=FALSE;
5206  }
5207  }
5208  MemberNameSDict::Iterator fmnli(*Doxygen::functionNameSDict);
5209  for (fmnli.toFirst();(mn=fmnli.current());++fmnli)
5210  {
5211  MemberNameIterator mni(*mn);
5212  MemberDef *md=0;
5213  for (mni.toFirst();(md=mni.current());++mni)
5214  {
5215  md->visited=FALSE;
5216  }
5217  }
5218 
5219  ClassSDict::Iterator cli(*Doxygen::classSDict);
5220  ClassDef *cd=0;
5221  for (cli.toFirst();(cd=cli.current());++cli)
5222  {
5223  cd->addListReferences();
5224  }
5225 
5226  FileNameListIterator fnli(*Doxygen::inputNameList);
5227  FileName *fn;
5228  for (fnli.toFirst();(fn=fnli.current());++fnli)
5229  {
5230  FileNameIterator fni(*fn);
5231  FileDef *fd;
5232  for (;(fd=fni.current());++fni)
5233  {
5234  fd->addListReferences();
5235  }
5236  }
5237 
5238  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5239  NamespaceDef *nd=0;
5240  for (nli.toFirst();(nd=nli.current());++nli)
5241  {
5242  nd->addListReferences();
5243  }
5244 
5245  GroupSDict::Iterator gli(*Doxygen::groupSDict);
5246  GroupDef *gd;
5247  for (gli.toFirst();(gd=gli.current());++gli)
5248  {
5249  gd->addListReferences();
5250  }
5251 
5252  PageSDict::Iterator pdi(*Doxygen::pageSDict);
5253  PageDef *pd=0;
5254  for (pdi.toFirst();(pd=pdi.current());++pdi)
5255  {
5256  QCString name = pd->getOutputFileBase();
5257  if (pd->getGroupDef())
5258  {
5259  name = pd->getGroupDef()->getOutputFileBase();
5260  }
5261  {
5262  QList<ListItemInfo> *xrefItems = pd->xrefListItems();
5263  addRefItem(xrefItems,
5264  name,
5265  theTranslator->trPage(TRUE,TRUE),
5266  name,pd->title(),0,0);
5267  }
5268  }
5269 
5270  DirSDict::Iterator ddi(*Doxygen::directories);
5271  DirDef *dd = 0;
5272  for (ddi.toFirst();(dd=ddi.current());++ddi)
5273  {
5274  QCString name = dd->getOutputFileBase();
5275  //if (dd->getGroupDef())
5276  //{
5277  // name = dd->getGroupDef()->getOutputFileBase();
5278  //}
5279  QList<ListItemInfo> *xrefItems = dd->xrefListItems();
5280  addRefItem(xrefItems,
5281  name,
5282  theTranslator->trDir(TRUE,TRUE),
5283  name,dd->displayName(),0,0);
5284  }
5285 }
5286 
5287 //----------------------------------------------------------------------
5288 
5289 static void generateXRefPages()
5290 {
5291  QDictIterator<RefList> di(*Doxygen::xrefLists);
5292  RefList *rl;
5293  for (di.toFirst();(rl=di.current());++di)
5294  {
5295  rl->generatePage();
5296  }
5297 }
5298 
5299 //----------------------------------------------------------------------
5300 // Copy the documentation in entry `root' to member definition `md' and
5301 // set the function declaration of the member to `funcDecl'. If the boolean
5302 // over_load is set the standard overload text is added.
5303 
5304 static void addMemberDocs(EntryNav *rootNav,
5305  MemberDef *md, const char *funcDecl,
5306  ArgumentList *al,
5307  bool over_load,
5308  NamespaceSDict *
5309  )
5310 {
5311  Entry *root = rootNav->entry();
5312  //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
5313  // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
5314  QCString fDecl=funcDecl;
5315  // strip extern specifier
5316  fDecl.stripPrefix("extern ");
5317  md->setDefinition(fDecl);
5318  md->enableCallGraph(root->callGraph);
5319  md->enableCallerGraph(root->callerGraph);
5320  ClassDef *cd=md->getClassDef();
5321  NamespaceDef *nd=md->getNamespaceDef();
5322  QCString fullName;
5323  if (cd)
5324  fullName = cd->name();
5325  else if (nd)
5326  fullName = nd->name();
5327 
5328  if (!fullName.isEmpty()) fullName+="::";
5329  fullName+=md->name();
5330  FileDef *rfd=rootNav->fileDef();
5331 
5332  // TODO determine scope based on root not md
5333  Definition *rscope = md->getOuterScope();
5334 
5335  ArgumentList *mdAl = md->argumentList();
5336  if (al)
5337  {
5338  //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5339  mergeArguments(mdAl,al,!root->doc.isEmpty());
5340  }
5341  else
5342  {
5343  if (
5344  matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
5345  rscope,rfd,root->argList,
5346  TRUE
5347  )
5348  )
5349  {
5350  //printf("merging arguments (2)\n");
5351  mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
5352  }
5353  }
5354  if (over_load) // the \overload keyword was used
5355  {
5356  QCString doc=getOverloadDocs();
5357  if (!root->doc.isEmpty())
5358  {
5359  doc+="<p>";
5360  doc+=root->doc;
5361  }
5362  md->setDocumentation(doc,root->docFile,root->docLine);
5363  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5364  md->setDocsForDefinition(!root->proto);
5365  }
5366  else
5367  {
5368  //printf("overwrite!\n");
5369  md->setDocumentation(root->doc,root->docFile,root->docLine);
5370  md->setDocsForDefinition(!root->proto);
5371 
5372  //printf("overwrite!\n");
5373  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5374 
5375  if (
5376  (md->inbodyDocumentation().isEmpty() ||
5377  !rootNav->parent()->name().isEmpty()
5378  ) && !root->inbodyDocs.isEmpty()
5379  )
5380  {
5381  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5382  }
5383  }
5384 
5385  //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5386  // md->initializer().data(),md->initializer().isEmpty(),
5387  // root->initializer.data(),root->initializer.isEmpty()
5388  // );
5389  if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5390  {
5391  //printf("setInitializer\n");
5392  md->setInitializer(root->initializer);
5393  }
5394 
5395  md->setMaxInitLines(root->initLines);
5396 
5397  if (rfd)
5398  {
5399  if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5400  )
5401  {
5402  //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5403  md->setBodySegment(root->bodyLine,root->endBodyLine);
5404  md->setBodyDef(rfd);
5405  }
5406 
5407  md->setRefItems(root->sli);
5408  }
5409 
5410  md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5411  md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5412 
5413  md->mergeMemberSpecifiers(root->spec);
5414  md->addSectionsToDefinition(root->anchors);
5415  addMemberToGroups(root,md);
5416  if (cd) cd->insertUsedFile(rfd);
5417  //printf("root->mGrpId=%d\n",root->mGrpId);
5418  if (root->mGrpId!=-1)
5419  {
5420  if (md->getMemberGroupId()!=-1)
5421  {
5422  if (md->getMemberGroupId()!=root->mGrpId)
5423  {
5424  warn(
5425  root->fileName,root->startLine,
5426  "member %s belongs to two different groups. The second "
5427  "one found here will be ignored.",
5428  md->name().data()
5429  );
5430  }
5431  }
5432  else // set group id
5433  {
5434  //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5435  md->setMemberGroupId(root->mGrpId);
5436  }
5437  }
5438 }
5439 
5440 //----------------------------------------------------------------------
5441 // find a class definition given the scope name and (optionally) a
5442 // template list specifier
5443 
5445  const char *scopeName)
5446 {
5447  ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5448  return tcd;
5449 }
5450 
5451 
5452 //----------------------------------------------------------------------
5453 // Adds the documentation contained in `root' to a global function
5454 // with name `name' and argument list `args' (for overloading) and
5455 // function declaration `decl' to the corresponding member definition.
5456 
5457 static bool findGlobalMember(EntryNav *rootNav,
5458  const QCString &namespaceName,
5459  const char *type,
5460  const char *name,
5461  const char *tempArg,
5462  const char *,
5463  const char *decl)
5464 {
5465  Entry *root = rootNav->entry();
5467  "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5468  qPrint(namespaceName),qPrint(type),qPrint(name),qPrint(tempArg),qPrint(decl));
5469  QCString n=name;
5470  if (n.isEmpty()) return FALSE;
5471  if (n.find("::")!=-1) return FALSE; // skip undefined class members
5472  MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5473  if (mn==0)
5474  {
5475  mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5476  }
5477  if (mn) // function name defined
5478  {
5479  Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5480  //int count=0;
5481  MemberNameIterator mni(*mn);
5482  MemberDef *md;
5483  bool found=FALSE;
5484  for (mni.toFirst();(md=mni.current()) && !found;++mni)
5485  {
5486  NamespaceDef *nd=md->getNamespaceDef();
5487 
5488  //printf("Namespace namespaceName=%s nd=%s\n",
5489  // namespaceName.data(),nd ? nd->name().data() : "<none>");
5490 
5491  FileDef *fd=rootNav->fileDef();
5492  //printf("File %s\n",fd ? fd->name().data() : "<none>");
5493  NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5494  //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0;
5495  //printf("NamespaceList %p\n",nl);
5496 
5497  // search in the list of namespaces that are imported via a
5498  // using declaration
5499  bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5500 
5501  if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
5502  (nd && nd->name()==namespaceName) || // or in the same namespace
5503  viaUsingDirective // member in `using' namespace
5504  )
5505  {
5506  Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5507  qPrint(md->name()),qPrint(namespaceName));
5508 
5509  NamespaceDef *rnd = 0;
5510  if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5511 
5512  ArgumentList *mdAl = md->argumentList();
5513  bool matching=
5514  (mdAl==0 && root->argList->count()==0) ||
5515  md->isVariable() || md->isTypedef() || /* in case of function pointers */
5516  matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl,
5517  rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5518  FALSE);
5519 
5520  // for template members we need to check if the number of
5521  // template arguments is the same, otherwise we are dealing with
5522  // different functions.
5523  if (matching && root->tArgLists)
5524  {
5525  ArgumentList *mdTempl = md->templateArguments();
5526  if (mdTempl)
5527  {
5528  if (root->tArgLists->getLast()->count()!=mdTempl->count())
5529  {
5530  matching=FALSE;
5531  }
5532  }
5533  }
5534 
5535  //printf("%s<->%s\n",
5536  // argListToString(md->argumentList()).data(),
5537  // argListToString(root->argList).data());
5538 
5539  // for static members we also check if the comment block was found in
5540  // the same file. This is needed because static members with the same
5541  // name can be in different files. Thus it would be wrong to just
5542  // put the comment block at the first syntactically matching member.
5543  if (matching && md->isStatic() &&
5544  md->getDefFileName()!=root->fileName &&
5545  mn->count()>1)
5546  {
5547  matching = FALSE;
5548  }
5549 
5550  // for template member we also need to check the return type
5551  if (md->templateArguments()!=0 && root->tArgLists!=0)
5552  {
5553  //printf("Comparing return types '%s'<->'%s'\n",
5554  // md->typeString(),type);
5555  if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
5556  qstrcmp(md->typeString(),type)!=0)
5557  {
5558  //printf(" ---> no matching\n");
5559  matching = FALSE;
5560  }
5561  }
5562 
5563  if (matching) // add docs to the member
5564  {
5565  Debug::print(Debug::FindMembers,0,"5. Match found\n");
5566  addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5567  found=TRUE;
5568  }
5569  }
5570  }
5571  if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5572  {
5573  QCString fullFuncDecl=decl;
5574  if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5575  QCString warnMsg =
5576  QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5577  if (mn->count()>0)
5578  {
5579  warnMsg+="\nPossible candidates:\n";
5580  for (mni.toFirst();(md=mni.current());++mni)
5581  {
5582  warnMsg+=" '";
5583  warnMsg+=substitute(md->declaration(),"%","%%");
5584  warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5585  " of file"+md->getDefFileName()+"\n";
5586  }
5587  }
5588  warn(root->fileName,root->startLine,warnMsg);
5589  }
5590  }
5591  else // got docs for an undefined member!
5592  {
5593  if (root->type!="friend class" &&
5594  root->type!="friend struct" &&
5595  root->type!="friend union" &&
5596  (!Config_getBool(TYPEDEF_HIDES_STRUCT) ||
5597  root->type.find("typedef ")==-1)
5598  )
5599  {
5600  warn(root->fileName,root->startLine,
5601  "documented symbol `%s' was not declared or defined.",decl
5602  );
5603  }
5604  }
5605  return TRUE;
5606 }
5607 
5608 static bool isSpecialization(
5609  const QList<ArgumentList> &srcTempArgLists,
5610  const QList<ArgumentList> &dstTempArgLists
5611  )
5612 {
5613  QListIterator<ArgumentList> srclali(srcTempArgLists);
5614  QListIterator<ArgumentList> dstlali(dstTempArgLists);
5615  for (;srclali.current();++srclali,++dstlali)
5616  {
5617  ArgumentList *sal = srclali.current();
5618  ArgumentList *dal = dstlali.current();
5619  if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5620  }
5621  return FALSE;
5622 }
5623 
5625 {
5626  bool result=FALSE;
5627  if (d && d->definitionType()==Definition::TypeClass)
5628  {
5629  result = ((ClassDef*)d)->templateArguments() || scopeIsTemplate(d->getOuterScope());
5630  }
5631  return result;
5632 }
5633 
5635  const QList<ArgumentList> &srcTempArgLists,
5636  const QList<ArgumentList> &dstTempArgLists,
5637  ArgumentList *funcTempArgList, // can be used to match template specializations
5638  const QCString &src
5639  )
5640 {
5641  QCString dst;
5642  QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5643  //printf("type=%s\n",sa->type.data());
5644  int i,p=0,l;
5645  while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5646  {
5647  bool found=FALSE;
5648  dst+=src.mid(p,i-p);
5649  QCString name=src.mid(i,l);
5650 
5651  QListIterator<ArgumentList> srclali(srcTempArgLists);
5652  QListIterator<ArgumentList> dstlali(dstTempArgLists);
5653  for (;srclali.current() && !found;++srclali,++dstlali)
5654  {
5655  ArgumentListIterator tsali(*srclali.current());
5656  ArgumentListIterator tdali(*dstlali.current());
5657  ArgumentListIterator *fali=0;
5658  Argument *tsa =0,*tda=0, *fa=0;
5659  if (funcTempArgList)
5660  {
5661  fali = new ArgumentListIterator(*funcTempArgList);
5662  fa = fali->current();
5663  }
5664 
5665  for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5666  {
5667  tda = tdali.current();
5668  //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5669  // tsa->type.data(),tsa->name.data(),
5670  // tda->type.data(),tda->name.data());
5671  if (name==tsa->name)
5672  {
5673  if (tda && tda->name.isEmpty())
5674  {
5675  int vc=0;
5676  if (tda->type.left(6)=="class ") vc=6;
5677  else if (tda->type.left(9)=="typename ") vc=9;
5678  if (vc>0) // convert type=="class T" to type=="class" name=="T"
5679  {
5680  tda->name = tda->type.mid(vc);
5681  tda->type = tda->type.left(vc-1);
5682  }
5683  }
5684  if (tda && !tda->name.isEmpty())
5685  {
5686  name=tda->name; // substitute
5687  found=TRUE;
5688  }
5689  else if (fa)
5690  {
5691  name=fa->type;
5692  found=TRUE;
5693  }
5694  }
5695  if (tda)
5696  ++tdali;
5697  else if (fali)
5698  { ++(*fali); fa=fali->current(); }
5699  }
5700 
5701  delete fali;
5702  //printf(" srcList='%s' dstList='%s faList='%s'\n",
5703  // argListToString(srclali.current()).data(),
5704  // argListToString(dstlali.current()).data(),
5705  // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5706  }
5707  dst+=name;
5708  p=i+l;
5709  }
5710  dst+=src.right(src.length()-p);
5711  //printf(" substituteTemplatesInString(%s)=%s\n",
5712  // src.data(),dst.data());
5713  return dst;
5714 }
5715 
5717  const QList<ArgumentList> &srcTempArgLists,
5718  const QList<ArgumentList> &dstTempArgLists,
5719  ArgumentList *src,
5720  ArgumentList *dst,
5721  ArgumentList *funcTempArgs = 0
5722  )
5723 {
5724  ArgumentListIterator sali(*src);
5725  ArgumentListIterator dali(*dst);
5726  Argument *sa=0;
5727  Argument *da=dali.current();
5728 
5729  for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5730  {
5731  QCString dstType = substituteTemplatesInString(
5732  srcTempArgLists,dstTempArgLists,funcTempArgs,
5733  sa->type);
5734  QCString dstArray = substituteTemplatesInString(
5735  srcTempArgLists,dstTempArgLists,funcTempArgs,
5736  sa->array);
5737  if (da==0)
5738  {
5739  da=new Argument(*sa);
5740  dst->append(da);
5741  da->type=dstType;
5742  da->array=dstArray;
5743  da=0;
5744  }
5745  else
5746  {
5747  da->type=dstType;
5748  da->type=dstArray;
5749  ++dali;
5750  da=dali.current();
5751  }
5752  }
5753  dst->constSpecifier = src->constSpecifier;
5755  dst->pureSpecifier = src->pureSpecifier;
5757  srcTempArgLists,dstTempArgLists,
5758  funcTempArgs,src->trailingReturnType);
5759  //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5760  // argListToString(src).data(),argListToString(dst).data()
5761  // );
5762 }
5763 
5764 
5765 
5775 static void findMember(EntryNav *rootNav,
5776  QCString funcDecl,
5777  bool overloaded,
5778  bool isFunc
5779  )
5780 {
5781  Entry *root = rootNav->entry();
5782 
5784  "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5785  "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5786  "spec=%lld lang=%x\n",
5787  root,qPrint(funcDecl),qPrint(root->relates),overloaded,isFunc,root->mGrpId,
5788  root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5789  root->spec,root->lang
5790  );
5791 
5792  QCString scopeName;
5793  QCString className;
5794  QCString namespaceName;
5795  QCString funcType;
5796  QCString funcName;
5797  QCString funcArgs;
5798  QCString funcTempList;
5799  QCString exceptions;
5800  QCString funcSpec;
5801  bool isRelated=FALSE;
5802  bool isMemberOf=FALSE;
5803  bool isFriend=FALSE;
5804  bool done;
5805  do
5806  {
5807  done=TRUE;
5808  if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5809  {
5810  isFriend=TRUE;
5811  done=FALSE;
5812  }
5813  if (funcDecl.stripPrefix("inline "))
5814  {
5815  root->spec|=Entry::Inline;
5816  done=FALSE;
5817  }
5818  if (funcDecl.stripPrefix("explicit "))
5819  {
5820  root->spec|=Entry::Explicit;
5821  done=FALSE;
5822  }
5823  if (funcDecl.stripPrefix("mutable "))
5824  {
5825  root->spec|=Entry::Mutable;
5826  done=FALSE;
5827  }
5828  if (funcDecl.stripPrefix("virtual "))
5829  {
5830  done=FALSE;
5831  }
5832  } while (!done);
5833 
5834  // delete any ; from the function declaration
5835  int sep;
5836  while ((sep=funcDecl.find(';'))!=-1)
5837  {
5838  funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5839  }
5840 
5841  // make sure the first character is a space to simplify searching.
5842  if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5843 
5844  // remove some superfluous spaces
5845  funcDecl= substitute(
5846  substitute(
5847  substitute(funcDecl,"~ ","~"),
5848  ":: ","::"
5849  ),
5850  " ::","::"
5851  ).stripWhiteSpace();
5852 
5853  //printf("funcDecl=`%s'\n",funcDecl.data());
5854  if (isFriend && funcDecl.left(6)=="class ")
5855  {
5856  //printf("friend class\n");
5857  funcDecl=funcDecl.right(funcDecl.length()-6);
5858  funcName = funcDecl.copy();
5859  }
5860  else if (isFriend && funcDecl.left(7)=="struct ")
5861  {
5862  funcDecl=funcDecl.right(funcDecl.length()-7);
5863  funcName = funcDecl.copy();
5864  }
5865  else
5866  {
5867  // extract information from the declarations
5868  parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5869  funcArgs,funcTempList,exceptions
5870  );
5871  }
5872  //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5873  // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5874 
5875  // the class name can also be a namespace name, we decide this later.
5876  // if a related class name is specified and the class name could
5877  // not be derived from the function declaration, then use the
5878  // related field.
5879  //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5880  // scopeName.data(),className.data(),namespaceName.data());
5881  if (!root->relates.isEmpty())
5882  { // related member, prefix user specified scope
5883  isRelated=TRUE;
5884  isMemberOf=(root->relatesType == MemberOf);
5885  if (getClass(root->relates)==0 && !scopeName.isEmpty())
5886  {
5887  scopeName= mergeScopes(scopeName,root->relates);
5888  }
5889  else
5890  {
5891  scopeName = root->relates;
5892  }
5893  }
5894 
5895  if (root->relates.isEmpty() && rootNav->parent() &&
5896  ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5897  (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5898  ) &&
5899  !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName
5900  // with the scope in which it was found
5901  {
5902  QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5903  if (!scopeName.isEmpty() &&
5904  (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5905  {
5906  scopeName = joinedName;
5907  }
5908  else
5909  {
5910  scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5911  }
5912  }
5913  else // see if we can prefix a namespace or class that is used from the file
5914  {
5915  FileDef *fd=rootNav->fileDef();
5916  if (fd)
5917  {
5918  NamespaceSDict *fnl = fd->getUsedNamespaces();
5919  if (fnl)
5920  {
5921  QCString joinedName;
5922  NamespaceDef *fnd;
5923  NamespaceSDict::Iterator nsdi(*fnl);
5924  for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5925  {
5926  joinedName = fnd->name()+"::"+scopeName;
5927  if (Doxygen::namespaceSDict->find(joinedName))
5928  {
5929  scopeName=joinedName;
5930  break;
5931  }
5932  }
5933  }
5934  }
5935  }
5937  removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
5938 
5939  // funcSpec contains the last template specifiers of the given scope.
5940  // If this method does not have any template arguments or they are
5941  // empty while funcSpec is not empty we assume this is a
5942  // specialization of a method. If not, we clear the funcSpec and treat
5943  // this as a normal method of a template class.
5944  if (!(root->tArgLists &&
5945  root->tArgLists->count()>0 &&
5946  root->tArgLists->getFirst()->count()==0
5947  )
5948  )
5949  {
5950  funcSpec.resize(0);
5951  }
5952 
5953  // split scope into a namespace and a class part
5954  extractNamespaceName(scopeName,className,namespaceName,TRUE);
5955  //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5956  // scopeName.data(),className.data(),namespaceName.data());
5957 
5958  //namespaceName=removeAnonymousScopes(namespaceName);
5959  if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5960 
5961  //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5962  // merge class and namespace scopes again
5963  scopeName.resize(0);
5964  if (!namespaceName.isEmpty())
5965  {
5966  if (className.isEmpty())
5967  {
5968  scopeName=namespaceName;
5969  }
5970  else if (!root->relates.isEmpty() || // relates command with explicit scope
5971  !getClass(className)) // class name only exists in a namespace
5972  {
5973  scopeName=namespaceName+"::"+className;
5974  }
5975  else
5976  {
5977  scopeName=className;
5978  }
5979  }
5980  else if (!className.isEmpty())
5981  {
5982  scopeName=className;
5983  }
5984  //printf("new scope=`%s'\n",scopeName.data());
5985 
5986  QCString tempScopeName=scopeName;
5987  ClassDef *cd=getClass(scopeName);
5988  if (cd)
5989  {
5990  if (funcSpec.isEmpty())
5991  {
5992  int argListIndex=0;
5993  tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists,&argListIndex);
5994  }
5995  else
5996  {
5997  tempScopeName=scopeName+funcSpec;
5998  }
5999  }
6000  //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
6001  // scopeName.data(),cd,root->tArgLists,tempScopeName.data());
6002 
6003  //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6004  // rebuild the function declaration (needed to get the scope right).
6005  if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool(HIDE_SCOPE_NAMES))
6006  {
6007  if (!funcType.isEmpty())
6008  {
6009  if (isFunc) // a function -> we use argList for the arguments
6010  {
6011  funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
6012  }
6013  else
6014  {
6015  funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
6016  }
6017  }
6018  else
6019  {
6020  if (isFunc) // a function => we use argList for the arguments
6021  {
6022  funcDecl=tempScopeName+"::"+funcName+funcTempList;
6023  }
6024  else // variable => add `argument' list
6025  {
6026  funcDecl=tempScopeName+"::"+funcName+funcArgs;
6027  }
6028  }
6029  }
6030  else // build declaration without scope
6031  {
6032  if (!funcType.isEmpty()) // but with a type
6033  {
6034  if (isFunc) // function => omit argument list
6035  {
6036  funcDecl=funcType+" "+funcName+funcTempList;
6037  }
6038  else // variable => add `argument' list
6039  {
6040  funcDecl=funcType+" "+funcName+funcArgs;
6041  }
6042  }
6043  else // no type
6044  {
6045  if (isFunc)
6046  {
6047  funcDecl=funcName+funcTempList;
6048  }
6049  else
6050  {
6051  funcDecl=funcName+funcArgs;
6052  }
6053  }
6054  }
6055 
6056  if (funcType=="template class" && !funcTempList.isEmpty())
6057  return; // ignore explicit template instantiations
6058 
6060  "findMember() Parse results:\n"
6061  " namespaceName=`%s'\n"
6062  " className=`%s`\n"
6063  " funcType=`%s'\n"
6064  " funcSpec=`%s'\n"
6065  " funcName=`%s'\n"
6066  " funcArgs=`%s'\n"
6067  " funcTempList=`%s'\n"
6068  " funcDecl=`%s'\n"
6069  " related=`%s'\n"
6070  " exceptions=`%s'\n"
6071  " isRelated=%d\n"
6072  " isMemberOf=%d\n"
6073  " isFriend=%d\n"
6074  " isFunc=%d\n\n",
6075  qPrint(namespaceName),qPrint(className),
6076  qPrint(funcType),qPrint(funcSpec),qPrint(funcName),qPrint(funcArgs),qPrint(funcTempList),
6077  qPrint(funcDecl),qPrint(root->relates),qPrint(exceptions),isRelated,isMemberOf,isFriend,
6078  isFunc
6079  );
6080 
6081  MemberName *mn=0;
6082  if (!funcName.isEmpty()) // function name is valid
6083  {
6085  "1. funcName=`%s'\n",funcName.data());
6086  if (funcName.left(9)=="operator ") // strip class scope from cast operator
6087  {
6088  funcName = substitute(funcName,className+"::","");
6089  }
6090  if (!funcTempList.isEmpty()) // try with member specialization
6091  {
6092  mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
6093  }
6094  if (mn==0) // try without specialization
6095  {
6096  mn=Doxygen::memberNameSDict->find(funcName);
6097  }
6098  if (!isRelated && mn) // function name already found
6099  {
6101  "2. member name exists (%d members with this name)\n",mn->count());
6102  if (!className.isEmpty()) // class name is valid
6103  {
6104  if (funcSpec.isEmpty()) // not a member specialization
6105  {
6106  int count=0;
6107  int noMatchCount=0;
6108  MemberNameIterator mni(*mn);
6109  MemberDef *md;
6110  bool memFound=FALSE;
6111  for (mni.toFirst();!memFound && (md=mni.current());++mni)
6112  {
6113  ClassDef *cd=md->getClassDef();
6115  "3. member definition found, "
6116  "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
6117  qPrint(scopeName),cd ? qPrint(cd->name()) : "<none>",
6118  qPrint(md->argsString()),
6119  qPrint(root->fileName));
6120  //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
6121  FileDef *fd=rootNav->fileDef();
6122  NamespaceDef *nd=0;
6123  if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
6124 
6125  //printf("scopeName %s->%s\n",scopeName.data(),
6126  // stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
6127 
6128  ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
6129  if (tcd==0 && cd && stripAnonymousNamespaceScope(cd->name())==scopeName)
6130  {
6131  // don't be fooled by anonymous scopes
6132  tcd=cd;
6133  }
6134  //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
6135  // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
6136 
6137  if (cd && tcd==cd) // member's classes match
6138  {
6140  "4. class definition %s found\n",cd->name().data());
6141 
6142  // get the template parameter lists found at the member declaration
6143  QList<ArgumentList> declTemplArgs;
6144  cd->getTemplateParameterLists(declTemplArgs);
6145  ArgumentList *templAl = md->templateArguments();
6146  if (templAl)
6147  {
6148  declTemplArgs.append(templAl);
6149  }
6150 
6151  // get the template parameter lists found at the member definition
6152  QList<ArgumentList> *defTemplArgs = root->tArgLists;
6153  //printf("defTemplArgs=%p\n",defTemplArgs);
6154 
6155  // do we replace the decl argument lists with the def argument lists?
6156  bool substDone=FALSE;
6157  ArgumentList *argList=0;
6158 
6159  /* substitute the occurrences of class template names in the
6160  * argument list before matching
6161  */
6162  ArgumentList *mdAl = md->argumentList();
6163  if (declTemplArgs.count()>0 && defTemplArgs &&
6164  declTemplArgs.count()==defTemplArgs->count() &&
6165  mdAl
6166  )
6167  {
6168  /* the function definition has template arguments
6169  * and the class definition also has template arguments, so
6170  * we must substitute the template names of the class by that
6171  * of the function definition before matching.
6172  */
6173  argList = new ArgumentList;
6174  substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
6175  mdAl,argList);
6176 
6177  substDone=TRUE;
6178  }
6179  else /* no template arguments, compare argument lists directly */
6180  {
6181  argList = mdAl;
6182  }
6183 
6185  "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
6186  qPrint(argListToString(argList,TRUE)),qPrint(argListToString(root->argList,TRUE)),
6187  qPrint(className),qPrint(namespaceName)
6188  );
6189 
6190  bool matching=
6191  md->isVariable() || md->isTypedef() || // needed for function pointers
6192  (mdAl==0 && root->argList->count()==0) ||
6194  md->getClassDef(),md->getFileDef(),argList,
6195  cd,fd,root->argList,
6196  TRUE);
6197 
6198  if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
6199  {
6200  matching = FALSE; // don't match methods and attributes with the same name
6201  }
6202 
6203  // for template member we also need to check the return type
6204  if (md->templateArguments()!=0 && root->tArgLists!=0)
6205  {
6206  QCString memType = md->typeString();
6207  memType.stripPrefix("static "); // see bug700696
6208  funcType=substitute(stripTemplateSpecifiersFromScope(funcType,TRUE),
6209  className+"::",""); // see bug700693 & bug732594
6210  memType=substitute(stripTemplateSpecifiersFromScope(memType,TRUE),
6211  className+"::",""); // see bug758900
6213  "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
6214  qPrint(md->typeString()),qPrint(funcType),
6215  md->templateArguments()->count(),root->tArgLists->getLast()->count());
6216  if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
6217  qstrcmp(memType,funcType))
6218  {
6219  //printf(" ---> no matching\n");
6220  matching = FALSE;
6221  }
6222  }
6223  bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
6224  bool classIsTemplate = scopeIsTemplate(md->getClassDef());
6225  bool mdIsTemplate = md->templateArguments()!=0;
6226  bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
6227  bool rootIsTemplate = root->tArgLists!=0;
6228  //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
6229  if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
6230  (mdIsTemplate || rootIsTemplate) && // either md or root is a template
6231  ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
6232  )
6233  {
6234  // Method with template return type does not match method without return type
6235  // even if the parameters are the same. See also bug709052
6237  "5b. Comparing return types: template v.s. non-template\n");
6238  matching = FALSE;
6239  }
6240 
6241 
6243  "6. match results of matchArguments2 = %d\n",matching);
6244 
6245  if (substDone) // found a new argument list
6246  {
6247  if (matching) // replace member's argument list
6248  {
6249  md->setDefinitionTemplateParameterLists(root->tArgLists);
6250  md->setArgumentList(argList); // new owner of the list => no delete
6251  }
6252  else // no match
6253  {
6254  if (!funcTempList.isEmpty() &&
6255  isSpecialization(declTemplArgs,*defTemplArgs))
6256  {
6257  // check if we are dealing with a partial template
6258  // specialization. In this case we add it to the class
6259  // even though the member arguments do not match.
6260 
6261  // TODO: copy other aspects?
6262  root->protection=md->protection(); // copy protection level
6263  addMethodToClass(rootNav,cd,md->name(),isFriend);
6264  return;
6265  }
6266  delete argList;
6267  }
6268  }
6269  if (matching)
6270  {
6271  addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
6272  count++;
6273  memFound=TRUE;
6274  }
6275  }
6276  else if (cd && cd!=tcd) // we did find a class with the same name as cd
6277  // but in a different namespace
6278  {
6279  noMatchCount++;
6280  }
6281  }
6282  if (count==0 && rootNav->parent() &&
6283  rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6284  {
6285  goto localObjCMethod;
6286  }
6287  if (count==0 && !(isFriend && funcType=="class"))
6288  {
6289  int candidates=0;
6290  ClassDef *ecd = 0, *ucd = 0;
6291  MemberDef *emd = 0, *umd = 0;
6292  if (mn->count()>0)
6293  {
6294  //printf("Assume template class\n");
6295  for (mni.toFirst();(md=mni.current());++mni)
6296  {
6297  ClassDef *ccd=md->getClassDef();
6298  MemberDef *cmd=md;
6299  //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
6300  if (ccd!=0 && rightScopeMatch(ccd->name(),className))
6301  {
6302  ArgumentList *templAl = md->templateArguments();
6303  if (root->tArgLists && templAl!=0 &&
6304  root->tArgLists->getLast()->count()<=templAl->count())
6305  {
6306  addMethodToClass(rootNav,ccd,md->name(),isFriend);
6307  return;
6308  }
6309  if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
6310  { // exact argument list match -> remember
6311  ucd = ecd = ccd;
6312  umd = emd = cmd;
6314  "7. new candidate className=%s scope=%s args=%s exact match\n",
6315  qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6316  }
6317  else // arguments do not match, but member name and scope do -> remember
6318  {
6319  ucd = ccd;
6320  umd = cmd;
6322  "7. new candidate className=%s scope=%s args=%s no match\n",
6323  qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6324  }
6325  candidates++;
6326  }
6327  }
6328  }
6329  static bool strictProtoMatching = Config_getBool(STRICT_PROTO_MATCHING);
6330  if (!strictProtoMatching)
6331  {
6332  if (candidates==1 && ucd && umd)
6333  {
6334  // we didn't find an actual match on argument lists, but there is only 1 member with this
6335  // name in the same scope, so that has to be the one.
6336  addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
6337  return;
6338  }
6339  else if (candidates>1 && ecd && emd)
6340  {
6341  // we didn't find a unique match using type resolution,
6342  // but one of the matches has the exact same signature so
6343  // we take that one.
6344  addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
6345  return;
6346  }
6347  }
6348 
6349  QCString warnMsg = "no ";
6350  if (noMatchCount>1) warnMsg+="uniquely ";
6351  warnMsg+="matching class member found for \n";
6352 
6353  if (root->tArgLists)
6354  {
6355  QListIterator<ArgumentList> alli(*root->tArgLists);
6356  ArgumentList *al;
6357  for (;(al=alli.current());++alli)
6358  {
6359  warnMsg+=" template ";
6360  warnMsg+=tempArgListToString(al,root->lang);
6361  warnMsg+='\n';
6362  }
6363  }
6364  QCString fullFuncDecl=funcDecl.copy();
6365  if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6366 
6367  warnMsg+=" ";
6368  warnMsg+=fullFuncDecl;
6369  warnMsg+='\n';
6370 
6371  if (candidates>0)
6372  {
6373  warnMsg+="Possible candidates:\n";
6374  for (mni.toFirst();(md=mni.current());++mni)
6375  {
6376  ClassDef *cd=md->getClassDef();
6377  if (cd!=0 && rightScopeMatch(cd->name(),className))
6378  {
6379  ArgumentList *templAl = md->templateArguments();
6380  if (templAl!=0)
6381  {
6382  warnMsg+=" 'template ";
6383  warnMsg+=tempArgListToString(templAl,root->lang);
6384  warnMsg+='\n';
6385  }
6386  warnMsg+=" ";
6387  if (md->typeString())
6388  {
6389  warnMsg+=md->typeString();
6390  warnMsg+=' ';
6391  }
6392  QCString qScope = cd->qualifiedNameWithTemplateParameters();
6393  if (!qScope.isEmpty())
6394  warnMsg+=qScope+"::"+md->name();
6395  if (md->argsString())
6396  warnMsg+=md->argsString();
6397  if (noMatchCount>1)
6398  {
6399  warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6400  " of file "+md->getDefFileName();
6401  }
6402 
6403  warnMsg+='\n';
6404  }
6405  }
6406  }
6407  warn_simple(root->fileName,root->startLine,warnMsg);
6408  }
6409  }
6410  else if (cd) // member specialization
6411  {
6412  MemberNameIterator mni(*mn);
6413  MemberDef *declMd=0;
6414  MemberDef *md=0;
6415  for (mni.toFirst();(md=mni.current());++mni)
6416  {
6417  if (md->getClassDef()==cd)
6418  {
6419  // TODO: we should probably also check for matching arguments
6420  declMd = md;
6421  break;
6422  }
6423  }
6425  ArgumentList *tArgList = new ArgumentList;
6426  // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6427  md=new MemberDef(
6428  root->fileName,root->startLine,root->startColumn,
6429  funcType,funcName,funcArgs,exceptions,
6430  declMd ? declMd->protection() : root->protection,
6431  root->virt,root->stat,Member,
6432  mtype,tArgList,root->argList);
6433  //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6434  md->setTagInfo(rootNav->tagInfo());
6435  md->setLanguage(root->lang);
6436  md->setId(root->id);
6437  md->setMemberClass(cd);
6438  md->setTemplateSpecialization(TRUE);
6439  md->setTypeConstraints(root->typeConstr);
6440  md->setDefinition(funcDecl);
6441  md->enableCallGraph(root->callGraph);
6442  md->enableCallerGraph(root->callerGraph);
6443  md->setDocumentation(root->doc,root->docFile,root->docLine);
6444  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6445  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6446  md->setDocsForDefinition(!root->proto);
6447  md->setPrototype(root->proto);
6448  md->addSectionsToDefinition(root->anchors);
6449  md->setBodySegment(root->bodyLine,root->endBodyLine);
6450  FileDef *fd=rootNav->fileDef();
6451  md->setBodyDef(fd);
6452  md->setMemberSpecifiers(root->spec);
6453  md->setMemberGroupId(root->mGrpId);
6454  mn->append(md);
6455  cd->insertMember(md);
6456  md->setRefItems(root->sli);
6457  delete tArgList;
6458  }
6459  else
6460  {
6461  //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6462  // scopeName.data(),funcName.data(),funcArgs.data());
6463  }
6464  }
6465  else if (overloaded) // check if the function belongs to only one class
6466  {
6467  // for unique overloaded member we allow the class to be
6468  // omitted, this is to be Qt compatible. Using this should
6469  // however be avoided, because it is error prone
6470  MemberNameIterator mni(*mn);
6471  MemberDef *md=mni.toFirst();
6472  ASSERT(md);
6473  ClassDef *cd=md->getClassDef();
6474  ASSERT(cd);
6475  QCString className=cd->name().copy();
6476  ++mni;
6477  bool unique=TRUE;
6478  for (;(md=mni.current());++mni)
6479  {
6480  ClassDef *cd=md->getClassDef();
6481  if (className!=cd->name()) unique=FALSE;
6482  }
6483  if (unique)
6484  {
6485  MemberType mtype;
6486  if (root->mtype==Signal) mtype=MemberType_Signal;
6487  else if (root->mtype==Slot) mtype=MemberType_Slot;
6488  else if (root->mtype==DCOP) mtype=MemberType_DCOP;
6489  else mtype=MemberType_Function;
6490 
6491  // new overloaded member function
6492  ArgumentList *tArgList =
6493  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6494  //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6495  MemberDef *md=new MemberDef(
6496  root->fileName,root->startLine,root->startColumn,
6497  funcType,funcName,funcArgs,exceptions,
6498  root->protection,root->virt,root->stat,Related,
6499  mtype,tArgList,root->argList);
6500  md->setTagInfo(rootNav->tagInfo());
6501  md->setLanguage(root->lang);
6502  md->setId(root->id);
6503  md->setTypeConstraints(root->typeConstr);
6504  md->setMemberClass(cd);
6505  md->setDefinition(funcDecl);
6506  md->enableCallGraph(root->callGraph);
6507  md->enableCallerGraph(root->callerGraph);
6508  QCString doc=getOverloadDocs();
6509  doc+="<p>";
6510  doc+=root->doc;
6511  md->setDocumentation(doc,root->docFile,root->docLine);
6512  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6513  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6514  md->setDocsForDefinition(!root->proto);
6515  md->setPrototype(root->proto);
6516  md->addSectionsToDefinition(root->anchors);
6517  md->setBodySegment(root->bodyLine,root->endBodyLine);
6518  FileDef *fd=rootNav->fileDef();
6519  md->setBodyDef(fd);
6520  md->setMemberSpecifiers(root->spec);
6521  md->setMemberGroupId(root->mGrpId);
6522  mn->append(md);
6523  cd->insertMember(md);
6524  cd->insertUsedFile(fd);
6525  md->setRefItems(root->sli);
6526  }
6527  }
6528  else // unrelated function with the same name as a member
6529  {
6530  if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6531  {
6532  QCString fullFuncDecl=funcDecl.copy();
6533  if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6534  warn(root->fileName,root->startLine,
6535  "Cannot determine class for function\n%s",
6536  fullFuncDecl.data()
6537  );
6538  }
6539  }
6540  }
6541  else if (isRelated && !root->relates.isEmpty())
6542  {
6543  Debug::print(Debug::FindMembers,0,"2. related function\n"
6544  " scopeName=%s className=%s\n",qPrint(scopeName),qPrint(className));
6545  if (className.isEmpty()) className=root->relates;
6546  ClassDef *cd;
6547  //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6548  if ((cd=getClass(scopeName)))
6549  {
6550  bool newMember=TRUE; // assume we have a new member
6551  bool newMemberName=FALSE;
6552  MemberDef *mdDefine=0;
6553  bool isDefine=FALSE;
6554  {
6555  MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6556  if (mn)
6557  {
6558  MemberNameIterator mni(*mn);
6559  mdDefine = mni.current();
6560  while (mdDefine && !isDefine)
6561  {
6562  isDefine = isDefine || mdDefine->isDefine();
6563  if (!isDefine) { ++mni; mdDefine=mni.current(); }
6564  }
6565  }
6566  }
6567 
6568  FileDef *fd=rootNav->fileDef();
6569 
6570  if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6571  {
6572  mn=new MemberName(funcName);
6573  newMemberName=TRUE; // we create a new member name
6574  }
6575  else
6576  {
6577  MemberNameIterator mni(*mn);
6578  MemberDef *rmd;
6579  while ((rmd=mni.current()) && newMember) // see if we got another member with matching arguments
6580  {
6581  ArgumentList *rmdAl = rmd->argumentList();
6582 
6583  newMember=
6584  className!=rmd->getOuterScope()->name() ||
6585  !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6586  cd,fd,root->argList,
6587  TRUE);
6588  if (newMember) ++mni;
6589  }
6590  if (!newMember && rmd) // member already exists as rmd -> add docs
6591  {
6592  //printf("addMemberDocs for related member %s\n",root->name.data());
6593  //rmd->setMemberDefTemplateArguments(root->mtArgList);
6594  addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6595  }
6596  }
6597 
6598  if (newMember) // need to create a new member
6599  {
6600  MemberType mtype;
6601  if (isDefine)
6602  mtype=MemberType_Define;
6603  else if (root->mtype==Signal)
6604  mtype=MemberType_Signal;
6605  else if (root->mtype==Slot)
6606  mtype=MemberType_Slot;
6607  else if (root->mtype==DCOP)
6608  mtype=MemberType_DCOP;
6609  else
6610  mtype=MemberType_Function;
6611 
6612  if (isDefine && mdDefine)
6613  {
6614  mdDefine->setHidden(TRUE);
6615  funcType="#define";
6616  funcArgs=mdDefine->argsString();
6617  funcDecl=funcType + " " + funcName;
6618  }
6619 
6620  //printf("New related name `%s' `%d'\n",funcName.data(),
6621  // root->argList ? (int)root->argList->count() : -1);
6622 
6623  // first note that we pass:
6624  // (root->tArgLists ? root->tArgLists->last() : 0)
6625  // for the template arguments fo the new "member."
6626  // this accurately reflects the template arguments of
6627  // the related function, which don't have to do with
6628  // those of the related class.
6629  MemberDef *md=new MemberDef(
6630  root->fileName,root->startLine,root->startColumn,
6631  funcType,funcName,funcArgs,exceptions,
6632  root->protection,root->virt,
6633  root->stat && !isMemberOf,
6634  isMemberOf ? Foreign : Related,
6635  mtype,
6636  (root->tArgLists ? root->tArgLists->getLast() : 0),
6637  funcArgs.isEmpty() ? 0 : root->argList);
6638 
6639  if (isDefine && mdDefine)
6640  {
6641  md->setInitializer(mdDefine->initializer());
6642  }
6643 
6644  //
6645  // we still have the problem that
6646  // MemberDef::writeDocumentation() in memberdef.cpp
6647  // writes the template argument list for the class,
6648  // as if this member is a member of the class.
6649  // fortunately, MemberDef::writeDocumentation() has
6650  // a special mechanism that allows us to totally
6651  // override the set of template argument lists that
6652  // are printed. We use that and set it to the
6653  // template argument lists of the related function.
6654  //
6656 
6657  md->setTagInfo(rootNav->tagInfo());
6658 
6659 
6660 
6661  //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6662  // funcName.data(),funcDecl.data(),root->bodyLine);
6663 
6664  // try to find the matching line number of the body from the
6665  // global function list
6666  bool found=FALSE;
6667  if (root->bodyLine==-1)
6668  {
6669  MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6670  if (rmn)
6671  {
6672  MemberNameIterator rmni(*rmn);
6673  MemberDef *rmd;
6674  while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
6675  {
6676  ArgumentList *rmdAl = rmd->argumentList();
6677  // check for matching argument lists
6678  if (
6679  matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6680  cd,fd,root->argList,
6681  TRUE)
6682  )
6683  {
6684  found=TRUE;
6685  }
6686  if (!found) ++rmni;
6687  }
6688  if (rmd) // member found -> copy line number info
6689  {
6690  md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6691  md->setBodyDef(rmd->getBodyDef());
6692  //md->setBodyMember(rmd);
6693  }
6694  }
6695  }
6696  if (!found) // line number could not be found or is available in this
6697  // entry
6698  {
6699  md->setBodySegment(root->bodyLine,root->endBodyLine);
6700  md->setBodyDef(fd);
6701  }
6702 
6703  //if (root->mGrpId!=-1)
6704  //{
6705  // md->setMemberGroup(memberGroupDict[root->mGrpId]);
6706  //}
6707  md->setMemberClass(cd);
6708  md->setMemberSpecifiers(root->spec);
6709  md->setDefinition(funcDecl);
6710  md->enableCallGraph(root->callGraph);
6711  md->enableCallerGraph(root->callerGraph);
6712  md->setDocumentation(root->doc,root->docFile,root->docLine);
6713  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6714  md->setDocsForDefinition(!root->proto);
6715  md->setPrototype(root->proto);
6716  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6717  md->addSectionsToDefinition(root->anchors);
6718  md->setMemberGroupId(root->mGrpId);
6719  md->setLanguage(root->lang);
6720  md->setId(root->id);
6721  //md->setMemberDefTemplateArguments(root->mtArgList);
6722  mn->append(md);
6723  cd->insertMember(md);
6724  cd->insertUsedFile(fd);
6725  md->setRefItems(root->sli);
6726  if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6727  if (!isDefine)
6728  {
6729  addMemberToGroups(root,md);
6730  }
6731  //printf("Adding member=%s\n",md->name().data());
6732  if (newMemberName)
6733  {
6734  //Doxygen::memberNameList.append(mn);
6735  //Doxygen::memberNameDict.insert(funcName,mn);
6736  Doxygen::memberNameSDict->append(funcName,mn);
6737  }
6738  }
6739  if (root->relatesType == Duplicate)
6740  {
6741  if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6742  {
6743  QCString fullFuncDecl=funcDecl.copy();
6744  if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6745  warn(root->fileName,root->startLine,
6746  "Cannot determine file/namespace for relatedalso function\n%s",
6747  fullFuncDecl.data()
6748  );
6749  }
6750  }
6751  }
6752  else
6753  {
6754  warn_undoc(root->fileName,root->startLine,
6755  "class `%s' for related function `%s' is not "
6756  "documented.",
6757  className.data(),funcName.data()
6758  );
6759  }
6760  }
6761  else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6762  {
6763 localObjCMethod:
6764  ClassDef *cd;
6765  //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6766  if (Config_getBool(EXTRACT_LOCAL_METHODS) && (cd=getClass(scopeName)))
6767  {
6768  Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6769  " scopeName=%s className=%s\n",qPrint(root->name),qPrint(scopeName),qPrint(className));
6770  //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6771  MemberDef *md=new MemberDef(
6772  root->fileName,root->startLine,root->startColumn,
6773  funcType,funcName,funcArgs,exceptions,
6774  root->protection,root->virt,root->stat,Member,
6775  MemberType_Function,0,root->argList);
6776  md->setTagInfo(rootNav->tagInfo());
6777  md->setLanguage(root->lang);
6778  md->setId(root->id);
6780  md->setMemberClass(cd);
6781  md->setDefinition(funcDecl);
6782  md->enableCallGraph(root->callGraph);
6783  md->enableCallerGraph(root->callerGraph);
6784  md->setDocumentation(root->doc,root->docFile,root->docLine);
6785  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6786  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6787  md->setDocsForDefinition(!root->proto);
6788  md->setPrototype(root->proto);
6789  md->addSectionsToDefinition(root->anchors);
6790  md->setBodySegment(root->bodyLine,root->endBodyLine);
6791  FileDef *fd=rootNav->fileDef();
6792  md->setBodyDef(fd);
6793  md->setMemberSpecifiers(root->spec);
6794  md->setMemberGroupId(root->mGrpId);
6795  cd->insertMember(md);
6796  cd->insertUsedFile(fd);
6797  md->setRefItems(root->sli);
6798  if ((mn=Doxygen::memberNameSDict->find(root->name)))
6799  {
6800  mn->append(md);
6801  }
6802  else
6803  {
6804  mn = new MemberName(root->name);
6805  mn->append(md);
6806  Doxygen::memberNameSDict->append(root->name,mn);
6807  }
6808  }
6809  else
6810  {
6811  // local objective C method found for class without interface
6812  }
6813  }
6814  else // unrelated not overloaded member found
6815  {
6816  bool globMem = findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl);
6817  if (className.isEmpty() && !globMem)
6818  {
6819  warn(root->fileName,root->startLine,
6820  "class for member `%s' cannot "
6821  "be found.", funcName.data()
6822  );
6823  }
6824  else if (!className.isEmpty() && !globMem)
6825  {
6826  warn(root->fileName,root->startLine,
6827  "member `%s' of class `%s' cannot be found",
6828  funcName.data(),className.data());
6829  }
6830  }
6831  }
6832  else
6833  {
6834  // this should not be called
6835  warn(root->fileName,root->startLine,
6836  "member with no name found.");
6837  }
6838  return;
6839 }
6840 
6841 //----------------------------------------------------------------------
6842 // find the members corresponding to the different documentation blocks
6843 // that are extracted from the sources.
6844 
6846 {
6847  Entry *root = rootNav->entry();
6848  int i=-1,l;
6850  "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6851  qPrint(root->type),qPrint(root->inside),qPrint(root->name),qPrint(root->args),root->section,root->spec,root->mGrpId
6852  );
6853  //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6854  bool isFunc=TRUE;
6855 
6856  if (root->relatesType == Duplicate && !root->relates.isEmpty())
6857  {
6858  QCString tmp = root->relates;
6859  root->relates.resize(0);
6860  filterMemberDocumentation(rootNav);
6861  root->relates = tmp;
6862  }
6863 
6864  if ( // detect func variable/typedef to func ptr
6865  (i=findFunctionPtr(root->type,root->lang,&l))!=-1
6866  )
6867  {
6868  //printf("Fixing function pointer!\n");
6869  // fix type and argument
6870  root->args.prepend(root->type.right(root->type.length()-i-l));
6871  root->type=root->type.left(i+l);
6872  //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6873  isFunc=FALSE;
6874  }
6875  else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1))
6876  // detect function types marked as functions
6877  {
6878  isFunc=FALSE;
6879  }
6880 
6881  //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6882  if (root->section==Entry::MEMBERDOC_SEC)
6883  {
6884  //printf("Documentation for inline member `%s' found args=`%s'\n",
6885  // root->name.data(),root->args.data());
6886  //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6887  if (root->type.isEmpty())
6888  {
6889  findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6890  }
6891  else
6892  {
6893  findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6894  }
6895  }
6896  else if (root->section==Entry::OVERLOADDOC_SEC)
6897  {
6898  //printf("Overloaded member %s found\n",root->name.data());
6899  findMember(rootNav,root->name,TRUE,isFunc);
6900  }
6901  else if
6902  ((root->section==Entry::FUNCTION_SEC // function
6903  ||
6904  (root->section==Entry::VARIABLE_SEC && // variable
6905  !root->type.isEmpty() && // with a type
6906  g_compoundKeywordDict.find(root->type)==0 // that is not a keyword
6907  // (to skip forward declaration of class etc.)
6908  )
6909  )
6910  )
6911  {
6912  //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6913  // root->name.data(),root->args.data(),root->exception.data());
6914  //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6915  //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6916  if (root->type=="friend class" || root->type=="friend struct" ||
6917  root->type=="friend union")
6918  {
6919  findMember(rootNav,
6920  root->type+" "+
6921  root->name,
6922  FALSE,FALSE);
6923 
6924  }
6925  else if (!root->type.isEmpty())
6926  {
6927  findMember(rootNav,
6928  root->type+" "+
6929  root->inside+
6930  root->name+
6931  root->args+
6932  root->exception,
6933  FALSE,isFunc);
6934  }
6935  else
6936  {
6937  findMember(rootNav,
6938  root->inside+
6939  root->name+
6940  root->args+
6941  root->exception,
6942  FALSE,isFunc);
6943  }
6944  }
6945  else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6946  {
6947  findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6948  }
6949  else if (root->section==Entry::VARIABLEDOC_SEC)
6950  {
6951  //printf("Documentation for variable %s found\n",root->name.data());
6952  //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data());
6953  findMember(rootNav,root->name,FALSE,FALSE);
6954  }
6955  else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
6957  {
6958  findMember(rootNav,root->type + " " + root->name,FALSE,FALSE);
6959  }
6960  else
6961  {
6962  // skip section
6963  //printf("skip section\n");
6964  }
6965 }
6966 
6967 static void findMemberDocumentation(EntryNav *rootNav)
6968 {
6969  if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6970  rootNav->section()==Entry::OVERLOADDOC_SEC ||
6971  rootNav->section()==Entry::FUNCTION_SEC ||
6972  rootNav->section()==Entry::VARIABLE_SEC ||
6973  rootNav->section()==Entry::VARIABLEDOC_SEC ||
6974  rootNav->section()==Entry::DEFINE_SEC ||
6975  rootNav->section()==Entry::INCLUDED_SERVICE_SEC ||
6977  )
6978  {
6979  rootNav->loadEntry(g_storage);
6980 
6981  filterMemberDocumentation(rootNav);
6982 
6983  rootNav->releaseEntry();
6984  }
6985  if (rootNav->children())
6986  {
6987  EntryNavListIterator eli(*rootNav->children());
6988  EntryNav *e;
6989  for (;(e=eli.current());++eli)
6990  {
6991  if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6992  }
6993  }
6994 }
6995 
6996 //----------------------------------------------------------------------
6997 
6999 {
7000  if (rootNav->children())
7001  {
7002  EntryNavListIterator eli(*rootNav->children());
7003  EntryNav *objCImplNav;
7004  for (;(objCImplNav=eli.current());++eli)
7005  {
7006  if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
7007  {
7008  EntryNavListIterator seli(*objCImplNav->children());
7009  EntryNav *objCMethodNav;
7010  for (;(objCMethodNav=seli.current());++seli)
7011  {
7012  if (objCMethodNav->section()==Entry::FUNCTION_SEC)
7013  {
7014  objCMethodNav->loadEntry(g_storage);
7015  Entry *objCMethod = objCMethodNav->entry();
7016 
7017  //Printf(" Found ObjC method definition %s\n",objCMethod->name.data());
7018  findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
7019  objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
7020  objCMethod->section=Entry::EMPTY_SEC;
7021 
7022  objCMethodNav->releaseEntry();
7023  }
7024  }
7025  }
7026  }
7027  }
7028 }
7029 
7030 //----------------------------------------------------------------------
7031 // find and add the enumeration to their classes, namespaces or files
7032 
7033 static void findEnums(EntryNav *rootNav)
7034 {
7035  if (rootNav->section()==Entry::ENUM_SEC)
7036  {
7037  rootNav->loadEntry(g_storage);
7038  Entry *root = rootNav->entry();
7039 
7040  MemberDef *md=0;
7041  ClassDef *cd=0;
7042  FileDef *fd=0;
7043  NamespaceDef *nd=0;
7044  MemberNameSDict *mnsd=0;
7045  bool isGlobal;
7046  bool isRelated=FALSE;
7047  bool isMemberOf=FALSE;
7048  //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7049  int i;
7050 
7051  QCString name;
7052  QCString scope;
7053 
7054  if ((i=root->name.findRev("::"))!=-1) // scope is specified
7055  {
7056  scope=root->name.left(i); // extract scope
7057  name=root->name.right(root->name.length()-i-2); // extract name
7058  if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7059  }
7060  else // no scope, check the scope in which the docs where found
7061  {
7062  if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7063  && !rootNav->parent()->name().isEmpty()
7064  ) // found enum docs inside a compound
7065  {
7066  scope=rootNav->parent()->name();
7067  if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7068  }
7069  name=root->name;
7070  }
7071 
7072  if (!root->relates.isEmpty())
7073  { // related member, prefix user specified scope
7074  isRelated=TRUE;
7075  isMemberOf=(root->relatesType == MemberOf);
7076  if (getClass(root->relates)==0 && !scope.isEmpty())
7077  scope=mergeScopes(scope,root->relates);
7078  else
7079  scope=root->relates.copy();
7080  if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7081  }
7082 
7083  if (cd && !name.isEmpty()) // found a enum inside a compound
7084  {
7085  //printf("Enum `%s'::`%s'\n",cd->name().data(),name.data());
7086  fd=0;
7088  isGlobal=FALSE;
7089  }
7090  else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7091  {
7093  isGlobal=TRUE;
7094  }
7095  else // found a global enum
7096  {
7097  fd=rootNav->fileDef();
7099  isGlobal=TRUE;
7100  }
7101 
7102  if (!name.isEmpty())
7103  {
7104  // new enum type
7105  md = new MemberDef(
7106  root->fileName,root->startLine,root->startColumn,
7107  0,name,0,0,
7108  root->protection,Normal,FALSE,
7109  isMemberOf ? Foreign : isRelated ? Related : Member,
7111  0,0);
7112  md->setTagInfo(rootNav->tagInfo());
7113  md->setLanguage(root->lang);
7114  md->setId(root->id);
7115  if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7116  md->setBodySegment(root->bodyLine,root->endBodyLine);
7117  md->setBodyDef(rootNav->fileDef());
7118  md->setMemberSpecifiers(root->spec);
7119  md->setEnumBaseType(root->args);
7120  //printf("Enum %s definition at line %d of %s: protection=%d scope=%s\n",
7121  // root->name.data(),root->bodyLine,root->fileName.data(),root->protection,cd?cd->name().data():"<none>");
7122  md->addSectionsToDefinition(root->anchors);
7123  md->setMemberGroupId(root->mGrpId);
7124  md->enableCallGraph(root->callGraph);
7125  md->enableCallerGraph(root->callerGraph);
7126  //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
7127  md->setRefItems(root->sli);
7128  //printf("found enum %s nd=%p\n",md->name().data(),nd);
7129  bool defSet=FALSE;
7130 
7131  QCString baseType = root->args;
7132  if (!baseType.isEmpty())
7133  {
7134  baseType.prepend(" : ");
7135  }
7136 
7137  if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7138  {
7139  if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7140  {
7141  md->setDefinition(name+baseType);
7142  }
7143  else
7144  {
7145  md->setDefinition(nd->name()+"::"+name+baseType);
7146  }
7147  //printf("definition=%s\n",md->definition());
7148  defSet=TRUE;
7149  md->setNamespace(nd);
7150  nd->insertMember(md);
7151  }
7152 
7153  // even if we have already added the enum to a namespace, we still
7154  // also want to add it to other appropriate places such as file
7155  // or class.
7156  if (isGlobal)
7157  {
7158  if (!defSet) md->setDefinition(name+baseType);
7159  if (fd==0 && rootNav->parent())
7160  {
7161  fd=rootNav->parent()->fileDef();
7162  }
7163  if (fd)
7164  {
7165  md->setFileDef(fd);
7166  fd->insertMember(md);
7167  }
7168  }
7169  else if (cd)
7170  {
7171  if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7172  {
7173  md->setDefinition(name+baseType);
7174  }
7175  else
7176  {
7177  md->setDefinition(cd->name()+"::"+name+baseType);
7178  }
7179  cd->insertMember(md);
7180  cd->insertUsedFile(fd);
7181  }
7182  md->setDocumentation(root->doc,root->docFile,root->docLine);
7183  md->setDocsForDefinition(!root->proto);
7184  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7185  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7186 
7187  //printf("Adding member=%s\n",md->name().data());
7188  MemberName *mn;
7189  if ((mn=(*mnsd)[name]))
7190  {
7191  // this is used if the same enum is in multiple namespaces/classes
7192  mn->append(md);
7193  }
7194  else // new enum name
7195  {
7196  mn = new MemberName(name);
7197  mn->append(md);
7198  mnsd->append(name,mn);
7199  //printf("add %s to new memberName. Now %d members\n",
7200  // name.data(),mn->count());
7201  }
7202  addMemberToGroups(root,md);
7203  }
7204  rootNav->releaseEntry();
7205  }
7206  else
7207  {
7208  RECURSE_ENTRYTREE(findEnums,rootNav);
7209  }
7210 }
7211 
7212 //----------------------------------------------------------------------
7213 
7214 static void addEnumValuesToEnums(EntryNav *rootNav)
7215 {
7216  if (rootNav->section()==Entry::ENUM_SEC)
7217  // non anonymous enumeration
7218  {
7219  rootNav->loadEntry(g_storage);
7220  Entry *root = rootNav->entry();
7221 
7222  ClassDef *cd=0;
7223  FileDef *fd=0;
7224  NamespaceDef *nd=0;
7225  MemberNameSDict *mnsd=0;
7226  bool isGlobal;
7227  bool isRelated=FALSE;
7228  //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7229  int i;
7230 
7231  QCString name;
7232  QCString scope;
7233 
7234  if ((i=root->name.findRev("::"))!=-1) // scope is specified
7235  {
7236  scope=root->name.left(i); // extract scope
7237  name=root->name.right(root->name.length()-i-2); // extract name
7238  if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7239  }
7240  else // no scope, check the scope in which the docs where found
7241  {
7242  if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7243  && !rootNav->parent()->name().isEmpty()
7244  ) // found enum docs inside a compound
7245  {
7246  scope=rootNav->parent()->name();
7247  if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7248  }
7249  name=root->name;
7250  }
7251 
7252  if (!root->relates.isEmpty())
7253  { // related member, prefix user specified scope
7254  isRelated=TRUE;
7255  if (getClass(root->relates)==0 && !scope.isEmpty())
7256  scope=mergeScopes(scope,root->relates);
7257  else
7258  scope=root->relates.copy();
7259  if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7260  }
7261 
7262  if (cd && !name.isEmpty()) // found a enum inside a compound
7263  {
7264  //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
7265  fd=0;
7267  isGlobal=FALSE;
7268  }
7269  else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7270  {
7271  //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
7273  isGlobal=TRUE;
7274  }
7275  else // found a global enum
7276  {
7277  fd=rootNav->fileDef();
7278  //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
7280  isGlobal=TRUE;
7281  }
7282 
7283  if (!name.isEmpty())
7284  {
7285  //printf("** name=%s\n",name.data());
7286  MemberName *mn = mnsd->find(name); // for all members with this name
7287  if (mn)
7288  {
7289  MemberNameIterator mni(*mn);
7290  MemberDef *md;
7291  for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list
7292  {
7293  if (md->isEnumerate() && rootNav->children())
7294  {
7295  //printf(" enum with %d children\n",rootNav->children()->count());
7296  EntryNavListIterator eli(*rootNav->children()); // for each enum value
7297  EntryNav *e;
7298  for (;(e=eli.current());++eli)
7299  {
7300  SrcLangExt sle;
7301  if (
7302  (sle=rootNav->lang())==SrcLangExt_CSharp ||
7303  sle==SrcLangExt_Java ||
7304  sle==SrcLangExt_XML ||
7305  (root->spec&Entry::Strong)
7306  )
7307  {
7308  // Unlike classic C/C++ enums, for C++11, C# & Java enum
7309  // values are only visible inside the enum scope, so we must create
7310  // them here and only add them to the enum
7311  e->loadEntry(g_storage);
7312  Entry *root = e->entry();
7313  //printf("md->qualifiedName()=%s rootNav->name()=%s tagInfo=%p name=%s\n",
7314  // md->qualifiedName().data(),rootNav->name().data(),rootNav->tagInfo(),root->name.data());
7315  QCString qualifiedName = substitute(rootNav->name(),"::",".");
7316  if (!scope.isEmpty() && rootNav->tagInfo())
7317  {
7318  qualifiedName=substitute(scope,"::",".")+"."+qualifiedName;
7319  }
7320  if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7321  qualifiedName // enum value scope matches that of the enum
7322  )
7323  {
7324  QCString fileName = root->fileName;
7325  if (fileName.isEmpty() && rootNav->tagInfo())
7326  {
7327  fileName = rootNav->tagInfo()->tagName;
7328  }
7329  MemberDef *fmd=new MemberDef(
7330  fileName,root->startLine,root->startColumn,
7331  root->type,root->name,root->args,0,
7332  root->protection, Normal,root->stat,Member,
7333  MemberType_EnumValue,0,0);
7334  if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
7335  else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
7336  else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
7337  fmd->setOuterScope(md->getOuterScope());
7338  fmd->setTagInfo(e->tagInfo());
7339  fmd->setLanguage(root->lang);
7340  fmd->setId(root->id);
7341  fmd->setDocumentation(root->doc,root->docFile,root->docLine);
7342  fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7343  fmd->addSectionsToDefinition(root->anchors);
7344  fmd->setInitializer(root->initializer);
7345  fmd->setMaxInitLines(root->initLines);
7346  fmd->setMemberGroupId(root->mGrpId);
7348  fmd->setRefItems(root->sli);
7349  fmd->setAnchor();
7350  md->insertEnumField(fmd);
7351  fmd->setEnumScope(md,TRUE);
7352  MemberName *mn=mnsd->find(root->name);
7353  if (mn)
7354  {
7355  mn->append(fmd);
7356  }
7357  else
7358  {
7359  mn = new MemberName(root->name);
7360  mn->append(fmd);
7361  mnsd->append(root->name,mn);
7362  }
7363  }
7364  e->releaseEntry();
7365  }
7366  else
7367  {
7368  //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
7369  MemberName *fmn=0;
7370  MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
7371  if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
7372  // get list of members with the same name as the field
7373  {
7374  MemberNameIterator fmni(*fmn);
7375  MemberDef *fmd;
7376  for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
7377  {
7378  if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7379  {
7380  //printf("found enum value with same name %s in scope %s\n",
7381  // fmd->name().data(),fmd->getOuterScope()->name().data());
7382  if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7383  {
7384  NamespaceDef *fnd=fmd->getNamespaceDef();
7385  if (fnd==nd) // enum value is inside a namespace
7386  {
7387  md->insertEnumField(fmd);
7388  fmd->setEnumScope(md);
7389  }
7390  }
7391  else if (isGlobal)
7392  {
7393  FileDef *ffd=fmd->getFileDef();
7394  if (ffd==fd) // enum value has file scope
7395  {
7396  md->insertEnumField(fmd);
7397  fmd->setEnumScope(md);
7398  }
7399  }
7400  else if (isRelated && cd) // reparent enum value to
7401  // match the enum's scope
7402  {
7403  md->insertEnumField(fmd); // add field def to list
7404  fmd->setEnumScope(md); // cross ref with enum name
7405  fmd->setEnumClassScope(cd); // cross ref with enum name
7406  fmd->setOuterScope(cd);
7407  fmd->makeRelated();
7408  cd->insertMember(fmd);
7409  }
7410  else
7411  {
7412  ClassDef *fcd=fmd->getClassDef();
7413  if (fcd==cd) // enum value is inside a class
7414  {
7415  //printf("Inserting enum field %s in enum scope %s\n",
7416  // fmd->name().data(),md->name().data());
7417  md->insertEnumField(fmd); // add field def to list
7418  fmd->setEnumScope(md); // cross ref with enum name
7419  }
7420  }
7421  }
7422  }
7423  }
7424  }
7425  }
7426  }
7427  }
7428  }
7429  }
7430 
7431  rootNav->releaseEntry();
7432  }
7433  else
7434  {
7436  }
7437 }
7438 
7439 
7440 //----------------------------------------------------------------------
7441 // find the documentation blocks for the enumerations
7442 
7443 static void findEnumDocumentation(EntryNav *rootNav)
7444 {
7445  if (rootNav->section()==Entry::ENUMDOC_SEC
7446  && !rootNav->name().isEmpty()
7447  && rootNav->name().at(0)!='@' // skip anonymous enums
7448  )
7449  {
7450  rootNav->loadEntry(g_storage);
7451  Entry *root = rootNav->entry();
7452 
7453  //printf("Found docs for enum with name `%s' in context %s\n",
7454  // root->name.data(),root->parent->name.data());
7455  int i;
7456  QCString name;
7457  QCString scope;
7458  if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7459  {
7460  name=root->name.right(root->name.length()-i-2); // extract name
7461  scope=root->name.left(i); // extract scope
7462  //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7463  }
7464  else // just the name
7465  {
7466  name=root->name;
7467  }
7468  if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7469  && !rootNav->parent()->name().isEmpty()
7470  ) // found enum docs inside a compound
7471  {
7472  if (!scope.isEmpty()) scope.prepend("::");
7473  scope.prepend(rootNav->parent()->name());
7474  }
7475  ClassDef *cd=getClass(scope);
7476 
7477  if (!name.isEmpty())
7478  {
7479  bool found=FALSE;
7480  if (cd)
7481  {
7482  //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7483  QCString className=cd->name().copy();
7484  MemberName *mn=Doxygen::memberNameSDict->find(name);
7485  if (mn)
7486  {
7487  MemberNameIterator mni(*mn);
7488  MemberDef *md;
7489  for (mni.toFirst();(md=mni.current()) && !found;++mni)
7490  {
7491  ClassDef *cd=md->getClassDef();
7492  if (cd && cd->name()==className && md->isEnumerate())
7493  {
7494  // documentation outside a compound overrides the documentation inside it
7495 #if 0
7496  if (!md->documentation() || rootNav->parent()->name().isEmpty())
7497 #endif
7498  {
7499  md->setDocumentation(root->doc,root->docFile,root->docLine);
7500  md->setDocsForDefinition(!root->proto);
7501  }
7502 
7503  // brief descriptions inside a compound override the documentation
7504  // outside it
7505 #if 0
7506  if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7507 #endif
7508  {
7509  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7510  }
7511 
7512  if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7513  {
7514  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7515  }
7516 
7517  if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7518  {
7519  md->setMemberGroupId(root->mGrpId);
7520  }
7521 
7522  md->addSectionsToDefinition(root->anchors);
7523  md->setRefItems(root->sli);
7524 
7525  GroupDef *gd=md->getGroupDef();
7526  if (gd==0 &&root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7527  {
7528  addMemberToGroups(root,md);
7529  }
7530 
7531  found=TRUE;
7532  }
7533  }
7534  }
7535  else
7536  {
7537  //printf("MemberName %s not found!\n",name.data());
7538  }
7539  }
7540  else // enum outside class
7541  {
7542  //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7543  MemberName *mn=Doxygen::functionNameSDict->find(name);
7544  if (mn)
7545  {
7546  MemberNameIterator mni(*mn);
7547  MemberDef *md;
7548  for (mni.toFirst();(md=mni.current()) && !found;++mni)
7549  {
7550  if (md->isEnumerate())
7551  {
7552  md->setDocumentation(root->doc,root->docFile,root->docLine);
7553  md->setDocsForDefinition(!root->proto);
7554  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7555  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7556  md->addSectionsToDefinition(root->anchors);
7557  md->setMemberGroupId(root->mGrpId);
7558 
7559  GroupDef *gd=md->getGroupDef();
7560  if (gd==0 && root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7561  {
7562  addMemberToGroups(root,md);
7563  }
7564 
7565  found=TRUE;
7566  }
7567  }
7568  }
7569  }
7570  if (!found)
7571  {
7572  warn(root->fileName,root->startLine,
7573  "Documentation for undefined enum `%s' found.",
7574  name.data()
7575  );
7576  }
7577  }
7578 
7579  rootNav->releaseEntry();
7580  }
7582 }
7583 
7584 // search for each enum (member or function) in mnl if it has documented
7585 // enum values.
7586 static void findDEV(const MemberNameSDict &mnsd)
7587 {
7588  MemberName *mn;
7589  MemberNameSDict::Iterator mnli(mnsd);
7590  // for each member name
7591  for (mnli.toFirst();(mn=mnli.current());++mnli)
7592  {
7593  MemberDef *md;
7594  MemberNameIterator mni(*mn);
7595  // for each member definition
7596  for (mni.toFirst();(md=mni.current());++mni)
7597  {
7598  if (md->isEnumerate()) // member is an enum
7599  {
7600  MemberList *fmdl = md->enumFieldList();
7601  int documentedEnumValues=0;
7602  if (fmdl) // enum has values
7603  {
7604  MemberListIterator fmni(*fmdl);
7605  MemberDef *fmd;
7606  // for each enum value
7607  for (fmni.toFirst();(fmd=fmni.current());++fmni)
7608  {
7609  if (fmd->isLinkableInProject()) documentedEnumValues++;
7610  }
7611  }
7612  // at least one enum value is documented
7613  if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7614  }
7615  }
7616  }
7617 }
7618 
7619 // search for each enum (member or function) if it has documented enum
7620 // values.
7622 {
7623  findDEV(*Doxygen::memberNameSDict);
7624  findDEV(*Doxygen::functionNameSDict);
7625 }
7626 
7627 //----------------------------------------------------------------------
7628 
7629 static void addMembersToIndex()
7630 {
7631  MemberName *mn;
7632  MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7633  // for each member name
7634  for (mnli.toFirst();(mn=mnli.current());++mnli)
7635  {
7636  MemberDef *md;
7637  MemberNameIterator mni(*mn);
7638  // for each member definition
7639  for (mni.toFirst();(md=mni.current());++mni)
7640  {
7642  }
7643  }
7644  MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7645  // for each member name
7646  for (fnli.toFirst();(mn=fnli.current());++fnli)
7647  {
7648  MemberDef *md;
7649  MemberNameIterator mni(*mn);
7650  // for each member definition
7651  for (mni.toFirst();(md=mni.current());++mni)
7652  {
7653  if (md->getNamespaceDef())
7654  {
7656  }
7657  else
7658  {
7660  }
7661  }
7662  }
7663 }
7664 
7665 //----------------------------------------------------------------------
7666 // computes the relation between all members. For each member `m'
7667 // the members that override the implementation of `m' are searched and
7668 // the member that `m' overrides is searched.
7669 
7671 {
7672  MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7673  MemberName *mn;
7674  for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7675  {
7676  MemberNameIterator mdi(*mn);
7677  MemberNameIterator bmdi(*mn);
7678  MemberDef *md;
7679  MemberDef *bmd;
7680  for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7681  {
7682  for ( bmdi.toFirst() ; (bmd=bmdi.current()); ++bmdi ) // for each other member with the same name
7683  {
7684  ClassDef *mcd = md->getClassDef();
7685  if (mcd && mcd->baseClasses())
7686  {
7687  ClassDef *bmcd = bmd->getClassDef();
7688  //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7689  // mcd->name().data(),md->name().data(),md,
7690  // bmcd->name().data(),bmd->name().data(),bmd
7691  // );
7692  if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
7693  (bmd->virtualness()!=Normal ||
7694  bmcd->compoundType()==ClassDef::Interface ||
7696  ) &&
7697  md->isFunction() &&
7698  mcd->isLinkable() &&
7699  bmcd->isLinkable() &&
7700  mcd->isBaseClass(bmcd,TRUE))
7701  {
7702  //printf(" derived scope\n");
7703  ArgumentList *bmdAl = bmd->argumentList();
7704  ArgumentList *mdAl = md->argumentList();
7705  //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7706  // argListToString(bmdAl.pointer()).data(),
7707  // argListToString(mdAl.pointer()).data()
7708  // );
7709  if (
7710  matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl,
7711  md->getOuterScope(), md->getFileDef(), mdAl,
7712  TRUE
7713  )
7714  )
7715  {
7716  MemberDef *rmd;
7717  if ((rmd=md->reimplements())==0 ||
7718  minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7719  )
7720  {
7721  //printf("setting (new) reimplements member\n");
7722  md->setReimplements(bmd);
7723  }
7724  //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7725  bmd->insertReimplementedBy(md);
7726  }
7727  }
7728  }
7729  }
7730  }
7731  }
7732 }
7733 
7734 
7735 //----------------------------------------------------------------------------
7736 //static void computeClassImplUsageRelations()
7737 //{
7738 // ClassDef *cd;
7739 // ClassSDict::Iterator cli(*Doxygen::classSDict);
7740 // for (;(cd=cli.current());++cli)
7741 // {
7742 // cd->determineImplUsageRelation();
7743 // }
7744 //}
7745 
7746 //----------------------------------------------------------------------------
7747 
7749 {
7750  ClassSDict::Iterator cli(*Doxygen::classSDict);
7751  ClassDef *cd;
7752  // for each class
7753  for (cli.toFirst();(cd=cli.current());++cli)
7754  {
7755  // that is a template
7756  QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7757  if (templInstances)
7758  {
7759  QDictIterator<ClassDef> qdi(*templInstances);
7760  ClassDef *tcd=0;
7761  // for each instance of the template
7762  for (qdi.toFirst();(tcd=qdi.current());++qdi)
7763  {
7764  tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7765  }
7766  }
7767  }
7768 }
7769 
7770 //----------------------------------------------------------------------------
7771 
7772 static void mergeCategories()
7773 {
7774  ClassDef *cd;
7775  ClassSDict::Iterator cli(*Doxygen::classSDict);
7776  // merge members of categories into the class they extend
7777  for (cli.toFirst();(cd=cli.current());++cli)
7778  {
7779  int i=cd->name().find('(');
7780  if (i!=-1) // it is an Objective-C category
7781  {
7782  QCString baseName=cd->name().left(i);
7783  ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7784  if (baseClass)
7785  {
7786  //printf("*** merging members of category %s into %s\n",
7787  // cd->name().data(),baseClass->name().data());
7788  baseClass->mergeCategory(cd);
7789  }
7790  }
7791  }
7792 }
7793 
7794 // builds the list of all members for each class
7795 
7797 {
7798  ClassDef *cd;
7799  ClassSDict::Iterator cli(*Doxygen::classSDict);
7800  // merge the member list of base classes into the inherited classes.
7801  for (cli.toFirst();(cd=cli.current());++cli)
7802  {
7803  if (// !cd->isReference() && // not an external class
7804  cd->subClasses()==0 && // is a root of the hierarchy
7805  cd->baseClasses()) // and has at least one base class
7806  {
7807  //printf("*** merging members for %s\n",cd->name().data());
7808  cd->mergeMembers();
7809  }
7810  }
7811  // now sort the member list of all classes.
7812  for (cli.toFirst();(cd=cli.current());++cli)
7813  {
7814  if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7815  }
7816 }
7817 
7818 //----------------------------------------------------------------------------
7819 
7820 static void generateFileSources()
7821 {
7822  if (Doxygen::inputNameList->count()>0)
7823  {
7824 #if USE_LIBCLANG
7825  static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
7826  if (clangAssistedParsing)
7827  {
7828  QDict<void> g_processedFiles(10007);
7829 
7830  // create a dictionary with files to process
7831  QDict<void> g_filesToProcess(10007);
7832  FileNameListIterator fnli(*Doxygen::inputNameList);
7833  FileName *fn;
7834  for (fnli.toFirst();(fn=fnli.current());++fnli)
7835  {
7836  FileNameIterator fni(*fn);
7837  FileDef *fd;
7838  for (;(fd=fni.current());++fni)
7839  {
7840  g_filesToProcess.insert(fd->absFilePath(),(void*)0x8);
7841  }
7842  }
7843  // process source files (and their include dependencies)
7844  for (fnli.toFirst();(fn=fnli.current());++fnli)
7845  {
7846  FileNameIterator fni(*fn);
7847  FileDef *fd;
7848  for (;(fd=fni.current());++fni)
7849  {
7850  if (fd->isSource() && !fd->isReference())
7851  {
7852  QStrList filesInSameTu;
7853  fd->getAllIncludeFilesRecursively(filesInSameTu);
7854  fd->startParsing();
7855  if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7856  {
7857  msg("Generating code for file %s...\n",fd->docName().data());
7858  fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7859 
7860  }
7861  else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7862  // we needed to parse the sources even if we do not show them
7863  {
7864  msg("Parsing code for file %s...\n",fd->docName().data());
7865  fd->parseSource(FALSE,filesInSameTu);
7866  }
7867 
7868  char *incFile = filesInSameTu.first();
7869  while (incFile && g_filesToProcess.find(incFile))
7870  {
7871  if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile))
7872  {
7873  QStrList moreFiles;
7874  bool ambig;
7875  FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
7876  if (ifd && !ifd->isReference())
7877  {
7878  if (ifd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7879  {
7880  msg(" Generating code for file %s...\n",ifd->docName().data());
7881  ifd->writeSource(*g_outputList,TRUE,moreFiles);
7882 
7883  }
7884  else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
7885  // we needed to parse the sources even if we do not show them
7886  {
7887  msg(" Parsing code for file %s...\n",ifd->docName().data());
7888  ifd->parseSource(TRUE,moreFiles);
7889  }
7890  g_processedFiles.insert(incFile,(void*)0x8);
7891  }
7892  }
7893  incFile = filesInSameTu.next();
7894  }
7895  fd->finishParsing();
7896  g_processedFiles.insert(fd->absFilePath(),(void*)0x8);
7897  }
7898  }
7899  }
7900  // process remaining files
7901  for (fnli.toFirst();(fn=fnli.current());++fnli)
7902  {
7903  FileNameIterator fni(*fn);
7904  FileDef *fd;
7905  for (;(fd=fni.current());++fni)
7906  {
7907  if (!g_processedFiles.find(fd->absFilePath())) // not yet processed
7908  {
7909  QStrList filesInSameTu;
7910  fd->startParsing();
7911  if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7912  {
7913  msg("Generating code for file %s...\n",fd->docName().data());
7914  fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7915 
7916  }
7917  else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7918  // we needed to parse the sources even if we do not show them
7919  {
7920  msg("Parsing code for file %s...\n",fd->docName().data());
7921  fd->parseSource(FALSE,filesInSameTu);
7922  }
7923  fd->finishParsing();
7924  }
7925  }
7926  }
7927  }
7928  else
7929 #endif
7930  {
7931  FileNameListIterator fnli(*Doxygen::inputNameList);
7932  FileName *fn;
7933  for (;(fn=fnli.current());++fnli)
7934  {
7935  FileNameIterator fni(*fn);
7936  FileDef *fd;
7937  for (;(fd=fni.current());++fni)
7938  {
7939  QStrList filesInSameTu;
7940  fd->startParsing();
7941  if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7942  {
7943  msg("Generating code for file %s...\n",fd->docName().data());
7944  fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7945 
7946  }
7947  else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7948  // we needed to parse the sources even if we do not show them
7949  {
7950  msg("Parsing code for file %s...\n",fd->docName().data());
7951  fd->parseSource(FALSE,filesInSameTu);
7952  }
7953  fd->finishParsing();
7954  }
7955  }
7956  }
7957  }
7958 }
7959 
7960 //----------------------------------------------------------------------------
7961 
7962 static void generateFileDocs()
7963 {
7964  if (documentedHtmlFiles==0) return;
7965 
7966  if (Doxygen::inputNameList->count()>0)
7967  {
7968  FileNameListIterator fnli(*Doxygen::inputNameList);
7969  FileName *fn;
7970  for (fnli.toFirst();(fn=fnli.current());++fnli)
7971  {
7972  FileNameIterator fni(*fn);
7973  FileDef *fd;
7974  for (fni.toFirst();(fd=fni.current());++fni)
7975  {
7976  bool doc = fd->isLinkableInProject();
7977  if (doc)
7978  {
7979  msg("Generating docs for file %s...\n",fd->docName().data());
7980  fd->writeDocumentation(*g_outputList);
7981  }
7982  }
7983  }
7984  }
7985 }
7986 
7987 //----------------------------------------------------------------------------
7988 
7989 static void addSourceReferences()
7990 {
7991  // add source references for class definitions
7992  ClassSDict::Iterator cli(*Doxygen::classSDict);
7993  ClassDef *cd=0;
7994  for (cli.toFirst();(cd=cli.current());++cli)
7995  {
7996  FileDef *fd=cd->getBodyDef();
7997  if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
7998  {
7999  fd->addSourceRef(cd->getStartBodyLine(),cd,0);
8000  }
8001  }
8002  // add source references for namespace definitions
8003  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8004  NamespaceDef *nd=0;
8005  for (nli.toFirst();(nd=nli.current());++nli)
8006  {
8007  FileDef *fd=nd->getBodyDef();
8008  if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
8009  {
8010  fd->addSourceRef(nd->getStartBodyLine(),nd,0);
8011  }
8012  }
8013 
8014  // add source references for member names
8015  MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8016  MemberName *mn=0;
8017  for (mnli.toFirst();(mn=mnli.current());++mnli)
8018  {
8019  MemberNameIterator mni(*mn);
8020  MemberDef *md=0;
8021  for (mni.toFirst();(md=mni.current());++mni)
8022  {
8023  //printf("class member %s: def=%s body=%d link?=%d\n",
8024  // md->name().data(),
8025  // md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
8026  // md->getStartBodyLine(),md->isLinkableInProject());
8027  FileDef *fd=md->getBodyDef();
8028  if (fd &&
8029  md->getStartBodyLine()!=-1 &&
8030  md->isLinkableInProject() &&
8032  )
8033  {
8034  //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8035  // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8036  fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8037  }
8038  }
8039  }
8040  MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8041  for (fnli.toFirst();(mn=fnli.current());++fnli)
8042  {
8043  MemberNameIterator mni(*mn);
8044  MemberDef *md=0;
8045  for (mni.toFirst();(md=mni.current());++mni)
8046  {
8047  FileDef *fd=md->getBodyDef();
8048  //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
8049  // md->name().data(),
8050  // md->getStartBodyLine(),md->getEndBodyLine(),fd,
8051  // md->isLinkableInProject(),
8052  // Doxygen::parseSourcesNeeded);
8053  if (fd &&
8054  md->getStartBodyLine()!=-1 &&
8055  md->isLinkableInProject() &&
8057  )
8058  {
8059  //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8060  // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8061  fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8062  }
8063  }
8064  }
8065 }
8066 
8067 //----------------------------------------------------------------------------
8068 
8069 static void sortMemberLists()
8070 {
8071  // sort class member lists
8072  ClassSDict::Iterator cli(*Doxygen::classSDict);
8073  ClassDef *cd=0;
8074  for (cli.toFirst();(cd=cli.current());++cli)
8075  {
8076  cd->sortMemberLists();
8077  }
8078 
8079  // sort namespace member lists
8080  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8081  NamespaceDef *nd=0;
8082  for (nli.toFirst();(nd=nli.current());++nli)
8083  {
8084  nd->sortMemberLists();
8085  }
8086 
8087  // sort file member lists
8088  FileNameListIterator fnli(*Doxygen::inputNameList);
8089  FileName *fn;
8090  for (;(fn=fnli.current());++fnli)
8091  {
8092  FileNameIterator fni(*fn);
8093  FileDef *fd;
8094  for (;(fd=fni.current());++fni)
8095  {
8096  fd->sortMemberLists();
8097  }
8098  }
8099 
8100  // sort group member lists
8101  GroupSDict::Iterator gli(*Doxygen::groupSDict);
8102  GroupDef *gd;
8103  for (gli.toFirst();(gd=gli.current());++gli)
8104  {
8105  gd->sortMemberLists();
8106  }
8107 }
8108 
8109 //----------------------------------------------------------------------------
8110 // generate the documentation of all classes
8111 
8112 static void generateClassList(ClassSDict &classSDict)
8113 {
8114  ClassSDict::Iterator cli(classSDict);
8115  for ( ; cli.current() ; ++cli )
8116  {
8117  ClassDef *cd=cli.current();
8118 
8119  //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
8120  if (cd &&
8121  (cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8122  cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8123  ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8124  )
8125  {
8126  // skip external references, anonymous compounds and
8127  // template instances
8128  if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8129  {
8130  msg("Generating docs for compound %s...\n",cd->name().data());
8131 
8132  cd->writeDocumentation(*g_outputList);
8133  cd->writeMemberList(*g_outputList);
8134  }
8135  // even for undocumented classes, the inner classes can be documented.
8136  cd->writeDocumentationForInnerClasses(*g_outputList);
8137  }
8138  }
8139 }
8140 
8141 static void generateClassDocs()
8142 {
8143  generateClassList(*Doxygen::classSDict);
8144  generateClassList(*Doxygen::hiddenClasses);
8145 }
8146 
8147 //----------------------------------------------------------------------------
8148 
8150 {
8151  MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8152  MemberName *mn;
8153  //int count=0;
8154  for (;(mn=mnli.current());++mnli)
8155  {
8156  MemberNameIterator mni(*mn);
8157  MemberDef *md;
8158  for (;(md=mni.current());++mni)
8159  {
8160  //printf("%04d Member `%s'\n",count++,md->name().data());
8161  if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
8162  { // no documentation yet
8163  MemberDef *bmd = md->reimplements();
8164  while (bmd && bmd->documentation().isEmpty() &&
8165  bmd->briefDescription().isEmpty()
8166  )
8167  { // search up the inheritance tree for a documentation member
8168  //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
8169  bmd = bmd->reimplements();
8170  }
8171  if (bmd) // copy the documentation from the reimplemented member
8172  {
8173  md->setInheritsDocsFrom(bmd);
8174  md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8176  md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8177  md->copyArgumentNames(bmd);
8179  }
8180  }
8181  }
8182  }
8183 }
8184 
8185 //----------------------------------------------------------------------------
8186 
8188 {
8189  // for each file
8190  FileNameListIterator fnli(*Doxygen::inputNameList);
8191  FileName *fn;
8192  for (fnli.toFirst();(fn=fnli.current());++fnli)
8193  {
8194  FileNameIterator fni(*fn);
8195  FileDef *fd;
8196  for (fni.toFirst();(fd=fni.current());++fni)
8197  {
8198  fd->visited=FALSE;
8199  }
8200  }
8201  for (fnli.toFirst();(fn=fnli.current());++fnli)
8202  {
8203  FileNameIterator fni(*fn);
8204  FileDef *fd;
8205  for (fni.toFirst();(fd=fni.current());++fni)
8206  {
8207  fd->combineUsingRelations();
8208  }
8209  }
8210 
8211  // for each namespace
8212  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8213  NamespaceDef *nd;
8214  for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8215  {
8216  nd->visited=FALSE;
8217  }
8218  for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8219  {
8220  nd->combineUsingRelations();
8221  }
8222 }
8223 
8224 //----------------------------------------------------------------------------
8225 
8227 {
8228  // for each class
8229  ClassSDict::Iterator cli(*Doxygen::classSDict);
8230  ClassDef *cd;
8231  for ( ; (cd=cli.current()) ; ++cli )
8232  {
8234  }
8235  // for each file
8236  FileNameListIterator fnli(*Doxygen::inputNameList);
8237  FileName *fn;
8238  for (fnli.toFirst();(fn=fnli.current());++fnli)
8239  {
8240  FileNameIterator fni(*fn);
8241  FileDef *fd;
8242  for (fni.toFirst();(fd=fni.current());++fni)
8243  {
8245  }
8246  }
8247  // for each namespace
8248  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8249  NamespaceDef *nd;
8250  for ( ; (nd=nli.current()) ; ++nli )
8251  {
8253  }
8254  // for each group
8255  GroupSDict::Iterator gli(*Doxygen::groupSDict);
8256  GroupDef *gd;
8257  for (gli.toFirst();(gd=gli.current());++gli)
8258  {
8260  }
8261 }
8262 
8263 //----------------------------------------------------------------------------
8264 
8266 {
8267  // for each class
8268  ClassSDict::Iterator cli(*Doxygen::classSDict);
8269  ClassDef *cd;
8270  for ( ; (cd=cli.current()) ; ++cli )
8271  {
8273  }
8274  // for each file
8275  FileNameListIterator fnli(*Doxygen::inputNameList);
8276  FileName *fn;
8277  for (fnli.toFirst();(fn=fnli.current());++fnli)
8278  {
8279  FileNameIterator fni(*fn);
8280  FileDef *fd;
8281  for (fni.toFirst();(fd=fni.current());++fni)
8282  {
8284  }
8285  }
8286  // for each namespace
8287  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8288  NamespaceDef *nd;
8289  for ( ; (nd=nli.current()) ; ++nli )
8290  {
8292  }
8293  // for each group
8294  GroupSDict::Iterator gli(*Doxygen::groupSDict);
8295  GroupDef *gd;
8296  for (gli.toFirst();(gd=gli.current());++gli)
8297  {
8299  }
8300 }
8301 
8302 //----------------------------------------------------------------------------
8303 
8305 {
8306  // for each class
8307  ClassSDict::Iterator cli(*Doxygen::classSDict);
8308  ClassDef *cd;
8309  for ( ; (cd=cli.current()) ; ++cli )
8310  {
8312  }
8313  // for each file
8314  FileNameListIterator fnli(*Doxygen::inputNameList);
8315  FileName *fn;
8316  for (fnli.toFirst();(fn=fnli.current());++fnli)
8317  {
8318  FileNameIterator fni(*fn);
8319  FileDef *fd;
8320  for (fni.toFirst();(fd=fni.current());++fni)
8321  {
8323  }
8324  }
8325  // for each namespace
8326  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8327  NamespaceDef *nd;
8328  for ( ; (nd=nli.current()) ; ++nli )
8329  {
8331  }
8332  // for each group
8333  GroupSDict::Iterator gli(*Doxygen::groupSDict);
8334  GroupDef *gd;
8335  for (gli.toFirst();(gd=gli.current());++gli)
8336  {
8338  }
8339  // for each page
8340  PageSDict::Iterator pdi(*Doxygen::pageSDict);
8341  PageDef *pd=0;
8342  for (pdi.toFirst();(pd=pdi.current());++pdi)
8343  {
8345  }
8346  if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8347 }
8348 
8350 {
8351  // remove all references to classes from the cache
8352  // as there can be new template instances in the inheritance path
8353  // to this class. Optimization: only remove those classes that
8354  // have inheritance instances as direct or indirect sub classes.
8355  QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8356  LookupInfo *li=0;
8357  for (ci.toFirst();(li=ci.current());++ci)
8358  {
8359  if (li->classDef)
8360  {
8361  Doxygen::lookupCache->remove(ci.currentKey());
8362  }
8363  }
8364  // remove all cached typedef resolutions whose target is a
8365  // template class as this may now be a template instance
8366  MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8367  MemberName *fn;
8368  for (;(fn=fnli.current());++fnli) // for each global function name
8369  {
8370  MemberNameIterator fni(*fn);
8371  MemberDef *fmd;
8372  for (;(fmd=fni.current());++fni) // for each function with that name
8373  {
8374  if (fmd->isTypedefValCached())
8375  {
8376  ClassDef *cd = fmd->getCachedTypedefVal();
8377  if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8378  }
8379  }
8380  }
8381  MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8382  for (;(fn=mnli.current());++mnli) // for each class method name
8383  {
8384  MemberNameIterator mni(*fn);
8385  MemberDef *fmd;
8386  for (;(fmd=mni.current());++mni) // for each function with that name
8387  {
8388  if (fmd->isTypedefValCached())
8389  {
8390  ClassDef *cd = fmd->getCachedTypedefVal();
8391  if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8392  }
8393  }
8394  }
8395 }
8396 
8397 //----------------------------------------------------------------------------
8398 
8400 {
8401  // Remove all unresolved references to classes from the cache.
8402  // This is needed before resolving the inheritance relations, since
8403  // it would otherwise not find the inheritance relation
8404  // for C in the example below, as B::I was already found to be unresolvable
8405  // (which is correct if you igore the inheritance relation between A and B).
8406  //
8407  // class A { class I {} };
8408  // class B : public A {};
8409  // class C : public B::I {};
8410  //
8411  QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8412  LookupInfo *li=0;
8413  for (ci.toFirst();(li=ci.current());++ci)
8414  {
8415  if (li->classDef==0 && li->typeDef==0)
8416  {
8417  Doxygen::lookupCache->remove(ci.currentKey());
8418  }
8419  }
8420 
8421  MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8422  MemberName *fn;
8423  for (;(fn=fnli.current());++fnli) // for each global function name
8424  {
8425  MemberNameIterator fni(*fn);
8426  MemberDef *fmd;
8427  for (;(fmd=fni.current());++fni) // for each function with that name
8428  {
8430  }
8431  }
8432  MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8433  for (;(fn=mnli.current());++mnli) // for each class method name
8434  {
8435  MemberNameIterator mni(*fn);
8436  MemberDef *fmd;
8437  for (;(fmd=mni.current());++mni) // for each function with that name
8438  {
8440  }
8441  }
8442 
8443 }
8444 
8445 //----------------------------------------------------------------------------
8446 
8447 static void findDefineDocumentation(EntryNav *rootNav)
8448 {
8449  if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
8450  rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
8451  )
8452  {
8453  rootNav->loadEntry(g_storage);
8454  Entry *root = rootNav->entry();
8455 
8456  //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
8457  // root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
8458 
8459  if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8460  {
8461  MemberDef *md=new MemberDef(rootNav->tagInfo()->tagName,1,1,
8462  "#define",root->name,root->args,0,
8464  md->setTagInfo(rootNav->tagInfo());
8465  md->setLanguage(root->lang);
8466  //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
8467  md->setFileDef(rootNav->parent()->fileDef());
8468  //printf("Adding member=%s\n",md->name().data());
8469  MemberName *mn;
8470  if ((mn=Doxygen::functionNameSDict->find(root->name)))
8471  {
8472  mn->append(md);
8473  }
8474  else
8475  {
8476  mn = new MemberName(root->name);
8477  mn->append(md);
8478  Doxygen::functionNameSDict->append(root->name,mn);
8479  }
8480  }
8481  MemberName *mn=Doxygen::functionNameSDict->find(root->name);
8482  if (mn)
8483  {
8484  MemberNameIterator mni(*mn);
8485  MemberDef *md;
8486  int count=0;
8487  for (;(md=mni.current());++mni)
8488  {
8489  if (md->memberType()==MemberType_Define) count++;
8490  }
8491  if (count==1)
8492  {
8493  for (mni.toFirst();(md=mni.current());++mni)
8494  {
8495  if (md->memberType()==MemberType_Define)
8496  {
8497  md->setDocumentation(root->doc,root->docFile,root->docLine);
8498  md->setDocsForDefinition(!root->proto);
8499  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8500  if (md->inbodyDocumentation().isEmpty())
8501  {
8502  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8503  }
8504  md->setBodySegment(root->bodyLine,root->endBodyLine);
8505  md->setBodyDef(rootNav->fileDef());
8506  md->addSectionsToDefinition(root->anchors);
8507  md->setMaxInitLines(root->initLines);
8508  md->setRefItems(root->sli);
8509  if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8510  addMemberToGroups(root,md);
8511  }
8512  }
8513  }
8514  else if (count>1 &&
8515  (!root->doc.isEmpty() ||
8516  !root->brief.isEmpty() ||
8517  root->bodyLine!=-1
8518  )
8519  )
8520  // multiple defines don't know where to add docs
8521  // but maybe they are in different files together with their documentation
8522  {
8523  for (mni.toFirst();(md=mni.current());++mni)
8524  {
8525  if (md->memberType()==MemberType_Define)
8526  {
8527  FileDef *fd=md->getFileDef();
8528  if (fd && fd->absFilePath()==root->fileName)
8529  // doc and define in the same file assume they belong together.
8530  {
8531 #if 0
8532  if (md->documentation().isEmpty())
8533 #endif
8534  {
8535  md->setDocumentation(root->doc,root->docFile,root->docLine);
8536  md->setDocsForDefinition(!root->proto);
8537  }
8538 #if 0
8539  if (md->briefDescription().isEmpty())
8540 #endif
8541  {
8542  md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8543  }
8544  if (md->inbodyDocumentation().isEmpty())
8545  {
8546  md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8547  }
8548  md->setBodySegment(root->bodyLine,root->endBodyLine);
8549  md->setBodyDef(rootNav->fileDef());
8550  md->addSectionsToDefinition(root->anchors);
8551  md->setRefItems(root->sli);
8552  md->setLanguage(root->lang);
8553  if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8554  addMemberToGroups(root,md);
8555  }
8556  }
8557  }
8558  //warn("define %s found in the following files:\n",root->name.data());
8559  //warn("Cannot determine where to add the documentation found "
8560  // "at line %d of file %s. \n",
8561  // root->startLine,root->fileName.data());
8562  }
8563  }
8564  else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8565  {
8566  static bool preEnabled = Config_getBool(ENABLE_PREPROCESSING);
8567  if (preEnabled)
8568  {
8569  warn(root->fileName,root->startLine,
8570  "documentation for unknown define %s found.\n",
8571  root->name.data()
8572  );
8573  }
8574  else
8575  {
8576  warn(root->fileName,root->startLine,
8577  "found documented #define but ignoring it because "
8578  "ENABLE_PREPROCESSING is NO.\n",
8579  root->name.data()
8580  );
8581  }
8582  }
8583 
8584  rootNav->releaseEntry();
8585  }
8587 }
8588 
8589 //----------------------------------------------------------------------------
8590 
8591 static void findDirDocumentation(EntryNav *rootNav)
8592 {
8593  if (rootNav->section() == Entry::DIRDOC_SEC)
8594  {
8595  rootNav->loadEntry(g_storage);
8596  Entry *root = rootNav->entry();
8597 
8598  QCString normalizedName = root->name;
8599  normalizedName = substitute(normalizedName,"\\","/");
8600  //printf("root->docFile=%s normalizedName=%s\n",
8601  // root->docFile.data(),normalizedName.data());
8602  if (root->docFile==normalizedName) // current dir?
8603  {
8604  int lastSlashPos=normalizedName.findRev('/');
8605  if (lastSlashPos!=-1) // strip file name
8606  {
8607  normalizedName=normalizedName.left(lastSlashPos);
8608  }
8609  }
8610  if (normalizedName.at(normalizedName.length()-1)!='/')
8611  {
8612  normalizedName+='/';
8613  }
8614  DirDef *dir,*matchingDir=0;
8615  SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8616  for (sdi.toFirst();(dir=sdi.current());++sdi)
8617  {
8618  //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8619  if (dir->name().right(normalizedName.length())==normalizedName)
8620  {
8621  if (matchingDir)
8622  {
8623  warn(root->fileName,root->startLine,
8624  "\\dir command matches multiple directories.\n"
8625  " Applying the command for directory %s\n"
8626  " Ignoring the command for directory %s\n",
8627  matchingDir->name().data(),dir->name().data()
8628  );
8629  }
8630  else
8631  {
8632  matchingDir=dir;
8633  }
8634  }
8635  }
8636  if (matchingDir)
8637  {
8638  //printf("Match for with dir %s\n",matchingDir->name().data());
8639  matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8640  matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8641  matchingDir->setRefItems(root->sli);
8642  addDirToGroups(root,matchingDir);
8643  }
8644  else
8645  {
8646  warn(root->fileName,root->startLine,"No matching "
8647  "directory found for command \\dir %s\n",normalizedName.data());
8648  }
8649  rootNav->releaseEntry();
8650  }
8652 }
8653 
8654 
8655 //----------------------------------------------------------------------------
8656 // create a (sorted) list of separate documentation pages
8657 
8658 static void buildPageList(EntryNav *rootNav)
8659 {
8660  if (rootNav->section() == Entry::PAGEDOC_SEC)
8661  {
8662  rootNav->loadEntry(g_storage);
8663  Entry *root = rootNav->entry();
8664 
8665  if (!root->name.isEmpty())
8666  {
8667  addRelatedPage(rootNav);
8668  }
8669 
8670  rootNav->releaseEntry();
8671  }
8672  else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8673  {
8674  rootNav->loadEntry(g_storage);
8675  Entry *root = rootNav->entry();
8676 
8677  QCString title=root->args.stripWhiteSpace();
8678  if (title.isEmpty()) title=theTranslator->trMainPage();
8679  //QCString name = Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8680  QCString name = "index";
8681  addRefItem(root->sli,
8682  name,
8683  "page",
8684  name,
8685  title,
8686  0,0
8687  );
8688 
8689  rootNav->releaseEntry();
8690  }
8692 }
8693 
8694 // search for the main page defined in this project
8695 static void findMainPage(EntryNav *rootNav)
8696 {
8697  if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8698  {
8699  rootNav->loadEntry(g_storage);
8700 
8701  if (Doxygen::mainPage==0 && rootNav->tagInfo()==0)
8702  {
8703  Entry *root = rootNav->entry();
8704  //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8705  QCString title=root->args.stripWhiteSpace();
8706  //QCString indexName=Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8707  QCString indexName="index";
8708  Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8709  indexName, root->brief+root->doc+root->inbodyDocs,title);
8710  //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8711  Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8712  Doxygen::mainPage->setFileName(indexName);
8713  Doxygen::mainPage->setShowToc(root->stat);
8714  addPageToContext(Doxygen::mainPage,rootNav);
8715 
8716  SectionInfo *si = Doxygen::sectionDict->find(Doxygen::mainPage->name());
8717  if (si)
8718  {
8719  if (si->lineNr != -1)
8720  {
8721  warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s, line %d)",Doxygen::mainPage->name().data(),si->fileName.data(),si->lineNr);
8722  }
8723  else
8724  {
8725  warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s)",Doxygen::mainPage->name().data(),si->fileName.data());
8726  }
8727  }
8728  else
8729  {
8730  // a page name is a label as well! but should no be double either
8731  si=new SectionInfo(
8732  indexName, root->startLine,
8733  Doxygen::mainPage->name(),
8734  Doxygen::mainPage->title(),
8736  0); // level 0
8737  Doxygen::sectionDict->append(indexName,si);
8738  Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8739  }
8740  }
8741  else if (rootNav->tagInfo()==0)
8742  {
8743  Entry *root = rootNav->entry();
8744  warn(root->fileName,root->startLine,
8745  "found more than one \\mainpage comment block! (first occurrence: %s, line %d), Skipping current block!",
8746  Doxygen::mainPage->docFile().data(),Doxygen::mainPage->docLine());
8747  }
8748 
8749  rootNav->releaseEntry();
8750  }
8752 }
8753 
8754 // search for the main page imported via tag files and add only the section labels
8755 static void findMainPageTagFiles(EntryNav *rootNav)
8756 {
8757  if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8758  {
8759  rootNav->loadEntry(g_storage);
8760 
8761  if (Doxygen::mainPage && rootNav->tagInfo())
8762  {
8763  Entry *root = rootNav->entry();
8764  Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8765  }
8766  }
8768 }
8769 
8770 static void computePageRelations(EntryNav *rootNav)
8771 {
8772  if ((rootNav->section()==Entry::PAGEDOC_SEC ||
8773  rootNav->section()==Entry::MAINPAGEDOC_SEC
8774  )
8775  && !rootNav->name().isEmpty()
8776  )
8777  {
8778  rootNav->loadEntry(g_storage);
8779  Entry *root = rootNav->entry();
8780 
8781  PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8782  Doxygen::pageSDict->find(root->name) :
8784  if (pd)
8785  {
8786  QListIterator<BaseInfo> bii(*root->extends);
8787  BaseInfo *bi;
8788  for (bii.toFirst();(bi=bii.current());++bii)
8789  {
8790  PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8791  if (subPd)
8792  {
8793  pd->addInnerCompound(subPd);
8794  //printf("*** Added subpage relation: %s->%s\n",
8795  // pd->name().data(),subPd->name().data());
8796  }
8797  }
8798  }
8799 
8800  rootNav->releaseEntry();
8801  }
8803 }
8804 
8805 static void checkPageRelations()
8806 {
8807  PageSDict::Iterator pdi(*Doxygen::pageSDict);
8808  PageDef *pd=0;
8809  for (pdi.toFirst();(pd=pdi.current());++pdi)
8810  {
8811  Definition *ppd = pd->getOuterScope();
8812  while (ppd)
8813  {
8814  if (ppd==pd)
8815  {
8816  err("page defined at line %d of file %s with label %s is a subpage "
8817  "of itself! Please remove this cyclic dependency.\n",
8818  pd->docLine(),pd->docFile().data(),pd->name().data());
8819  exit(1);
8820  }
8821  ppd=ppd->getOuterScope();
8822  }
8823  }
8824 }
8825 
8826 //----------------------------------------------------------------------------
8827 
8829 {
8830  SDict<SectionInfo>::Iterator sdi(*Doxygen::sectionDict);
8831  SectionInfo *si;
8832  for (;(si=sdi.current());++sdi)
8833  {
8834  //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8835  // si->label.data(),si->definition?si->definition->name().data():"<none>",
8836  // si->fileName.data());
8837  PageDef *pd=0;
8838 
8839  // hack: the items of a todo/test/bug/deprecated list are all fragments from
8840  // different files, so the resulting section's all have the wrong file
8841  // name (not from the todo/test/bug/deprecated list, but from the file in
8842  // which they are defined). We correct this here by looking at the
8843  // generated section labels!
8844  QDictIterator<RefList> rli(*Doxygen::xrefLists);
8845  RefList *rl;
8846  for (rli.toFirst();(rl=rli.current());++rli)
8847  {
8848  QCString label="_"+rl->listName(); // "_todo", "_test", ...
8849  if (si->label.left(label.length())==label)
8850  {
8851  si->fileName=rl->listName();
8852  si->generated=TRUE;
8853  break;
8854  }
8855  }
8856 
8857  //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8858  if (!si->generated)
8859  {
8860  // if this section is in a page and the page is in a group, then we
8861  // have to adjust the link file name to point to the group.
8862  if (!si->fileName.isEmpty() &&
8863  (pd=Doxygen::pageSDict->find(si->fileName)) &&
8864  pd->getGroupDef())
8865  {
8866  si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8867  }
8868 
8869  if (si->definition)
8870  {
8871  // TODO: there should be one function in Definition that returns
8872  // the file to link to, so we can avoid the following tests.
8873  GroupDef *gd=0;
8875  {
8876  gd = ((MemberDef *)si->definition)->getGroupDef();
8877  }
8878 
8879  if (gd)
8880  {
8881  si->fileName=gd->getOutputFileBase().copy();
8882  }
8883  else
8884  {
8885  //si->fileName=si->definition->getOutputFileBase().copy();
8886  //printf("Setting si->fileName to %s\n",si->fileName.data());
8887  }
8888  }
8889  }
8890  //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8891  }
8892 }
8893 
8894 
8895 
8896 //----------------------------------------------------------------------------
8897 // generate all separate documentation pages
8898 
8899 
8900 static void generatePageDocs()
8901 {
8902  //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8903  if (documentedPages==0) return;
8904  PageSDict::Iterator pdi(*Doxygen::pageSDict);
8905  PageDef *pd=0;
8906  for (pdi.toFirst();(pd=pdi.current());++pdi)
8907  {
8908  if (!pd->getGroupDef() && !pd->isReference())
8909  {
8910  msg("Generating docs for page %s...\n",pd->name().data());
8912  pd->writeDocumentation(*g_outputList);
8913  Doxygen::insideMainPage=FALSE;
8914  }
8915  }
8916 }
8917 
8918 //----------------------------------------------------------------------------
8919 // create a (sorted) list & dictionary of example pages
8920 
8921 static void buildExampleList(EntryNav *rootNav)
8922 {
8923  if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty())
8924  {
8925  rootNav->loadEntry(g_storage);
8926  Entry *root = rootNav->entry();
8927 
8928  if (Doxygen::exampleSDict->find(root->name))
8929  {
8930  warn(root->fileName,root->startLine,
8931  "Example %s was already documented. Ignoring "
8932  "documentation found here.",
8933  root->name.data()
8934  );
8935  }
8936  else
8937  {
8938  PageDef *pd=new PageDef(root->fileName,root->startLine,
8939  root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8940  pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8941  pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
8942  pd->addSectionsToDefinition(root->anchors);
8943  pd->setLanguage(root->lang);
8944  //pi->addSections(root->anchors);
8945 
8946  Doxygen::exampleSDict->inSort(root->name,pd);
8947  //we don't add example to groups
8948  //addExampleToGroups(root,pd);
8949  }
8950 
8951  rootNav->releaseEntry();
8952  }
8954 }
8955 
8956 //----------------------------------------------------------------------------
8957 // prints the Entry tree (for debugging)
8958 
8959 void printNavTree(EntryNav *rootNav,int indent)
8960 {
8961  QCString indentStr;
8962  indentStr.fill(' ',indent);
8963  msg("%s%s (sec=0x%x)\n",
8964  indentStr.isEmpty()?"":indentStr.data(),
8965  rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8966  rootNav->section());
8967  if (rootNav->children())
8968  {
8969  EntryNavListIterator eli(*rootNav->children());
8970  for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8971  }
8972 }
8973 
8974 
8975 //----------------------------------------------------------------------------
8976 // generate the example documentation
8977 
8978 static void generateExampleDocs()
8979 {
8980  g_outputList->disable(OutputGenerator::Man);
8981  PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8982  PageDef *pd=0;
8983  for (pdi.toFirst();(pd=pdi.current());++pdi)
8984  {
8985  msg("Generating docs for example %s...\n",pd->name().data());
8987  QCString n=pd->getOutputFileBase();
8988  startFile(*g_outputList,n,n,pd->name());
8989  startTitle(*g_outputList,n);
8990  g_outputList->docify(pd->name());
8991  endTitle(*g_outputList,n,0);
8992  g_outputList->startContents();
8993  g_outputList->generateDoc(pd->docFile(), // file
8994  pd->docLine(), // startLine
8995  pd, // context
8996  0, // memberDef
8997  pd->documentation()+"\n\n\\include "+pd->name(), // docs
8998  TRUE, // index words
8999  TRUE, // is example
9000  pd->name()
9001  );
9002  endFile(*g_outputList); // contains g_outputList->endContents()
9003  }
9004  g_outputList->enable(OutputGenerator::Man);
9005 }
9006 
9007 //----------------------------------------------------------------------------
9008 // generate module pages
9009 
9010 static void generateGroupDocs()
9011 {
9012  GroupSDict::Iterator gli(*Doxygen::groupSDict);
9013  GroupDef *gd;
9014  for (gli.toFirst();(gd=gli.current());++gli)
9015  {
9016  if (!gd->isReference())
9017  {
9018  gd->writeDocumentation(*g_outputList);
9019  }
9020  }
9021 }
9022 
9023 //----------------------------------------------------------------------------
9024 
9025 //static void generatePackageDocs()
9026 //{
9027 // writePackageIndex(*g_outputList);
9028 //
9029 // if (Doxygen::packageDict.count()>0)
9030 // {
9031 // PackageSDict::Iterator pdi(Doxygen::packageDict);
9032 // PackageDef *pd;
9033 // for (pdi.toFirst();(pd=pdi.current());++pdi)
9034 // {
9035 // pd->writeDocumentation(*g_outputList);
9036 // }
9037 // }
9038 //}
9039 
9040 //----------------------------------------------------------------------------
9041 // generate module pages
9042 
9044 {
9045  //writeNamespaceIndex(*g_outputList);
9046 
9047  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
9048  NamespaceDef *nd;
9049  // for each namespace...
9050  for (;(nd=nli.current());++nli)
9051  {
9052 
9053  if (nd->isLinkableInProject())
9054  {
9055  msg("Generating docs for namespace %s\n",nd->name().data());
9056  nd->writeDocumentation(*g_outputList);
9057  }
9058 
9059  // for each class in the namespace...
9060  ClassSDict::Iterator cli(*nd->getClassSDict());
9061  ClassDef *cd;
9062  for ( ; (cd=cli.current()) ; ++cli )
9063  {
9064  if ( ( cd->isLinkableInProject() &&
9065  cd->templateMaster()==0
9066  ) // skip external references, anonymous compounds and
9067  // template instances and nested classes
9068  && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
9069  )
9070  {
9071  msg("Generating docs for compound %s...\n",cd->name().data());
9072 
9073  cd->writeDocumentation(*g_outputList);
9074  cd->writeMemberList(*g_outputList);
9075  }
9076  cd->writeDocumentationForInnerClasses(*g_outputList);
9077  }
9078  }
9079 }
9080 
9081 #if defined(_WIN32)
9082 static QCString fixSlashes(QCString &s)
9083 {
9084  QCString result;
9085  uint i;
9086  for (i=0;i<s.length();i++)
9087  {
9088  switch(s.at(i))
9089  {
9090  case '/':
9091  case '\\':
9092  result+="\\\\";
9093  break;
9094  default:
9095  result+=s.at(i);
9096  }
9097  }
9098  return result;
9099 }
9100 #endif
9101 
9102 
9103 //----------------------------------------------------------------------------
9104 
9109 static void generateConfigFile(const char *configFile,bool shortList,
9110  bool updateOnly=FALSE)
9111 {
9112  QFile f;
9113  bool fileOpened=openOutputFile(configFile,f);
9114  bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
9115  if (fileOpened)
9116  {
9117  FTextStream t(&f);
9118  Config::writeTemplate(t,shortList,updateOnly);
9119  if (!writeToStdout)
9120  {
9121  if (!updateOnly)
9122  {
9123  msg("\n\nConfiguration file `%s' created.\n\n",configFile);
9124  msg("Now edit the configuration file and enter\n\n");
9125  if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
9126  msg(" doxygen %s\n\n",configFile);
9127  else
9128  msg(" doxygen\n\n");
9129  msg("to generate the documentation for your project\n\n");
9130  }
9131  else
9132  {
9133  msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
9134  }
9135  }
9136  }
9137  else
9138  {
9139  err("Cannot open file %s for writing\n",configFile);
9140  exit(1);
9141  }
9142 }
9143 
9144 //----------------------------------------------------------------------------
9145 // read and parse a tag file
9146 
9147 //static bool readLineFromFile(QFile &f,QCString &s)
9148 //{
9149 // char c=0;
9150 // s.resize(0);
9151 // while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
9152 // return f.atEnd();
9153 //}
9154 
9155 //----------------------------------------------------------------------------
9156 
9157 static void readTagFile(Entry *root,const char *tl)
9158 {
9159  QCString tagLine = tl;
9160  QCString fileName;
9161  QCString destName;
9162  int eqPos = tagLine.find('=');
9163  if (eqPos!=-1) // tag command contains a destination
9164  {
9165  fileName = tagLine.left(eqPos).stripWhiteSpace();
9166  destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9167  QFileInfo fi(fileName);
9168  Doxygen::tagDestinationDict.insert(fi.absFilePath().utf8(),new QCString(destName));
9169  //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
9170  }
9171  else
9172  {
9173  fileName = tagLine;
9174  }
9175 
9176  QFileInfo fi(fileName);
9177  if (!fi.exists() || !fi.isFile())
9178  {
9179  err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
9180  fileName.data());
9181  return;
9182  }
9183 
9184  if (!destName.isEmpty())
9185  msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
9186  else
9187  msg("Reading tag file `%s'...\n",fileName.data());
9188 
9189  parseTagFile(root,fi.absFilePath().utf8());
9190 }
9191 
9192 //----------------------------------------------------------------------------
9193 static void copyLatexStyleSheet()
9194 {
9195  QStrList latexExtraStyleSheet = Config_getList(LATEX_EXTRA_STYLESHEET);
9196  for (uint i=0; i<latexExtraStyleSheet.count(); ++i)
9197  {
9198  QCString fileName(latexExtraStyleSheet.at(i));
9199  if (!fileName.isEmpty())
9200  {
9201  QFileInfo fi(fileName);
9202  if (!fi.exists())
9203  {
9204  err("Style sheet '%s' specified by LATEX_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9205  }
9206  else
9207  {
9208  QCString destFileName = Config_getString(LATEX_OUTPUT)+"/"+fi.fileName().data();
9209  if (!checkExtension(fi.fileName().data(), latexStyleExtension))
9210  {
9211  destFileName += latexStyleExtension;
9212  }
9213  copyFile(fileName, destFileName);
9214  }
9215  }
9216  }
9217 }
9218 
9219 //----------------------------------------------------------------------------
9220 static void copyStyleSheet()
9221 {
9222  QCString &htmlStyleSheet = Config_getString(HTML_STYLESHEET);
9223  if (!htmlStyleSheet.isEmpty())
9224  {
9225  QFileInfo fi(htmlStyleSheet);
9226  if (!fi.exists())
9227  {
9228  err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
9229  htmlStyleSheet.resize(0); // revert to the default
9230  }
9231  else
9232  {
9233  QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9234  copyFile(htmlStyleSheet,destFileName);
9235  }
9236  }
9237  QStrList htmlExtraStyleSheet = Config_getList(HTML_EXTRA_STYLESHEET);
9238  for (uint i=0; i<htmlExtraStyleSheet.count(); ++i)
9239  {
9240  QCString fileName(htmlExtraStyleSheet.at(i));
9241  if (!fileName.isEmpty())
9242  {
9243  QFileInfo fi(fileName);
9244  if (!fi.exists())
9245  {
9246  err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9247  }
9248  else if (fi.fileName()=="doxygen.css" || fi.fileName()=="tabs.css" || fi.fileName()=="navtree.css")
9249  {
9250  err("Style sheet %s specified by HTML_EXTRA_STYLESHEET is already a built-in stylesheet. Please use a different name\n",fi.fileName().data());
9251  }
9252  else
9253  {
9254  QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9255  copyFile(fileName, destFileName);
9256  }
9257  }
9258  }
9259 }
9260 
9261 static void copyLogo(const QCString &outputOption)
9262 {
9263  QCString &projectLogo = Config_getString(PROJECT_LOGO);
9264  if (!projectLogo.isEmpty())
9265  {
9266  QFileInfo fi(projectLogo);
9267  if (!fi.exists())
9268  {
9269  err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
9270  projectLogo.resize(0); // revert to the default
9271  }
9272  else
9273  {
9274  QCString destFileName = outputOption+"/"+fi.fileName().data();
9275  copyFile(projectLogo,destFileName);
9276  Doxygen::indexList->addImageFile(fi.fileName().data());
9277  }
9278  }
9279 }
9280 
9281 static void copyExtraFiles(QStrList files,const QString &filesOption,const QCString &outputOption)
9282 {
9283  uint i;
9284  for (i=0; i<files.count(); ++i)
9285  {
9286  QCString fileName(files.at(i));
9287 
9288  if (!fileName.isEmpty())
9289  {
9290  QFileInfo fi(fileName);
9291  if (!fi.exists())
9292  {
9293  err("Extra file '%s' specified in %s does not exist!\n", fileName.data(),filesOption.data());
9294  }
9295  else
9296  {
9297  QCString destFileName = outputOption+"/"+fi.fileName().data();
9298  Doxygen::indexList->addImageFile(fi.fileName().utf8());
9299  copyFile(fileName, destFileName);
9300  }
9301  }
9302  }
9303 }
9304 
9305 //----------------------------------------------------------------------------
9306 
9307 static ParserInterface *getParserForFile(const char *fn)
9308 {
9309  QCString fileName=fn;
9310  QCString extension;
9311  int sep = fileName.findRev('/');
9312  int ei = fileName.findRev('.');
9313  if (ei!=-1 && (sep==-1 || ei>sep)) // matches dir/file.ext but not dir.1/file
9314  {
9315  extension=fileName.right(fileName.length()-ei);
9316  }
9317  else
9318  {
9319  extension = ".no_extension";
9320  }
9321 
9322  return Doxygen::parserManager->getParser(extension);
9323 }
9324 
9325 static void parseFile(ParserInterface *parser,
9326  Entry *root,EntryNav *rootNav,FileDef *fd,const char *fn,
9327  bool sameTu,QStrList &filesInSameTu)
9328 {
9329 #if USE_LIBCLANG
9330  static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9331 #else
9332  static bool clangAssistedParsing = FALSE;
9333 #endif
9334  QCString fileName=fn;
9335  QCString extension;
9336  int ei = fileName.findRev('.');
9337  if (ei!=-1)
9338  {
9339  extension=fileName.right(fileName.length()-ei);
9340  }
9341  else
9342  {
9343  extension = ".no_extension";
9344  }
9345 
9346  QFileInfo fi(fileName);
9347  BufStr preBuf(fi.size()+4096);
9348 
9349  if (Config_getBool(ENABLE_PREPROCESSING) &&
9350  parser->needsPreprocessing(extension))
9351  {
9352  BufStr inBuf(fi.size()+4096);
9353  msg("Preprocessing %s...\n",fn);
9354  readInputFile(fileName,inBuf);
9355  preprocessFile(fileName,inBuf,preBuf);
9356  }
9357  else // no preprocessing
9358  {
9359  msg("Reading %s...\n",fn);
9360  readInputFile(fileName,preBuf);
9361  }
9362  if (preBuf.data() && preBuf.curPos()>0 && *(preBuf.data()+preBuf.curPos()-1)!='\n')
9363  {
9364  preBuf.addChar('\n'); // add extra newline to help parser
9365  }
9366 
9367  BufStr convBuf(preBuf.curPos()+1024);
9368 
9369  // convert multi-line C++ comments to C style comments
9370  convertCppComments(&preBuf,&convBuf,fileName);
9371 
9372  convBuf.addChar('\0');
9373 
9374  if (clangAssistedParsing && !sameTu)
9375  {
9376  fd->getAllIncludeFilesRecursively(filesInSameTu);
9377  }
9378 
9379  // use language parse to parse the file
9380  parser->parseInput(fileName,convBuf.data(),root,sameTu,filesInSameTu);
9381 
9382  // store the Entry tree in a file and create an index to
9383  // navigate/load entries
9384  //printf("root->createNavigationIndex for %s\n",fd->name().data());
9385  root->createNavigationIndex(rootNav,g_storage,fd);
9386 }
9387 
9389 static void parseFiles(Entry *root,EntryNav *rootNav)
9390 {
9391 #if USE_LIBCLANG
9392  static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9393  if (clangAssistedParsing)
9394  {
9395  QDict<void> g_processedFiles(10007);
9396 
9397  // create a dictionary with files to process
9398  QDict<void> g_filesToProcess(10007);
9400  QCString *s;
9401  for (;(s=it.current());++it)
9402  {
9403  g_filesToProcess.insert(*s,(void*)0x8);
9404  }
9405 
9406  // process source files (and their include dependencies)
9407  for (it.toFirst();(s=it.current());++it)
9408  {
9409  bool ambig;
9410  FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9411  ASSERT(fd!=0);
9412  if (fd->isSource() && !fd->isReference()) // this is a source file
9413  {
9414  QStrList filesInSameTu;
9415  ParserInterface * parser = getParserForFile(s->data());
9416  parser->startTranslationUnit(s->data());
9417  parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9418  //printf(" got %d extra files in tu\n",filesInSameTu.count());
9419 
9420  // Now process any include files in the same translation unit
9421  // first. When libclang is used this is much more efficient.
9422  char *incFile = filesInSameTu.first();
9423  while (incFile && g_filesToProcess.find(incFile))
9424  {
9425  if (qstrcmp(incFile,s->data()) && !g_processedFiles.find(incFile))
9426  {
9427  FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
9428  if (ifd && !ifd->isReference())
9429  {
9430  QStrList moreFiles;
9431  //printf(" Processing %s in same translation unit as %s\n",incFile,s->data());
9432  parseFile(parser,root,rootNav,ifd,incFile,TRUE,moreFiles);
9433  g_processedFiles.insert(incFile,(void*)0x8);
9434  }
9435  }
9436  incFile = filesInSameTu.next();
9437  }
9438  parser->finishTranslationUnit();
9439  g_processedFiles.insert(*s,(void*)0x8);
9440  }
9441  }
9442  // process remaining files
9443  for (it.toFirst();(s=it.current());++it)
9444  {
9445  if (!g_processedFiles.find(*s)) // not yet processed
9446  {
9447  bool ambig;
9448  QStrList filesInSameTu;
9449  FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9450  ASSERT(fd!=0);
9451  ParserInterface * parser = getParserForFile(s->data());
9452  parser->startTranslationUnit(s->data());
9453  parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9454  parser->finishTranslationUnit();
9455  g_processedFiles.insert(*s,(void*)0x8);
9456  }
9457  }
9458  }
9459  else // normal pocessing
9460 #endif
9461  {
9463  QCString *s;
9464  for (;(s=it.current());++it)
9465  {
9466  bool ambig;
9467  QStrList filesInSameTu;
9468  FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9469  ASSERT(fd!=0);
9470  ParserInterface * parser = getParserForFile(s->data());
9471  parser->startTranslationUnit(s->data());
9472  parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9473  }
9474  }
9475 }
9476 
9477 // resolves a path that may include symlinks, if a recursive symlink is
9478 // found an empty string is returned.
9479 static QCString resolveSymlink(QCString path)
9480 {
9481  int sepPos=0;
9482  int oldPos=0;
9483  QFileInfo fi;
9484  QDict<void> nonSymlinks;
9485  QDict<void> known;
9486  QCString result = path;
9487  QCString oldPrefix = "/";
9488  do
9489  {
9490 #ifdef WIN32
9491  // UNC path, skip server and share name
9492  if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
9493  sepPos = result.find('/',2);
9494  if (sepPos!=-1)
9495  sepPos = result.find('/',sepPos+1);
9496 #else
9497  sepPos = result.find('/',sepPos+1);
9498 #endif
9499  QCString prefix = sepPos==-1 ? result : result.left(sepPos);
9500  if (nonSymlinks.find(prefix)==0)
9501  {
9502  fi.setFile(prefix);
9503  if (fi.isSymLink())
9504  {
9505  QString target = fi.readLink();
9506  bool isRelative = QFileInfo(target).isRelative();
9507  if (isRelative)
9508  {
9509  target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
9510  }
9511  if (sepPos!=-1)
9512  {
9513  if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
9514  {
9515  target+='/';
9516  }
9517  target+=result.mid(sepPos);
9518  }
9519  result = QDir::cleanDirPath(target).data();
9520  sepPos = 0;
9521  if (known.find(result)) return QCString(); // recursive symlink!
9522  known.insert(result,(void*)0x8);
9523  if (isRelative)
9524  {
9525  sepPos = oldPos;
9526  }
9527  else // link to absolute path
9528  {
9529  sepPos = 0;
9530  oldPrefix = "/";
9531  }
9532  }
9533  else
9534  {
9535  nonSymlinks.insert(prefix,(void*)0x8);
9536  oldPrefix = prefix;
9537  }
9538  oldPos = sepPos;
9539  }
9540  }
9541  while (sepPos!=-1);
9542  return QDir::cleanDirPath(result).data();
9543 }
9544 
9545 static QDict<void> g_pathsVisited(1009);
9546 
9547 //----------------------------------------------------------------------------
9548 // Read all files matching at least one pattern in `patList' in the
9549 // directory represented by `fi'.
9550 // The directory is read iff the recusiveFlag is set.
9551 // The contents of all files is append to the input string
9552 
9553 int readDir(QFileInfo *fi,
9554  FileNameList *fnList,
9555  FileNameDict *fnDict,
9556  StringDict *exclDict,
9557  QStrList *patList,
9558  QStrList *exclPatList,
9559  StringList *resultList,
9560  StringDict *resultDict,
9561  bool errorIfNotExist,
9562  bool recursive,
9563  QDict<void> *killDict,
9564  QDict<void> *paths
9565  )
9566 {
9567  QCString dirName = fi->absFilePath().utf8();
9568  if (paths && paths->find(dirName)==0)
9569  {
9570  paths->insert(dirName,(void*)0x8);
9571  }
9572  if (fi->isSymLink())
9573  {
9574  dirName = resolveSymlink(dirName.data());
9575  if (dirName.isEmpty()) return 0; // recusive symlink
9576  if (g_pathsVisited.find(dirName)) return 0; // already visited path
9577  g_pathsVisited.insert(dirName,(void*)0x8);
9578  }
9579  QDir dir(dirName);
9580  dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
9581  int totalSize=0;
9582  msg("Searching for files in directory %s\n", fi->absFilePath().data());
9583  //printf("killDict=%p count=%d\n",killDict,killDict->count());
9584 
9585  const QFileInfoList *list = dir.entryInfoList();
9586  if (list)
9587  {
9588  QFileInfoListIterator it( *list );
9589  QFileInfo *cfi;
9590 
9591  while ((cfi=it.current()))
9592  {
9593  if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0)
9594  { // file should not be excluded
9595  //printf("killDict->find(%s)\n",cfi->absFilePath().data());
9596  if (!cfi->exists() || !cfi->isReadable())
9597  {
9598  if (errorIfNotExist)
9599  {
9600  warn_uncond("source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
9601  }
9602  }
9603  else if (cfi->isFile() &&
9604  (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9605  (patList==0 || patternMatch(*cfi,patList)) &&
9606  !patternMatch(*cfi,exclPatList) &&
9607  (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
9608  )
9609  {
9610  totalSize+=cfi->size()+cfi->absFilePath().length()+4;
9611  QCString name=cfi->fileName().utf8();
9612  //printf("New file %s\n",name.data());
9613  if (fnDict)
9614  {
9615  FileDef *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
9616  FileName *fn=0;
9617  if (!name.isEmpty() && (fn=(*fnDict)[name]))
9618  {
9619  fn->append(fd);
9620  }
9621  else
9622  {
9623  fn = new FileName(cfi->absFilePath().utf8(),name);
9624  fn->append(fd);
9625  if (fnList) fnList->inSort(fn);
9626  fnDict->insert(name,fn);
9627  }
9628  }
9629  QCString *rs=0;
9630  if (resultList || resultDict)
9631  {
9632  rs=new QCString(cfi->absFilePath().utf8());
9633  }
9634  if (resultList) resultList->append(rs);
9635  if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
9636  if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
9637  }
9638  else if (recursive &&
9639  (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9640  cfi->isDir() &&
9641  !patternMatch(*cfi,exclPatList) &&
9642  cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
9643  {
9644  cfi->setFile(cfi->absFilePath());
9645  totalSize+=readDir(cfi,fnList,fnDict,exclDict,
9646  patList,exclPatList,resultList,resultDict,errorIfNotExist,
9647  recursive,killDict,paths);
9648  }
9649  }
9650  ++it;
9651  }
9652  }
9653  return totalSize;
9654 }
9655 
9656 
9657 //----------------------------------------------------------------------------
9658 // read a file or all files in a directory and append their contents to the
9659 // input string. The names of the files are appended to the `fiList' list.
9660 
9661 int readFileOrDirectory(const char *s,
9662  FileNameList *fnList,
9663  FileNameDict *fnDict,
9664  StringDict *exclDict,
9665  QStrList *patList,
9666  QStrList *exclPatList,
9667  StringList *resultList,
9668  StringDict *resultDict,
9669  bool recursive,
9670  bool errorIfNotExist,
9671  QDict<void> *killDict,
9672  QDict<void> *paths
9673  )
9674 {
9675  //printf("killDict=%p count=%d\n",killDict,killDict->count());
9676  // strip trailing slashes
9677  if (s==0) return 0;
9678  QCString fs = s;
9679  char lc = fs.at(fs.length()-1);
9680  if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9681 
9682  QFileInfo fi(fs);
9683  //printf("readFileOrDirectory(%s)\n",s);
9684  int totalSize=0;
9685  {
9686  if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9687  {
9688  if (!fi.exists() || !fi.isReadable())
9689  {
9690  if (errorIfNotExist)
9691  {
9692  warn_uncond("source %s is not a readable file or directory... skipping.\n",s);
9693  }
9694  }
9695  else if (!Config_getBool(EXCLUDE_SYMLINKS) || !fi.isSymLink())
9696  {
9697  if (fi.isFile())
9698  {
9699  QCString dirPath = fi.dirPath(TRUE).utf8();
9700  QCString filePath = fi.absFilePath().utf8();
9701  if (paths && paths->find(dirPath))
9702  {
9703  paths->insert(dirPath,(void*)0x8);
9704  }
9705  //printf("killDict->find(%s)\n",fi.absFilePath().data());
9706  if (killDict==0 || killDict->find(filePath)==0)
9707  {
9708  totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input);
9709  //fiList->inSort(new FileInfo(fi));
9710  QCString name=fi.fileName().utf8();
9711  //printf("New file %s\n",name.data());
9712  if (fnDict)
9713  {
9714  FileDef *fd=new FileDef(dirPath+"/",name);
9715  FileName *fn=0;
9716  if (!name.isEmpty() && (fn=(*fnDict)[name]))
9717  {
9718  fn->append(fd);
9719  }
9720  else
9721  {
9722  fn = new FileName(filePath,name);
9723  fn->append(fd);
9724  if (fnList) fnList->inSort(fn);
9725  fnDict->insert(name,fn);
9726  }
9727  }
9728  QCString *rs=0;
9729  if (resultList || resultDict)
9730  {
9731  rs=new QCString(filePath);
9732  if (resultList) resultList->append(rs);
9733  if (resultDict) resultDict->insert(filePath,rs);
9734  }
9735 
9736  if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9737  }
9738  }
9739  else if (fi.isDir()) // readable dir
9740  {
9741  totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9742  exclPatList,resultList,resultDict,errorIfNotExist,
9743  recursive,killDict,paths);
9744  }
9745  }
9746  }
9747  }
9748  return totalSize;
9749 }
9750 
9751 //----------------------------------------------------------------------------
9752 
9754 {
9755  QFile f(Config_getString(HTML_OUTPUT)+"/formula.repository");
9756  if (f.open(IO_ReadOnly)) // open repository
9757  {
9758  msg("Reading formula repository...\n");
9759  QTextStream t(&f);
9760  QCString line;
9761  while (!t.eof())
9762  {
9763  line=t.readLine().utf8();
9764  int se=line.find(':'); // find name and text separator.
9765  if (se==-1)
9766  {
9767  warn_uncond("formula.repository is corrupted!\n");
9768  break;
9769  }
9770  else
9771  {
9772  QCString formName = line.left(se);
9773  QCString formText = line.right(line.length()-se-1);
9774  Formula *f=new Formula(formText);
9775  Doxygen::formulaList->setAutoDelete(TRUE);
9776  Doxygen::formulaList->append(f);
9777  Doxygen::formulaDict->insert(formText,f);
9778  Doxygen::formulaNameDict->insert(formName,f);
9779  }
9780  }
9781  }
9782 }
9783 
9784 //----------------------------------------------------------------------------
9785 
9786 static void expandAliases()
9787 {
9788  QDictIterator<QCString> adi(Doxygen::aliasDict);
9789  QCString *s;
9790  for (adi.toFirst();(s=adi.current());++adi)
9791  {
9792  *s = expandAlias(adi.currentKey(),*s);
9793  }
9794 }
9795 
9796 //----------------------------------------------------------------------------
9797 
9798 static void escapeAliases()
9799 {
9800  QDictIterator<QCString> adi(Doxygen::aliasDict);
9801  QCString *s;
9802  for (adi.toFirst();(s=adi.current());++adi)
9803  {
9804  QCString value=*s,newValue;
9805  int in,p=0;
9806  // for each \n in the alias command value
9807  while ((in=value.find("\\n",p))!=-1)
9808  {
9809  newValue+=value.mid(p,in-p);
9810  // expand \n's except if \n is part of a built-in command.
9811  if (value.mid(in,5)!="\\note" &&
9812  value.mid(in,5)!="\\name" &&
9813  value.mid(in,10)!="\\namespace" &&
9814  value.mid(in,14)!="\\nosubgrouping"
9815  )
9816  {
9817  newValue+="\\_linebr ";
9818  }
9819  else
9820  {
9821  newValue+="\\n";
9822  }
9823  p=in+2;
9824  }
9825  newValue+=value.mid(p,value.length()-p);
9826  *s=newValue;
9827  //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9828  }
9829 }
9830 
9831 //----------------------------------------------------------------------------
9832 
9834 {
9835  // add aliases to a dictionary
9836  Doxygen::aliasDict.setAutoDelete(TRUE);
9837  QStrList &aliasList = Config_getList(ALIASES);
9838  const char *s=aliasList.first();
9839  while (s)
9840  {
9841  if (Doxygen::aliasDict[s]==0)
9842  {
9843  QCString alias=s;
9844  int i=alias.find('=');
9845  if (i>0)
9846  {
9847  QCString name=alias.left(i).stripWhiteSpace();
9848  QCString value=alias.right(alias.length()-i-1);
9849  //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
9850  if (!name.isEmpty())
9851  {
9852  QCString *dn=Doxygen::aliasDict[name];
9853  if (dn==0) // insert new alias
9854  {
9855  Doxygen::aliasDict.insert(name,new QCString(value));
9856  }
9857  else // overwrite previous alias
9858  {
9859  *dn=value;
9860  }
9861  }
9862  }
9863  }
9864  s=aliasList.next();
9865  }
9866  expandAliases();
9867  escapeAliases();
9868 }
9869 
9870 //----------------------------------------------------------------------------
9871 
9873 {
9874  QCString anchor;
9876  {
9877  MemberDef *md = (MemberDef *)d;
9878  anchor=":"+md->anchor();
9879  }
9880  QCString scope;
9882  {
9884  }
9885  t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9886  << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9887  << scope << "','"
9888  << d->name() << "','"
9889  << d->getDefFileName() << "','"
9890  << d->getDefLine()
9891  << "');" << endl;
9892 }
9893 
9894 static void dumpSymbolMap()
9895 {
9896  QFile f("symbols.sql");
9897  if (f.open(IO_WriteOnly))
9898  {
9899  FTextStream t(&f);
9900  QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9901  DefinitionIntf *intf;
9902  for (;(intf=di.current());++di)
9903  {
9904  if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9905  {
9907  Definition *d;
9908  // for each symbol
9909  for (dli.toFirst();(d=dli.current());++dli)
9910  {
9911  dumpSymbol(t,d);
9912  }
9913  }
9914  else // single symbol
9915  {
9916  Definition *d = (Definition *)intf;
9917  if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9918  }
9919  }
9920  }
9921 }
9922 
9923 // print developer options of doxygen
9924 static void devUsage()
9925 {
9926  msg("Developer parameters:\n");
9927  msg(" -m dump symbol map\n");
9928  msg(" -b output to wizard\n");
9929  msg(" -T activates output generation via Django like template\n");
9930  msg(" -d <level> enable a debug level, such as (multiple invocations of -d are possible):\n");
9932 }
9933 
9934 
9935 //----------------------------------------------------------------------------
9936 // print the usage of doxygen
9937 
9938 static void usage(const char *name)
9939 {
9940  msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2015\n\n",versionString);
9941  msg("You can use doxygen in a number of ways:\n\n");
9942  msg("1) Use doxygen to generate a template configuration file:\n");
9943  msg(" %s [-s] -g [configName]\n\n",name);
9944  msg(" If - is used for configName doxygen will write to standard output.\n\n");
9945  msg("2) Use doxygen to update an old configuration file:\n");
9946  msg(" %s [-s] -u [configName]\n\n",name);
9947  msg("3) Use doxygen to generate documentation using an existing ");
9948  msg("configuration file:\n");
9949  msg(" %s [configName]\n\n",name);
9950  msg(" If - is used for configName doxygen will read from standard input.\n\n");
9951  msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9952  msg(" generated documentation:\n");
9953  msg(" %s -l [layoutFileName.xml]\n\n",name);
9954  msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9955  msg(" RTF: %s -w rtf styleSheetFile\n",name);
9956  msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9957  msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9958  msg("6) Use doxygen to generate a rtf extensions file\n");
9959  msg(" RTF: %s -e rtf extensionsFile\n\n",name);
9960  msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
9961  msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9962  msg("-v print version string\n");
9963 }
9964 
9965 //----------------------------------------------------------------------------
9966 // read the argument of option `c' from the comment argument list and
9967 // update the option index `optind'.
9968 
9969 static const char *getArg(int argc,char **argv,int &optind)
9970 {
9971  char *s=0;
9972  if (qstrlen(&argv[optind][2])>0)
9973  s=&argv[optind][2];
9974  else if (optind+1<argc && argv[optind+1][0]!='-')
9975  s=argv[++optind];
9976  return s;
9977 }
9978 
9979 //----------------------------------------------------------------------------
9980 
9982 {
9983  initResources();
9984  const char *lang = portable_getenv("LC_ALL");
9985  if (lang) portable_setenv("LANG",lang);
9986  setlocale(LC_ALL,"");
9987  setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
9988  setlocale(LC_NUMERIC,"C");
9989 
9990  Doxygen::runningTime.start();
9991  initPreprocessor();
9992 
9993  Doxygen::parserManager = new ParserManager;
9994  Doxygen::parserManager->registerDefaultParser( new FileParser);
9995  Doxygen::parserManager->registerParser("c", new CLanguageScanner);
9996  Doxygen::parserManager->registerParser("python", new PythonLanguageScanner);
9997  Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
9998  Doxygen::parserManager->registerParser("fortranfree", new FortranLanguageScannerFree);
9999  Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed);
10000  Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner);
10001  Doxygen::parserManager->registerParser("xml", new XMLScanner);
10002  Doxygen::parserManager->registerParser("tcl", new TclLanguageScanner);
10003  Doxygen::parserManager->registerParser("md", new MarkdownFileParser);
10004 
10005  // register any additional parsers here...
10006 
10011 
10012  Doxygen::symbolMap = new QDict<DefinitionIntf>(50177);
10013 #ifdef USE_LIBCLANG
10014  Doxygen::clangUsrMap = new QDict<Definition>(50177);
10015 #endif
10016  Doxygen::inputNameList = new FileNameList;
10017  Doxygen::inputNameList->setAutoDelete(TRUE);
10018  Doxygen::memberNameSDict = new MemberNameSDict(10000);
10019  Doxygen::memberNameSDict->setAutoDelete(TRUE);
10020  Doxygen::functionNameSDict = new MemberNameSDict(10000);
10021  Doxygen::functionNameSDict->setAutoDelete(TRUE);
10022  Doxygen::groupSDict = new GroupSDict(17);
10023  Doxygen::groupSDict->setAutoDelete(TRUE);
10024  Doxygen::namespaceSDict = new NamespaceSDict(20);
10025  Doxygen::namespaceSDict->setAutoDelete(TRUE);
10026  Doxygen::classSDict = new ClassSDict(1009);
10027  Doxygen::classSDict->setAutoDelete(TRUE);
10028  Doxygen::hiddenClasses = new ClassSDict(257);
10029  Doxygen::hiddenClasses->setAutoDelete(TRUE);
10030  Doxygen::directories = new DirSDict(17);
10031  Doxygen::directories->setAutoDelete(TRUE);
10032  Doxygen::pageSDict = new PageSDict(1009); // all doc pages
10033  Doxygen::pageSDict->setAutoDelete(TRUE);
10034  Doxygen::exampleSDict = new PageSDict(1009); // all examples
10035  Doxygen::exampleSDict->setAutoDelete(TRUE);
10036  Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
10037  Doxygen::tagDestinationDict.setAutoDelete(TRUE);
10039  Doxygen::citeDict = new CiteDict(257);
10040  Doxygen::genericsDict = new GenericsSDict;
10041  Doxygen::indexList = new IndexList;
10042  Doxygen::formulaList = new FormulaList;
10043  Doxygen::formulaDict = new FormulaDict(1009);
10044  Doxygen::formulaNameDict = new FormulaDict(1009);
10045  Doxygen::sectionDict = new SectionDict(257);
10046  Doxygen::sectionDict->setAutoDelete(TRUE);
10047 
10048  // initialisation of these globals depends on
10049  // configuration switches so we need to postpone these
10050  Doxygen::globalScope = 0;
10051  Doxygen::inputNameDict = 0;
10052  Doxygen::includeNameDict = 0;
10053  Doxygen::exampleNameDict = 0;
10054  Doxygen::imageNameDict = 0;
10055  Doxygen::dotFileNameDict = 0;
10056  Doxygen::mscFileNameDict = 0;
10057  Doxygen::diaFileNameDict = 0;
10058 
10059  /**************************************************************************
10060  * Initialize some global constants
10061  **************************************************************************/
10062 
10063  g_compoundKeywordDict.insert("template class",(void *)8);
10064  g_compoundKeywordDict.insert("template struct",(void *)8);
10065  g_compoundKeywordDict.insert("class",(void *)8);
10066  g_compoundKeywordDict.insert("struct",(void *)8);
10067  g_compoundKeywordDict.insert("union",(void *)8);
10068  g_compoundKeywordDict.insert("interface",(void *)8);
10069  g_compoundKeywordDict.insert("exception",(void *)8);
10070 
10071 }
10072 
10074 {
10075  delete Doxygen::sectionDict;
10076  delete Doxygen::formulaNameDict;
10077  delete Doxygen::formulaDict;
10078  delete Doxygen::formulaList;
10079  delete Doxygen::indexList;
10080  delete Doxygen::genericsDict;
10081  delete Doxygen::inputNameDict;
10082  delete Doxygen::includeNameDict;
10083  delete Doxygen::exampleNameDict;
10084  delete Doxygen::imageNameDict;
10085  delete Doxygen::dotFileNameDict;
10086  delete Doxygen::mscFileNameDict;
10087  delete Doxygen::diaFileNameDict;
10088  delete Doxygen::mainPage;
10089  delete Doxygen::pageSDict;
10090  delete Doxygen::exampleSDict;
10091  delete Doxygen::globalScope;
10092  delete Doxygen::xrefLists;
10093  delete Doxygen::parserManager;
10095  delete theTranslator;
10096  delete g_outputList;
10098  codeFreeScanner();
10099 
10100  if (Doxygen::symbolMap)
10101  {
10102  // iterate through Doxygen::symbolMap and delete all
10103  // DefinitionList objects, since they have no owner
10104  QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
10105  DefinitionIntf *di;
10106  for (dli.toFirst();(di=dli.current());)
10107  {
10109  {
10110  DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
10111  delete (DefinitionList *)tmp;
10112  }
10113  else
10114  {
10115  ++dli;
10116  }
10117  }
10118  }
10119 
10120  delete Doxygen::inputNameList;
10121  delete Doxygen::memberNameSDict;
10123  delete Doxygen::groupSDict;
10124  delete Doxygen::classSDict;
10125  delete Doxygen::hiddenClasses;
10126  delete Doxygen::namespaceSDict;
10127  delete Doxygen::directories;
10128 
10129  //delete Doxygen::symbolMap; <- we cannot do this unless all static lists
10130  // (such as Doxygen::namespaceSDict)
10131  // with objects based on Definition are made
10132  // dynamic first
10133 }
10134 
10135 static int computeIdealCacheParam(uint v)
10136 {
10137  //printf("computeIdealCacheParam(v=%u)\n",v);
10138 
10139  int r=0;
10140  while (v!=0) v>>=1,r++;
10141  // r = log2(v)
10142 
10143  // convert to a valid cache size value
10144  return QMAX(0,QMIN(r-16,9));
10145 }
10146 
10147 void readConfiguration(int argc, char **argv)
10148 {
10149  /**************************************************************************
10150  * Handle arguments *
10151  **************************************************************************/
10152 
10153  int optind=1;
10154  const char *configName=0;
10155  const char *layoutName=0;
10156  const char *debugLabel;
10157  const char *formatName;
10158  bool genConfig=FALSE;
10159  bool shortList=FALSE;
10160  bool updateConfig=FALSE;
10161  bool genLayout=FALSE;
10162  int retVal;
10163  while (optind<argc && argv[optind][0]=='-' &&
10164  (isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
10165  argv[optind][1]=='-')
10166  )
10167  {
10168  switch(argv[optind][1])
10169  {
10170  case 'g':
10171  genConfig=TRUE;
10172  configName=getArg(argc,argv,optind);
10173  if (optind+1<argc && qstrcmp(argv[optind+1],"-")==0)
10174  { configName="-"; optind++; }
10175  if (!configName)
10176  { configName="Doxyfile"; }
10177  break;
10178  case 'l':
10179  genLayout=TRUE;
10180  layoutName=getArg(argc,argv,optind);
10181  if (!layoutName)
10182  { layoutName="DoxygenLayout.xml"; }
10183  break;
10184  case 'd':
10185  debugLabel=getArg(argc,argv,optind);
10186  if (!debugLabel)
10187  {
10188  err("option \"-d\" is missing debug specifier.\n");
10189  devUsage();
10190  cleanUpDoxygen();
10191  exit(1);
10192  }
10193  retVal = Debug::setFlag(debugLabel);
10194  if (!retVal)
10195  {
10196  err("option \"-d\" has unknown debug specifier: \"%s\".\n",debugLabel);
10197  cleanUpDoxygen();
10198  exit(1);
10199  }
10200  break;
10201  case 's':
10202  shortList=TRUE;
10203  break;
10204  case 'u':
10205  updateConfig=TRUE;
10206  break;
10207  case 'e':
10208  formatName=getArg(argc,argv,optind);
10209  if (!formatName)
10210  {
10211  err("option \"-e\" is missing format specifier rtf.\n");
10212  cleanUpDoxygen();
10213  exit(1);
10214  }
10215  if (qstricmp(formatName,"rtf")==0)
10216  {
10217  if (optind+1>=argc)
10218  {
10219  err("option \"-e rtf\" is missing an extensions file name\n");
10220  cleanUpDoxygen();
10221  exit(1);
10222  }
10223  QFile f;
10224  if (openOutputFile(argv[optind+1],f))
10225  {
10227  }
10228  cleanUpDoxygen();
10229  exit(0);
10230  }
10231  err("option \"-e\" has invalid format specifier.\n");
10232  cleanUpDoxygen();
10233  exit(1);
10234  break;
10235  case 'w':
10236  formatName=getArg(argc,argv,optind);
10237  if (!formatName)
10238  {
10239  err("option \"-w\" is missing format specifier rtf, html or latex\n");
10240  cleanUpDoxygen();
10241  exit(1);
10242  }
10243  if (qstricmp(formatName,"rtf")==0)
10244  {
10245  if (optind+1>=argc)
10246  {
10247  err("option \"-w rtf\" is missing a style sheet file name\n");
10248  cleanUpDoxygen();
10249  exit(1);
10250  }
10251  QFile f;
10252  if (openOutputFile(argv[optind+1],f))
10253  {
10255  }
10256  cleanUpDoxygen();
10257  exit(1);
10258  }
10259  else if (qstricmp(formatName,"html")==0)
10260  {
10261  Config::init();
10262  if (optind+4<argc || QFileInfo("Doxyfile").exists())
10263  // explicit config file mentioned or default found on disk
10264  {
10265  QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10266  if (!Config::parse(df)) // parse the config file
10267  {
10268  err("error opening or reading configuration file %s!\n",argv[optind+4]);
10269  cleanUpDoxygen();
10270  exit(1);
10271  }
10272  }
10273  if (optind+3>=argc)
10274  {
10275  err("option \"-w html\" does not have enough arguments\n");
10276  cleanUpDoxygen();
10277  exit(1);
10278  }
10279  Config::postProcess(TRUE);
10281 
10282  QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10283  if (!setTranslator(outputLanguage))
10284  {
10285  warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10286  }
10287 
10288  QFile f;
10289  if (openOutputFile(argv[optind+1],f))
10290  {
10291  HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
10292  }
10293  f.close();
10294  if (openOutputFile(argv[optind+2],f))
10295  {
10297  }
10298  f.close();
10299  if (openOutputFile(argv[optind+3],f))
10300  {
10302  }
10303  cleanUpDoxygen();
10304  exit(0);
10305  }
10306  else if (qstricmp(formatName,"latex")==0)
10307  {
10308  Config::init();
10309  if (optind+4<argc || QFileInfo("Doxyfile").exists())
10310  {
10311  QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10312  if (!Config::parse(df))
10313  {
10314  err("error opening or reading configuration file %s!\n",argv[optind+4]);
10315  cleanUpDoxygen();
10316  exit(1);
10317  }
10318  }
10319  if (optind+3>=argc)
10320  {
10321  err("option \"-w latex\" does not have enough arguments\n");
10322  cleanUpDoxygen();
10323  exit(1);
10324  }
10325  Config::postProcess(TRUE);
10327 
10328  QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10329  if (!setTranslator(outputLanguage))
10330  {
10331  warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10332  }
10333 
10334  QFile f;
10335  if (openOutputFile(argv[optind+1],f))
10336  {
10338  }
10339  f.close();
10340  if (openOutputFile(argv[optind+2],f))
10341  {
10343  }
10344  f.close();
10345  if (openOutputFile(argv[optind+3],f))
10346  {
10348  }
10349  cleanUpDoxygen();
10350  exit(0);
10351  }
10352  else
10353  {
10354  err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",formatName);
10355  cleanUpDoxygen();
10356  exit(1);
10357  }
10358  break;
10359  case 'm':
10360  g_dumpSymbolMap = TRUE;
10361  break;
10362  case 'v':
10363  msg("%s\n",versionString);
10364  cleanUpDoxygen();
10365  exit(0);
10366  break;
10367  case '-':
10368  if (qstrcmp(&argv[optind][2],"help")==0)
10369  {
10370  usage(argv[0]);
10371  exit(0);
10372  }
10373  else if (qstrcmp(&argv[optind][2],"version")==0)
10374  {
10375  msg("%s\n",versionString);
10376  cleanUpDoxygen();
10377  exit(0);
10378  }
10379  else
10380  {
10381  err("Unknown option \"-%s\"\n",&argv[optind][1]);
10382  usage(argv[0]);
10383  exit(1);
10384  }
10385  break;
10386  case 'b':
10387  setvbuf(stdout,NULL,_IONBF,0);
10389  break;
10390  case 'T':
10391  msg("Warning: this option activates output generation via Django like template files. "
10392  "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
10393  "Only use if you are a doxygen developer\n");
10394  g_useOutputTemplate=TRUE;
10395  break;
10396  case 'h':
10397  case '?':
10398  usage(argv[0]);
10399  exit(0);
10400  break;
10401  default:
10402  err("Unknown option \"-%c\"\n",argv[optind][1]);
10403  usage(argv[0]);
10404  exit(1);
10405  }
10406  optind++;
10407  }
10408 
10409  /**************************************************************************
10410  * Parse or generate the config file *
10411  **************************************************************************/
10412 
10413  Config::init();
10414 
10415  if (genConfig && g_useOutputTemplate)
10416  {
10417  generateTemplateFiles("templates");
10418  cleanUpDoxygen();
10419  exit(0);
10420  }
10421 
10422  if (genConfig)
10423  {
10424  generateConfigFile(configName,shortList);
10425  cleanUpDoxygen();
10426  exit(0);
10427  }
10428  if (genLayout)
10429  {
10430  writeDefaultLayoutFile(layoutName);
10431  cleanUpDoxygen();
10432  exit(0);
10433  }
10434 
10435  QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
10436  if (optind>=argc)
10437  {
10438  if (configFileInfo1.exists())
10439  {
10440  configName="Doxyfile";
10441  }
10442  else if (configFileInfo2.exists())
10443  {
10444  configName="doxyfile";
10445  }
10446  else
10447  {
10448  err("Doxyfile not found and no input file specified!\n");
10449  usage(argv[0]);
10450  exit(1);
10451  }
10452  }
10453  else
10454  {
10455  QFileInfo fi(argv[optind]);
10456  if (fi.exists() || qstrcmp(argv[optind],"-")==0)
10457  {
10458  configName=argv[optind];
10459  }
10460  else
10461  {
10462  err("configuration file %s not found!\n",argv[optind]);
10463  usage(argv[0]);
10464  exit(1);
10465  }
10466  }
10467 
10468 
10469  if (!Config::parse(configName,updateConfig))
10470  {
10471  err("could not open or read configuration file %s!\n",configName);
10472  cleanUpDoxygen();
10473  exit(1);
10474  }
10475 
10476  if (updateConfig)
10477  {
10478  generateConfigFile(configName,shortList,TRUE);
10479  cleanUpDoxygen();
10480  exit(0);
10481  }
10482 
10483  /* Perlmod wants to know the path to the config file.*/
10484  QFileInfo configFileInfo(configName);
10485  setPerlModDoxyfile(configFileInfo.absFilePath().data());
10486 
10487 }
10488 
10491 {
10492 
10493  Config::postProcess(FALSE);
10496 }
10497 
10500 {
10501  Doxygen::globalScope = new NamespaceDef("<globalScope>",1,1,"<globalScope>");
10502  Doxygen::inputNameDict = new FileNameDict(10007);
10503  Doxygen::includeNameDict = new FileNameDict(10007);
10504  Doxygen::exampleNameDict = new FileNameDict(1009);
10505  Doxygen::exampleNameDict->setAutoDelete(TRUE);
10506  Doxygen::imageNameDict = new FileNameDict(257);
10507  Doxygen::imageNameDict->setAutoDelete(TRUE);
10508  Doxygen::dotFileNameDict = new FileNameDict(257);
10509  Doxygen::mscFileNameDict = new FileNameDict(257);
10510  Doxygen::diaFileNameDict = new FileNameDict(257);
10511 
10512  QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10513  if (!setTranslator(outputLanguage))
10514  {
10515  warn_uncond("Output language %s not supported! Using English instead.\n",
10516  outputLanguage.data());
10517  }
10518  QStrList &includePath = Config_getList(INCLUDE_PATH);
10519  char *s=includePath.first();
10520  while (s)
10521  {
10522  QFileInfo fi(s);
10523  addSearchDir(fi.absFilePath().utf8());
10524  s=includePath.next();
10525  }
10526 
10527  /* Set the global html file extension. */
10528  Doxygen::htmlFileExtension = Config_getString(HTML_FILE_EXTENSION);
10529 
10530 
10531  Doxygen::xrefLists->setAutoDelete(TRUE);
10532 
10534  Config_getBool(CALLER_GRAPH) ||
10535  Config_getBool(REFERENCES_RELATION) ||
10536  Config_getBool(REFERENCED_BY_RELATION);
10537 
10538  Doxygen::markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
10539 
10540  /**************************************************************************
10541  * Add custom extension mappings
10542  **************************************************************************/
10543 
10544  QStrList &extMaps = Config_getList(EXTENSION_MAPPING);
10545  char *mapping = extMaps.first();
10546  while (mapping)
10547  {
10548  QCString mapStr = mapping;
10549  int i;
10550  if ((i=mapStr.find('='))!=-1)
10551  {
10552  QCString ext=mapStr.left(i).stripWhiteSpace().lower();
10553  QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
10554  if (!updateLanguageMapping(ext,language))
10555  {
10556  err("Failed to map file extension '%s' to unsupported language '%s'.\n"
10557  "Check the EXTENSION_MAPPING setting in the config file.\n",
10558  ext.data(),language.data());
10559  }
10560  else
10561  {
10562  msg("Adding custom extension mapping: .%s will be treated as language %s\n",
10563  ext.data(),language.data());
10564  }
10565  }
10566  mapping = extMaps.next();
10567  }
10568 
10569 
10570  // add predefined macro name to a dictionary
10571  QStrList &expandAsDefinedList =Config_getList(EXPAND_AS_DEFINED);
10572  s=expandAsDefinedList.first();
10573  while (s)
10574  {
10575  if (Doxygen::expandAsDefinedDict[s]==0)
10576  {
10577  Doxygen::expandAsDefinedDict.insert(s,(void *)666);
10578  }
10579  s=expandAsDefinedList.next();
10580  }
10581 
10582  // read aliases and store them in a dictionary
10583  readAliases();
10584 
10585  // store number of spaces in a tab into Doxygen::spaces
10586  int &tabSize = Config_getInt(TAB_SIZE);
10587  Doxygen::spaces.resize(tabSize+1);
10588  int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
10589  Doxygen::spaces.at(tabSize)='\0';
10590 }
10591 
10592 #ifdef HAS_SIGNALS
10593 static void stopDoxygen(int)
10594 {
10595  QDir thisDir;
10596  msg("Cleaning up...\n");
10597  if (!Doxygen::entryDBFileName.isEmpty())
10598  {
10599  thisDir.remove(Doxygen::entryDBFileName);
10600  }
10601  if (!Doxygen::objDBFileName.isEmpty())
10602  {
10603  thisDir.remove(Doxygen::objDBFileName);
10604  }
10605  killpg(0,SIGINT);
10606  exit(1);
10607 }
10608 #endif
10609 
10610 static void writeTagFile()
10611 {
10612  QCString &generateTagFile = Config_getString(GENERATE_TAGFILE);
10613  if (generateTagFile.isEmpty()) return;
10614 
10615  QFile tag(generateTagFile);
10616  if (!tag.open(IO_WriteOnly))
10617  {
10618  err("cannot open tag file %s for writing\n",
10619  generateTagFile.data()
10620  );
10621  return;
10622  }
10623  FTextStream tagFile(&tag);
10624  tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
10625  tagFile << "<tagfile>" << endl;
10626 
10627  // for each file
10628  FileNameListIterator fnli(*Doxygen::inputNameList);
10629  FileName *fn;
10630  for (fnli.toFirst();(fn=fnli.current());++fnli)
10631  {
10632  FileNameIterator fni(*fn);
10633  FileDef *fd;
10634  for (fni.toFirst();(fd=fni.current());++fni)
10635  {
10636  if (fd->isLinkableInProject()) fd->writeTagFile(tagFile);
10637  }
10638  }
10639  // for each class
10640  ClassSDict::Iterator cli(*Doxygen::classSDict);
10641  ClassDef *cd;
10642  for ( ; (cd=cli.current()) ; ++cli )
10643  {
10644  if (cd->isLinkableInProject()) cd->writeTagFile(tagFile);
10645  }
10646  // for each namespace
10647  NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
10648  NamespaceDef *nd;
10649  for ( ; (nd=nli.current()) ; ++nli )
10650  {
10651  if (nd->isLinkableInProject()) nd->writeTagFile(tagFile);
10652  }
10653  // for each group
10654  GroupSDict::Iterator gli(*Doxygen::groupSDict);
10655  GroupDef *gd;
10656  for (gli.toFirst();(gd=gli.current());++gli)
10657  {
10658  if (gd->isLinkableInProject()) gd->writeTagFile(tagFile);
10659  }
10660  // for each page
10661  PageSDict::Iterator pdi(*Doxygen::pageSDict);
10662  PageDef *pd=0;
10663  for (pdi.toFirst();(pd=pdi.current());++pdi)
10664  {
10665  if (pd->isLinkableInProject()) pd->writeTagFile(tagFile);
10666  }
10667  if (Doxygen::mainPage) Doxygen::mainPage->writeTagFile(tagFile);
10668 
10669  /*
10670  if (Doxygen::mainPage && !Config_getString(GENERATE_TAGFILE).isEmpty())
10671  {
10672  tagFile << " <compound kind=\"page\">" << endl
10673  << " <name>"
10674  << convertToXML(Doxygen::mainPage->name())
10675  << "</name>" << endl
10676  << " <title>"
10677  << convertToXML(Doxygen::mainPage->title())
10678  << "</title>" << endl
10679  << " <filename>"
10680  << convertToXML(Doxygen::mainPage->getOutputFileBase())
10681  << "</filename>" << endl;
10682 
10683  mainPage->writeDocAnchorsToTagFile();
10684  tagFile << " </compound>" << endl;
10685  }
10686  */
10687 
10688  tagFile << "</tagfile>" << endl;
10689 }
10690 
10691 static void exitDoxygen()
10692 {
10693  if (!g_successfulRun) // premature exit
10694  {
10695  QDir thisDir;
10696  msg("Exiting...\n");
10697  if (!Doxygen::entryDBFileName.isEmpty())
10698  {
10699  thisDir.remove(Doxygen::entryDBFileName);
10700  }
10701  if (!Doxygen::objDBFileName.isEmpty())
10702  {
10703  thisDir.remove(Doxygen::objDBFileName);
10704  }
10705  }
10706 }
10707 
10708 static QCString createOutputDirectory(const QCString &baseDirName,
10709  QCString &formatDirName,
10710  const char *defaultDirName)
10711 {
10712  // Note the & on the next line, we modify the formatDirOption!
10713  if (formatDirName.isEmpty())
10714  {
10715  formatDirName = baseDirName + defaultDirName;
10716  }
10717  else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
10718  {
10719  formatDirName.prepend(baseDirName+'/');
10720  }
10721  QDir formatDir(formatDirName);
10722  if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
10723  {
10724  err("Could not create output directory %s\n", formatDirName.data());
10725  cleanUpDoxygen();
10726  exit(1);
10727  }
10728  return formatDirName;
10729 }
10730 
10731 static QCString getQchFileName()
10732 {
10733  QCString const & qchFile = Config_getString(QCH_FILE);
10734  if (!qchFile.isEmpty())
10735  {
10736  return qchFile;
10737  }
10738 
10739  QCString const & projectName = Config_getString(PROJECT_NAME);
10740  QCString const & versionText = Config_getString(PROJECT_NUMBER);
10741 
10742  return QCString("../qch/")
10743  + (projectName.isEmpty() ? QCString("index") : projectName)
10744  + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
10745  + QCString(".qch");
10746 }
10747 
10749 {
10750  QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
10751  bool alwaysRecursive = Config_getBool(RECURSIVE);
10752  StringDict excludeNameDict(1009);
10753  excludeNameDict.setAutoDelete(TRUE);
10754 
10755  // gather names of all files in the include path
10756  g_s.begin("Searching for include files...\n");
10757  QStrList &includePathList = Config_getList(INCLUDE_PATH);
10758  char *s=includePathList.first();
10759  while (s)
10760  {
10761  QStrList &pl = Config_getList(INCLUDE_FILE_PATTERNS);
10762  if (pl.count()==0)
10763  {
10764  pl = Config_getList(FILE_PATTERNS);
10765  }
10766  readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
10767  &exclPatterns,0,0,
10768  alwaysRecursive);
10769  s=includePathList.next();
10770  }
10771  g_s.end();
10772 
10773  g_s.begin("Searching for example files...\n");
10774  QStrList &examplePathList = Config_getList(EXAMPLE_PATH);
10775  s=examplePathList.first();
10776  while (s)
10777  {
10778  readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
10779  &Config_getList(EXAMPLE_PATTERNS),
10780  0,0,0,
10781  (alwaysRecursive || Config_getBool(EXAMPLE_RECURSIVE)));
10782  s=examplePathList.next();
10783  }
10784  g_s.end();
10785 
10786  g_s.begin("Searching for images...\n");
10787  QStrList &imagePathList=Config_getList(IMAGE_PATH);
10788  s=imagePathList.first();
10789  while (s)
10790  {
10791  readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
10792  0,0,0,
10793  alwaysRecursive);
10794  s=imagePathList.next();
10795  }
10796  g_s.end();
10797 
10798  g_s.begin("Searching for dot files...\n");
10799  QStrList &dotFileList=Config_getList(DOTFILE_DIRS);
10800  s=dotFileList.first();
10801  while (s)
10802  {
10803  readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
10804  0,0,0,
10805  alwaysRecursive);
10806  s=dotFileList.next();
10807  }
10808  g_s.end();
10809 
10810  g_s.begin("Searching for msc files...\n");
10811  QStrList &mscFileList=Config_getList(MSCFILE_DIRS);
10812  s=mscFileList.first();
10813  while (s)
10814  {
10815  readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
10816  0,0,0,
10817  alwaysRecursive);
10818  s=mscFileList.next();
10819  }
10820  g_s.end();
10821 
10822  g_s.begin("Searching for dia files...\n");
10823  QStrList &diaFileList=Config_getList(DIAFILE_DIRS);
10824  s=diaFileList.first();
10825  while (s)
10826  {
10827  readFileOrDirectory(s,0,Doxygen::diaFileNameDict,0,0,
10828  0,0,0,
10829  alwaysRecursive);
10830  s=diaFileList.next();
10831  }
10832  g_s.end();
10833 
10834  g_s.begin("Searching for files to exclude\n");
10835  QStrList &excludeList = Config_getList(EXCLUDE);
10836  s=excludeList.first();
10837  while (s)
10838  {
10839  readFileOrDirectory(s,0,0,0,&Config_getList(FILE_PATTERNS),
10840  0,0,&excludeNameDict,
10841  alwaysRecursive,
10842  FALSE);
10843  s=excludeList.next();
10844  }
10845  g_s.end();
10846 
10847  /**************************************************************************
10848  * Determine Input Files *
10849  **************************************************************************/
10850 
10851  g_s.begin("Searching INPUT for files to process...\n");
10852  QDict<void> *killDict = new QDict<void>(10007);
10853  QStrList &inputList=Config_getList(INPUT);
10854  g_inputFiles.setAutoDelete(TRUE);
10855  s=inputList.first();
10856  while (s)
10857  {
10858  QCString path=s;
10859  uint l = path.length();
10860  if (l>0)
10861  {
10862  // strip trailing slashes
10863  if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
10864 
10866  path,
10867  Doxygen::inputNameList,
10868  Doxygen::inputNameDict,
10869  &excludeNameDict,
10870  &Config_getList(FILE_PATTERNS),
10871  &exclPatterns,
10872  &g_inputFiles,0,
10873  alwaysRecursive,
10874  TRUE,
10875  killDict,
10877  }
10878  s=inputList.next();
10879  }
10880  delete killDict;
10881  g_s.end();
10882 }
10883 
10884 
10886 {
10887  atexit(exitDoxygen);
10888 
10889 
10890  /**************************************************************************
10891  * Make sure the output directory exists
10892  **************************************************************************/
10893  QCString &outputDirectory = Config_getString(OUTPUT_DIRECTORY);
10894  if (outputDirectory.isEmpty())
10895  {
10896  outputDirectory=QDir::currentDirPath().utf8();
10897  }
10898  else
10899  {
10900  QDir dir(outputDirectory);
10901  if (!dir.exists())
10902  {
10903  dir.setPath(QDir::currentDirPath());
10904  if (!dir.mkdir(outputDirectory))
10905  {
10906  err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
10907  "exist and cannot be created\n",outputDirectory.data());
10908  cleanUpDoxygen();
10909  exit(1);
10910  }
10911  else
10912  {
10913  msg("Notice: Output directory `%s' does not exist. "
10914  "I have created it for you.\n", outputDirectory.data());
10915  }
10916  dir.cd(outputDirectory);
10917  }
10918  outputDirectory=dir.absPath().utf8();
10919  }
10920 
10921  /**************************************************************************
10922  * Initialize global lists and dictionaries
10923  **************************************************************************/
10924 
10925  Doxygen::symbolStorage = new Store;
10926 
10927  // also scale lookup cache with SYMBOL_CACHE_SIZE
10928  int cacheSize = Config_getInt(LOOKUP_CACHE_SIZE);
10929  if (cacheSize<0) cacheSize=0;
10930  if (cacheSize>9) cacheSize=9;
10931  uint lookupSize = 65536 << cacheSize;
10932  Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
10933  Doxygen::lookupCache->setAutoDelete(TRUE);
10934 
10935 #ifdef HAS_SIGNALS
10936  signal(SIGINT, stopDoxygen);
10937 #endif
10938 
10939  uint pid = portable_pid();
10940  Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10941  Doxygen::objDBFileName.prepend(outputDirectory+"/");
10942  Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10943  Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10944 
10945  if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10946  {
10947  err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10948  exit(1);
10949  }
10950 
10951 
10952 
10953  /**************************************************************************
10954  * Check/create output directorties *
10955  **************************************************************************/
10956 
10957  QCString htmlOutput;
10958  bool &generateHtml = Config_getBool(GENERATE_HTML);
10959  if (generateHtml || g_useOutputTemplate /* TODO: temp hack */)
10960  htmlOutput = createOutputDirectory(outputDirectory,Config_getString(HTML_OUTPUT),"/html");
10961 
10962  QCString docbookOutput;
10963  bool &generateDocbook = Config_getBool(GENERATE_DOCBOOK);
10964  if (generateDocbook)
10965  docbookOutput = createOutputDirectory(outputDirectory,Config_getString(DOCBOOK_OUTPUT),"/docbook");
10966 
10967  QCString xmlOutput;
10968  bool &generateXml = Config_getBool(GENERATE_XML);
10969  if (generateXml)
10970  xmlOutput = createOutputDirectory(outputDirectory,Config_getString(XML_OUTPUT),"/xml");
10971 
10972  QCString latexOutput;
10973  bool &generateLatex = Config_getBool(GENERATE_LATEX);
10974  if (generateLatex)
10975  latexOutput = createOutputDirectory(outputDirectory,Config_getString(LATEX_OUTPUT),"/latex");
10976 
10977  QCString rtfOutput;
10978  bool &generateRtf = Config_getBool(GENERATE_RTF);
10979  if (generateRtf)
10980  rtfOutput = createOutputDirectory(outputDirectory,Config_getString(RTF_OUTPUT),"/rtf");
10981 
10982  QCString manOutput;
10983  bool &generateMan = Config_getBool(GENERATE_MAN);
10984  if (generateMan)
10985  manOutput = createOutputDirectory(outputDirectory,Config_getString(MAN_OUTPUT),"/man");
10986 
10987  //QCString sqlOutput;
10988  //bool &generateSql = Config_getBool(GENERATE_SQLITE3);
10989  //if (generateSql)
10990  // sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3");
10991 
10992  if (Config_getBool(HAVE_DOT))
10993  {
10994  QCString curFontPath = Config_getString(DOT_FONTPATH);
10995  if (curFontPath.isEmpty())
10996  {
10997  portable_getenv("DOTFONTPATH");
10998  QCString newFontPath = ".";
10999  if (!curFontPath.isEmpty())
11000  {
11001  newFontPath+=portable_pathListSeparator();
11002  newFontPath+=curFontPath;
11003  }
11004  portable_setenv("DOTFONTPATH",newFontPath);
11005  }
11006  else
11007  {
11008  portable_setenv("DOTFONTPATH",curFontPath);
11009  }
11010  }
11011 
11012 
11013 
11014  /**************************************************************************
11015  * Handle layout file *
11016  **************************************************************************/
11017 
11019  QCString &layoutFileName = Config_getString(LAYOUT_FILE);
11020  bool defaultLayoutUsed = FALSE;
11021  if (layoutFileName.isEmpty())
11022  {
11023  layoutFileName = "DoxygenLayout.xml";
11024  defaultLayoutUsed = TRUE;
11025  }
11026 
11027  QFile layoutFile(layoutFileName);
11028  if (layoutFile.open(IO_ReadOnly))
11029  {
11030  msg("Parsing layout file %s...\n",layoutFileName.data());
11031  QTextStream t(&layoutFile);
11032  t.setEncoding(QTextStream::Latin1);
11033  LayoutDocManager::instance().parse(t,layoutFileName);
11034  }
11035  else if (!defaultLayoutUsed)
11036  {
11037  warn_uncond("failed to open layout file '%s' for reading!\n",layoutFileName.data());
11038  }
11039 
11040  /**************************************************************************
11041  * Read and preprocess input *
11042  **************************************************************************/
11043 
11044  // prevent search in the output directories
11045  QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
11046  if (generateHtml) exclPatterns.append(htmlOutput);
11047  if (generateDocbook) exclPatterns.append(docbookOutput);
11048  if (generateXml) exclPatterns.append(xmlOutput);
11049  if (generateLatex) exclPatterns.append(latexOutput);
11050  if (generateRtf) exclPatterns.append(rtfOutput);
11051  if (generateMan) exclPatterns.append(manOutput);
11052 
11053  searchInputFiles();
11054 
11055  // Notice: the order of the function calls below is very important!
11056 
11057  if (Config_getBool(GENERATE_HTML))
11058  {
11060  }
11061 
11062  /**************************************************************************
11063  * Handle Tag Files *
11064  **************************************************************************/
11065 
11066  g_storage = new FileStorage;
11067  g_storage->setName(Doxygen::entryDBFileName);
11068  if (!g_storage->open(IO_WriteOnly))
11069  {
11070  err("Failed to create temporary storage file %s\n",
11071  Doxygen::entryDBFileName.data());
11072  exit(1);
11073  }
11074  Entry *root=new Entry;
11075  EntryNav *rootNav = new EntryNav(0,root);
11076  rootNav->setEntry(root);
11077  msg("Reading and parsing tag files\n");
11078 
11079  QStrList &tagFileList = Config_getList(TAGFILES);
11080  char *s=tagFileList.first();
11081  while (s)
11082  {
11083  readTagFile(root,s);
11084  root->createNavigationIndex(rootNav,g_storage,0);
11085  s=tagFileList.next();
11086  }
11087 
11088  /**************************************************************************
11089  * Parse source files *
11090  **************************************************************************/
11091 
11092  if (Config_getBool(BUILTIN_STL_SUPPORT))
11093  {
11094  addSTLClasses(rootNav);
11095  }
11096 
11097  g_s.begin("Parsing files\n");
11098  parseFiles(root,rootNav);
11099  g_storage->close();
11100  g_s.end();
11101 
11102  // we are done with input scanning now, so free up the buffers used by flex
11103  // (can be around 4MB)
11104  preFreeScanner();
11105  scanFreeScanner();
11107 
11108  if (!g_storage->open(IO_ReadOnly))
11109  {
11110  err("Failed to open temporary storage file %s for reading",
11111  Doxygen::entryDBFileName.data());
11112  exit(1);
11113  }
11114 
11115  /**************************************************************************
11116  * Gather information *
11117  **************************************************************************/
11118 
11119  g_s.begin("Building group list...\n");
11120  buildGroupList(rootNav);
11121  organizeSubGroups(rootNav);
11122  g_s.end();
11123 
11124  g_s.begin("Building directory list...\n");
11125  buildDirectories();
11126  findDirDocumentation(rootNav);
11127  g_s.end();
11128 
11129  g_s.begin("Building namespace list...\n");
11130  buildNamespaceList(rootNav);
11131  findUsingDirectives(rootNav);
11132  g_s.end();
11133 
11134  g_s.begin("Building file list...\n");
11135  buildFileList(rootNav);
11136  g_s.end();
11137  //generateFileTree();
11138 
11139  g_s.begin("Building class list...\n");
11140  buildClassList(rootNav);
11141  g_s.end();
11142 
11143  g_s.begin("Associating documentation with classes...\n");
11144  buildClassDocList(rootNav);
11145 
11146  // build list of using declarations here (global list)
11147  buildListOfUsingDecls(rootNav);
11148  g_s.end();
11149 
11150  g_s.begin("Computing nesting relations for classes...\n");
11152  g_s.end();
11153  // 1.8.2-20121111: no longer add nested classes to the group as well
11154  //distributeClassGroupRelations();
11155 
11156  // calling buildClassList may result in cached relations that
11157  // become invalid after resolveClassNestingRelations(), that's why
11158  // we need to clear the cache here
11159  Doxygen::lookupCache->clear();
11160  // we don't need the list of using declaration anymore
11161  g_usingDeclarations.clear();
11162 
11163  g_s.begin("Building example list...\n");
11164  buildExampleList(rootNav);
11165  g_s.end();
11166 
11167  g_s.begin("Searching for enumerations...\n");
11168  findEnums(rootNav);
11169  g_s.end();
11170 
11171  // Since buildVarList calls isVarWithConstructor
11172  // and this calls getResolvedClass we need to process
11173  // typedefs first so the relations between classes via typedefs
11174  // are properly resolved. See bug 536385 for an example.
11175  g_s.begin("Searching for documented typedefs...\n");
11176  buildTypedefList(rootNav);
11177  g_s.end();
11178 
11179  g_s.begin("Searching for members imported via using declarations...\n");
11180  findUsingDeclImports(rootNav);
11181  // this should be after buildTypedefList in order to properly import
11182  // used typedefs
11183  findUsingDeclarations(rootNav);
11184  g_s.end();
11185 
11186  g_s.begin("Searching for included using directives...\n");
11188  g_s.end();
11189 
11190  g_s.begin("Searching for documented variables...\n");
11191  buildVarList(rootNav);
11192  g_s.end();
11193 
11194  g_s.begin("Building interface member list...\n");
11195  buildInterfaceAndServiceList(rootNav); // UNO IDL
11196 
11197  g_s.begin("Building member list...\n"); // using class info only !
11198  buildFunctionList(rootNav);
11199  g_s.end();
11200 
11201  g_s.begin("Searching for friends...\n");
11202  findFriends();
11203  g_s.end();
11204 
11205  g_s.begin("Searching for documented defines...\n");
11206  findDefineDocumentation(rootNav);
11207  g_s.end();
11208 
11209  g_s.begin("Computing class inheritance relations...\n");
11210  findClassEntries(rootNav);
11212  g_s.end();
11213 
11214  g_s.begin("Computing class usage relations...\n");
11216  g_s.end();
11217 
11218  if (Config_getBool(INLINE_SIMPLE_STRUCTS))
11219  {
11220  g_s.begin("Searching for tag less structs...\n");
11222  g_s.end();
11223  }
11224 
11225  g_s.begin("Flushing cached template relations that have become invalid...\n");
11227  g_s.end();
11228 
11229  g_s.begin("Computing class relations...\n");
11232  if (Config_getBool(OPTIMIZE_OUTPUT_VHDL))
11233  {
11235  }
11237  g_classEntries.clear();
11238  g_s.end();
11239 
11240  g_s.begin("Add enum values to enums...\n");
11241  addEnumValuesToEnums(rootNav);
11242  findEnumDocumentation(rootNav);
11243  g_s.end();
11244 
11245  g_s.begin("Searching for member function documentation...\n");
11246  findObjCMethodDefinitions(rootNav);
11247  findMemberDocumentation(rootNav); // may introduce new members !
11248 
11251  g_s.end();
11252 
11253  // moved to after finding and copying documentation,
11254  // as this introduces new members see bug 722654
11255  g_s.begin("Creating members for template instances...\n");
11257  g_s.end();
11258 
11259  g_s.begin("Building page list...\n");
11260  buildPageList(rootNav);
11261  g_s.end();
11262 
11263  g_s.begin("Search for main page...\n");
11264  findMainPage(rootNav);
11265  findMainPageTagFiles(rootNav);
11266  g_s.end();
11267 
11268  g_s.begin("Computing page relations...\n");
11269  computePageRelations(rootNav);
11271  g_s.end();
11272 
11273  g_s.begin("Determining the scope of groups...\n");
11274  findGroupScope(rootNav);
11275  g_s.end();
11276 
11277  g_s.begin("Sorting lists...\n");
11278  Doxygen::memberNameSDict->sort();
11279  Doxygen::functionNameSDict->sort();
11280  Doxygen::hiddenClasses->sort();
11281  Doxygen::classSDict->sort();
11282  g_s.end();
11283 
11284  msg("Freeing entry tree\n");
11285  delete rootNav;
11286  g_storage->close();
11287  delete g_storage;
11288  g_storage=0;
11289 
11290  QDir thisDir;
11291  thisDir.remove(Doxygen::entryDBFileName);
11292 
11293  g_s.begin("Determining which enums are documented\n");
11295  g_s.end();
11296 
11297  g_s.begin("Computing member relations...\n");
11298  mergeCategories();
11300  g_s.end();
11301 
11302  g_s.begin("Building full member lists recursively...\n");
11304  g_s.end();
11305 
11306  g_s.begin("Adding members to member groups.\n");
11308  g_s.end();
11309 
11310  if (Config_getBool(DISTRIBUTE_GROUP_DOC))
11311  {
11312  g_s.begin("Distributing member group documentation.\n");
11314  g_s.end();
11315  }
11316 
11317  g_s.begin("Computing member references...\n");
11319  g_s.end();
11320 
11321  if (Config_getBool(INHERIT_DOCS))
11322  {
11323  g_s.begin("Inheriting documentation...\n");
11325  g_s.end();
11326  }
11327 
11328  // compute the shortest possible names of all files
11329  // without losing the uniqueness of the file names.
11330  g_s.begin("Generating disk names...\n");
11331  Doxygen::inputNameList->generateDiskNames();
11332  g_s.end();
11333 
11334  g_s.begin("Adding source references...\n");
11336  g_s.end();
11337 
11338  g_s.begin("Adding xrefitems...\n");
11341  g_s.end();
11342 
11343  g_s.begin("Sorting member lists...\n");
11344  sortMemberLists();
11345  g_s.end();
11346 
11347  if (Config_getBool(DIRECTORY_GRAPH))
11348  {
11349  g_s.begin("Computing dependencies between directories...\n");
11351  g_s.end();
11352  }
11353 
11354  //g_s.begin("Resolving citations...\n");
11355  //Doxygen::citeDict->resolve();
11356 
11357  g_s.begin("Generating citations page...\n");
11358  Doxygen::citeDict->generatePage();
11359  g_s.end();
11360 
11361  g_s.begin("Counting data structures...\n");
11363  g_s.end();
11364 
11365  g_s.begin("Resolving user defined references...\n");
11367  g_s.end();
11368 
11369  g_s.begin("Finding anchors and sections in the documentation...\n");
11371  g_s.end();
11372 
11373  g_s.begin("Transferring function references...\n");
11375  g_s.end();
11376 
11377  g_s.begin("Combining using relations...\n");
11379  g_s.end();
11380 
11381  g_s.begin("Adding members to index pages...\n");
11383  g_s.end();
11384 }
11385 
11387 {
11388  /**************************************************************************
11389  * Initialize output generators *
11390  **************************************************************************/
11391 
11394 
11396  if (g_dumpSymbolMap)
11397  {
11398  dumpSymbolMap();
11399  exit(0);
11400  }
11401 
11403 
11404  bool generateHtml = Config_getBool(GENERATE_HTML);
11405  bool generateLatex = Config_getBool(GENERATE_LATEX);
11406  bool generateMan = Config_getBool(GENERATE_MAN);
11407  bool generateRtf = Config_getBool(GENERATE_RTF);
11408 
11409 
11410  g_outputList = new OutputList(TRUE);
11411  if (generateHtml)
11412  {
11413  g_outputList->add(new HtmlGenerator);
11415 
11416  // add HTML indexers that are enabled
11417  bool generateHtmlHelp = Config_getBool(GENERATE_HTMLHELP);
11418  bool generateEclipseHelp = Config_getBool(GENERATE_ECLIPSEHELP);
11419  bool generateQhp = Config_getBool(GENERATE_QHP);
11420  bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
11421  bool generateDocSet = Config_getBool(GENERATE_DOCSET);
11422  if (generateEclipseHelp) Doxygen::indexList->addIndex(new EclipseHelp);
11423  if (generateHtmlHelp) Doxygen::indexList->addIndex(new HtmlHelp);
11424  if (generateQhp) Doxygen::indexList->addIndex(new Qhp);
11425  if (generateTreeView) Doxygen::indexList->addIndex(new FTVHelp(TRUE));
11426  if (generateDocSet) Doxygen::indexList->addIndex(new DocSets);
11427  Doxygen::indexList->initialize();
11429  }
11430  if (generateLatex)
11431  {
11432  g_outputList->add(new LatexGenerator);
11434  }
11435  if (generateMan)
11436  {
11437  g_outputList->add(new ManGenerator);
11439  }
11440  if (generateRtf)
11441  {
11442  g_outputList->add(new RTFGenerator);
11444  }
11445  if (Config_getBool(USE_HTAGS))
11446  {
11447  Htags::useHtags = TRUE;
11448  QCString htmldir = Config_getString(HTML_OUTPUT);
11449  if (!Htags::execute(htmldir))
11450  err("USE_HTAGS is YES but htags(1) failed. \n");
11451  if (!Htags::loadFilemap(htmldir))
11452  err("htags(1) ended normally but failed to load the filemap. \n");
11453  }
11454 
11455  /**************************************************************************
11456  * Generate documentation *
11457  **************************************************************************/
11458 
11459  if (generateHtml) writeDoxFont(Config_getString(HTML_OUTPUT));
11460  if (generateLatex) writeDoxFont(Config_getString(LATEX_OUTPUT));
11461  if (generateRtf) writeDoxFont(Config_getString(RTF_OUTPUT));
11462 
11463  g_s.begin("Generating style sheet...\n");
11464  //printf("writing style info\n");
11465  g_outputList->writeStyleInfo(0); // write first part
11466  g_s.end();
11467 
11468  static bool searchEngine = Config_getBool(SEARCHENGINE);
11469  static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
11470 
11471  g_s.begin("Generating search indices...\n");
11472  if (searchEngine && !serverBasedSearch && (generateHtml || g_useOutputTemplate))
11473  {
11475  }
11476 
11477  // generate search indices (need to do this before writing other HTML
11478  // pages as these contain a drop down menu with options depending on
11479  // what categories we find in this function.
11480  if (generateHtml && searchEngine)
11481  {
11482  QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search";
11483  QDir searchDir(searchDirName);
11484  if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
11485  {
11486  err("Could not create search results directory '%s' $PWD='%s'\n",
11487  searchDirName.data(),QDir::currentDirPath().data());
11488  exit(1);
11489  }
11490  HtmlGenerator::writeSearchData(searchDirName);
11491  if (!serverBasedSearch) // client side search index
11492  {
11494  }
11495  }
11496  g_s.end();
11497 
11498  g_s.begin("Generating example documentation...\n");
11500  g_s.end();
11501 
11502  if (!Htags::useHtags)
11503  {
11504  g_s.begin("Generating file sources...\n");
11506  g_s.end();
11507  }
11508 
11509  g_s.begin("Generating file documentation...\n");
11510  generateFileDocs();
11511  g_s.end();
11512 
11513  g_s.begin("Generating page documentation...\n");
11514  generatePageDocs();
11515  g_s.end();
11516 
11517  g_s.begin("Generating group documentation...\n");
11519  g_s.end();
11520 
11521  g_s.begin("Generating class documentation...\n");
11523  g_s.end();
11524 
11525  g_s.begin("Generating namespace index...\n");
11527  g_s.end();
11528 
11529  if (Config_getBool(GENERATE_LEGEND))
11530  {
11531  g_s.begin("Generating graph info page...\n");
11532  writeGraphInfo(*g_outputList);
11533  g_s.end();
11534  }
11535 
11536  g_s.begin("Generating directory documentation...\n");
11537  generateDirDocs(*g_outputList);
11538  g_s.end();
11539 
11540  if (Doxygen::formulaList->count()>0 && generateHtml
11541  && !Config_getBool(USE_MATHJAX))
11542  {
11543  g_s.begin("Generating bitmaps for formulas in HTML...\n");
11544  Doxygen::formulaList->generateBitmaps(Config_getString(HTML_OUTPUT));
11545  g_s.end();
11546  }
11547 
11548  if (Config_getBool(SORT_GROUP_NAMES))
11549  {
11550  Doxygen::groupSDict->sort();
11551  GroupSDict::Iterator gli(*Doxygen::groupSDict);
11552  GroupDef *gd;
11553  for (gli.toFirst();(gd=gli.current());++gli)
11554  {
11555  gd->sortSubGroups();
11556  }
11557  }
11558 
11559  if (g_outputList->count()>0)
11560  {
11561  writeIndexHierarchy(*g_outputList);
11562  }
11563 
11564  g_s.begin("finalizing index lists...\n");
11565  Doxygen::indexList->finalize();
11566  g_s.end();
11567 
11568  g_s.begin("writing tag file...\n");
11569  writeTagFile();
11570  g_s.end();
11571 
11572  if (Config_getBool(DOT_CLEANUP))
11573  {
11574  if (generateHtml)
11575  removeDoxFont(Config_getString(HTML_OUTPUT));
11576  if (generateRtf)
11577  removeDoxFont(Config_getString(RTF_OUTPUT));
11578  if (generateLatex)
11579  removeDoxFont(Config_getString(LATEX_OUTPUT));
11580  }
11581 
11582  if (Config_getBool(GENERATE_XML))
11583  {
11584  g_s.begin("Generating XML output...\n");
11586  generateXML();
11588  g_s.end();
11589  }
11590  if (USE_SQLITE3)
11591  {
11592  g_s.begin("Generating SQLITE3 output...\n");
11593  generateSqlite3();
11594  g_s.end();
11595  }
11596 
11597  if (Config_getBool(GENERATE_DOCBOOK))
11598  {
11599  g_s.begin("Generating Docbook output...\n");
11600  generateDocbook();
11601  g_s.end();
11602  }
11603 
11604  if (Config_getBool(GENERATE_AUTOGEN_DEF))
11605  {
11606  g_s.begin("Generating AutoGen DEF output...\n");
11607  generateDEF();
11608  g_s.end();
11609  }
11610  if (Config_getBool(GENERATE_PERLMOD))
11611  {
11612  g_s.begin("Generating Perl module output...\n");
11613  generatePerlMod();
11614  g_s.end();
11615  }
11616  if (generateHtml && searchEngine && serverBasedSearch)
11617  {
11618  g_s.begin("Generating search index\n");
11619  if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
11620  {
11622  Doxygen::searchIndex->write(Config_getString(HTML_OUTPUT)+"/search/search.idx");
11623  }
11624  else // write data for external search index
11625  {
11627  QCString searchDataFile = Config_getString(SEARCHDATA_FILE);
11628  if (searchDataFile.isEmpty())
11629  {
11630  searchDataFile="searchdata.xml";
11631  }
11632  if (!portable_isAbsolutePath(searchDataFile))
11633  {
11634  searchDataFile.prepend(Config_getString(OUTPUT_DIRECTORY)+"/");
11635  }
11636  Doxygen::searchIndex->write(searchDataFile);
11637  }
11638  g_s.end();
11639  }
11640 
11642 
11643  if (generateRtf)
11644  {
11645  g_s.begin("Combining RTF output...\n");
11646  if (!RTFGenerator::preProcessFileInplace(Config_getString(RTF_OUTPUT),"refman.rtf"))
11647  {
11648  err("An error occurred during post-processing the RTF files!\n");
11649  }
11650  g_s.end();
11651  }
11652 
11653  if (Config_getBool(HAVE_DOT))
11654  {
11655  g_s.begin("Running dot...\n");
11657  g_s.end();
11658  }
11659 
11660  // copy static stuff
11661  if (generateHtml)
11662  {
11664  copyStyleSheet();
11665  copyLogo(Config_getString(HTML_OUTPUT));
11666  copyExtraFiles(Config_getList(HTML_EXTRA_FILES),"HTML_EXTRA_FILES",Config_getString(HTML_OUTPUT));
11667  }
11668  if (generateLatex)
11669  {
11671  copyLogo(Config_getString(LATEX_OUTPUT));
11672  copyExtraFiles(Config_getList(LATEX_EXTRA_FILES),"LATEX_EXTRA_FILES",Config_getString(LATEX_OUTPUT));
11673  }
11674  if (generateRtf)
11675  {
11676  copyLogo(Config_getString(RTF_OUTPUT));
11677  }
11678 
11679  if (generateHtml &&
11680  Config_getBool(GENERATE_HTMLHELP) &&
11681  !Config_getString(HHC_LOCATION).isEmpty())
11682  {
11683  g_s.begin("Running html help compiler...\n");
11684  QString oldDir = QDir::currentDirPath();
11685  QDir::setCurrent(Config_getString(HTML_OUTPUT));
11687  if (portable_system(Config_getString(HHC_LOCATION), "index.hhp", Debug::isFlagSet(Debug::ExtCmd))!=1)
11688  {
11689  err("failed to run html help compiler on index.hhp\n");
11690  }
11692  QDir::setCurrent(oldDir);
11693  g_s.end();
11694  }
11695  if ( generateHtml &&
11696  Config_getBool(GENERATE_QHP) &&
11697  !Config_getString(QHG_LOCATION).isEmpty())
11698  {
11699  g_s.begin("Running qhelpgenerator...\n");
11700  QCString const qhpFileName = Qhp::getQhpFileName();
11701  QCString const qchFileName = getQchFileName();
11702 
11703  QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
11704  QString const oldDir = QDir::currentDirPath();
11705  QDir::setCurrent(Config_getString(HTML_OUTPUT));
11707  if (portable_system(Config_getString(QHG_LOCATION), args.data(), FALSE))
11708  {
11709  err("failed to run qhelpgenerator on index.qhp\n");
11710  }
11712  QDir::setCurrent(oldDir);
11713  g_s.end();
11714  }
11715 
11716  int cacheParam;
11717  msg("lookup cache used %d/%d hits=%d misses=%d\n",
11718  Doxygen::lookupCache->count(),
11719  Doxygen::lookupCache->size(),
11720  Doxygen::lookupCache->hits(),
11721  Doxygen::lookupCache->misses());
11722  cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
11723  if (cacheParam>Config_getInt(LOOKUP_CACHE_SIZE))
11724  {
11725  msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
11726  }
11727 
11729  {
11730  msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
11731  ((double)Doxygen::runningTime.elapsed())/1000.0,
11733  );
11734  g_s.print();
11735  }
11736  else
11737  {
11738  msg("finished...\n");
11739  }
11740 
11741 
11742  /**************************************************************************
11743  * Start cleaning up *
11744  **************************************************************************/
11745 
11746  cleanUpDoxygen();
11747 
11749  Doxygen::symbolStorage->close();
11750  QDir thisDir;
11751  thisDir.remove(Doxygen::objDBFileName);
11752  Config::deinit();
11753  QTextCodec::deleteAllCodecs();
11754  delete Doxygen::symbolMap;
11755  delete Doxygen::clangUsrMap;
11756  delete Doxygen::symbolStorage;
11757  g_successfulRun=TRUE;
11758 }
11759