Imported Upstream version 1.8.15
[platform/upstream/doxygen.git] / src / doxygen.cpp
1 /******************************************************************************
2  *
3  * Copyright (C) 1997-2015 by Dimitri van Heesch.
4  *
5  * Permission to use, copy, modify, and distribute this software and its
6  * documentation under the terms of the GNU General Public License is hereby
7  * granted. No representations are made about the suitability of this software
8  * for any purpose. It is provided "as is" without express or implied warranty.
9  * See the GNU General Public License for more details.
10  *
11  * Documents produced by Doxygen are derivative works derived from the
12  * input used in their production; they are not affected by this license.
13  *
14  */
15
16 #if !defined(_WIN32) || defined(__CYGWIN__)
17 #define _DEFAULT_SOURCE 1
18 #endif
19
20 #include <locale.h>
21
22 #include <qfileinfo.h>
23 #include <qfile.h>
24 #include <qdir.h>
25 #include <qdict.h>
26 #include <qregexp.h>
27 #include <qstrlist.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <sys/stat.h>
31 #include <qtextcodec.h>
32 #include <errno.h>
33 #include <qptrdict.h>
34 #include <qtextstream.h>
35
36 #include "version.h"
37 #include "doxygen.h"
38 #include "scanner.h"
39 #include "entry.h"
40 #include "index.h"
41 #include "logos.h"
42 #include "message.h"
43 #include "config.h"
44 #include "util.h"
45 #include "pre.h"
46 #include "tagreader.h"
47 #include "dot.h"
48 #include "msc.h"
49 #include "docparser.h"
50 #include "dirdef.h"
51 #include "outputlist.h"
52 #include "declinfo.h"
53 #include "htmlgen.h"
54 #include "latexgen.h"
55 #include "mangen.h"
56 #include "language.h"
57 #include "debug.h"
58 #include "htmlhelp.h"
59 #include "qhp.h"
60 #include "ftvhelp.h"
61 #include "defargs.h"
62 #include "rtfgen.h"
63 #include "sqlite3gen.h"
64 #include "xmlgen.h"
65 #include "docbookgen.h"
66 #include "defgen.h"
67 #include "perlmodgen.h"
68 #include "reflist.h"
69 #include "pagedef.h"
70 #include "bufstr.h"
71 #include "commentcnv.h"
72 #include "cmdmapper.h"
73 #include "searchindex.h"
74 #include "parserintf.h"
75 #include "htags.h"
76 #include "pyscanner.h"
77 #include "fortranscanner.h"
78 #include "xmlscanner.h"
79 #include "sqlscanner.h"
80 #include "tclscanner.h"
81 #include "code.h"
82 #include "objcache.h"
83 #include "store.h"
84 #include "marshal.h"
85 #include "portable.h"
86 #include "vhdljjparser.h"
87 #include "vhdldocgen.h"
88 #include "eclipsehelp.h"
89 #include "cite.h"
90 #include "filestorage.h"
91 #include "markdown.h"
92 #include "arguments.h"
93 #include "memberlist.h"
94 #include "layout.h"
95 #include "groupdef.h"
96 #include "classlist.h"
97 #include "namespacedef.h"
98 #include "filename.h"
99 #include "membername.h"
100 #include "membergroup.h"
101 #include "docsets.h"
102 #include "formula.h"
103 #include "settings.h"
104 #include "context.h"
105 #include "fileparser.h"
106 #include "emoji.h"
107
108 // provided by the generated file resources.cpp
109 extern void initResources();
110
111 #define RECURSE_ENTRYTREE(func,var) \
112   do { if (var->children()) { \
113     EntryNavListIterator eli(*var->children()); \
114     for (;eli.current();++eli) func(eli.current()); \
115   } } while(0)
116
117
118 #if !defined(_WIN32) || defined(__CYGWIN__)
119 #include <signal.h>
120 #define HAS_SIGNALS
121 #endif
122
123 // globally accessible variables
124 ClassSDict      *Doxygen::classSDict = 0;
125 ClassSDict      *Doxygen::hiddenClasses = 0;
126 NamespaceSDict  *Doxygen::namespaceSDict = 0;
127 MemberNameSDict *Doxygen::memberNameSDict = 0;
128 MemberNameSDict *Doxygen::functionNameSDict = 0;
129 FileNameList    *Doxygen::inputNameList = 0;       // all input files
130 FileNameDict    *Doxygen::inputNameDict = 0;
131 GroupSDict      *Doxygen::groupSDict = 0;
132 FormulaList     *Doxygen::formulaList = 0;       // all formulas
133 FormulaDict     *Doxygen::formulaDict = 0;       // all formulas
134 FormulaDict     *Doxygen::formulaNameDict = 0;   // the label name of all formulas
135 PageSDict       *Doxygen::pageSDict = 0;
136 PageSDict       *Doxygen::exampleSDict = 0;
137 SectionDict     *Doxygen::sectionDict = 0;        // all page sections
138 CiteDict        *Doxygen::citeDict=0;              // database of bibliographic references
139 StringDict       Doxygen::aliasDict(257);          // aliases
140 QDict<void>      Doxygen::inputPaths(1009);
141 FileNameDict    *Doxygen::includeNameDict = 0;     // include names
142 FileNameDict    *Doxygen::exampleNameDict = 0;     // examples
143 FileNameDict    *Doxygen::imageNameDict = 0;       // images
144 FileNameDict    *Doxygen::dotFileNameDict = 0;     // dot files
145 FileNameDict    *Doxygen::mscFileNameDict = 0;     // msc files
146 FileNameDict    *Doxygen::diaFileNameDict = 0;     // dia files
147 StringDict       Doxygen::namespaceAliasDict(257); // all namespace aliases
148 StringDict       Doxygen::tagDestinationDict(257); // all tag locations
149 QDict<void>      Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
150 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
151 PageDef         *Doxygen::mainPage = 0;
152 bool             Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
153 NamespaceDef    *Doxygen::globalScope = 0;
154 QDict<RefList>  *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
155 bool             Doxygen::parseSourcesNeeded = FALSE;
156 QTime            Doxygen::runningTime;
157 SearchIndexIntf *Doxygen::searchIndex=0;
158 QDict<DefinitionIntf> *Doxygen::symbolMap = 0;
159 QDict<Definition> *Doxygen::clangUsrMap = 0;
160 bool             Doxygen::outputToWizard=FALSE;
161 QDict<int> *     Doxygen::htmlDirMap = 0;
162 QCache<LookupInfo> *Doxygen::lookupCache;
163 DirSDict        *Doxygen::directories;
164 SDict<DirRelation> Doxygen::dirRelations(257);
165 ParserManager   *Doxygen::parserManager = 0;
166 QCString Doxygen::htmlFileExtension;
167 bool             Doxygen::suppressDocWarnings = FALSE;
168 Store           *Doxygen::symbolStorage;
169 QCString         Doxygen::objDBFileName;
170 QCString         Doxygen::entryDBFileName;
171 QCString         Doxygen::filterDBFileName;
172 bool             Doxygen::gatherDefines = TRUE;
173 IndexList       *Doxygen::indexList;
174 int              Doxygen::subpageNestingLevel = 0;
175 bool             Doxygen::userComments = FALSE;
176 QCString         Doxygen::spaces;
177 bool             Doxygen::generatingXmlOutput = FALSE;
178 bool             Doxygen::markdownSupport = TRUE;
179 GenericsSDict   *Doxygen::genericsDict;
180
181 // locally accessible globals
182 static QDict<EntryNav>  g_classEntries(1009);
183 static StringList       g_inputFiles;
184 static QDict<void>      g_compoundKeywordDict(7);  // keywords recognised as compounds
185 static OutputList      *g_outputList = 0;          // list of output generating objects
186 static QDict<FileDef>   g_usingDeclarations(1009); // used classes
187 static FileStorage     *g_storage = 0;
188 static bool             g_successfulRun = FALSE;
189 static bool             g_dumpSymbolMap = FALSE;
190 static bool             g_useOutputTemplate = FALSE;
191
192 void clearAll()
193 {
194   g_inputFiles.clear();
195   //g_excludeNameDict.clear();
196   //delete g_outputList; g_outputList=0;
197
198   Doxygen::classSDict->clear();
199   Doxygen::namespaceSDict->clear();
200   Doxygen::pageSDict->clear();
201   Doxygen::exampleSDict->clear();
202   Doxygen::inputNameList->clear();
203   Doxygen::formulaList->clear();
204   Doxygen::sectionDict->clear();
205   Doxygen::inputNameDict->clear();
206   Doxygen::includeNameDict->clear();
207   Doxygen::exampleNameDict->clear();
208   Doxygen::imageNameDict->clear();
209   Doxygen::dotFileNameDict->clear();
210   Doxygen::mscFileNameDict->clear();
211   Doxygen::diaFileNameDict->clear();
212   Doxygen::formulaDict->clear();
213   Doxygen::formulaNameDict->clear();
214   Doxygen::tagDestinationDict.clear();
215   delete Doxygen::citeDict;
216   delete Doxygen::mainPage; Doxygen::mainPage=0;
217 }
218
219 class Statistics
220 {
221   public:
222     Statistics() { stats.setAutoDelete(TRUE); }
223     void begin(const char *name)
224     {
225       msg(name);
226       stat *entry= new stat(name,0);
227       stats.append(entry);
228       time.restart();
229     }
230     void end()
231     {
232       stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
233     }
234     void print()
235     {
236       bool restore=FALSE;
237       if (Debug::isFlagSet(Debug::Time))
238       {
239         Debug::clearFlag("time");
240         restore=TRUE;
241       }
242       msg("----------------------\n");
243       QListIterator<stat> sli(stats);
244       stat *s;
245       for ( sli.toFirst(); (s=sli.current()); ++sli )
246       {
247         msg("Spent %.3f seconds in %s",s->elapsed,s->name);
248       }
249       if (restore) Debug::setFlag("time");
250     }
251   private:
252     struct stat
253     {
254       const char *name;
255       double elapsed;
256       stat() : name(NULL),elapsed(0) {}
257       stat(const char *n, double el) : name(n),elapsed(el) {}
258     };
259     QList<stat> stats;
260     QTime       time;
261 } g_s;
262
263
264 void statistics()
265 {
266   fprintf(stderr,"--- inputNameDict stats ----\n");
267   Doxygen::inputNameDict->statistics();
268   fprintf(stderr,"--- includeNameDict stats ----\n");
269   Doxygen::includeNameDict->statistics();
270   fprintf(stderr,"--- exampleNameDict stats ----\n");
271   Doxygen::exampleNameDict->statistics();
272   fprintf(stderr,"--- imageNameDict stats ----\n");
273   Doxygen::imageNameDict->statistics();
274   fprintf(stderr,"--- dotFileNameDict stats ----\n");
275   Doxygen::dotFileNameDict->statistics();
276   fprintf(stderr,"--- mscFileNameDict stats ----\n");
277   Doxygen::mscFileNameDict->statistics();
278   fprintf(stderr,"--- diaFileNameDict stats ----\n");
279   Doxygen::diaFileNameDict->statistics();
280   //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
281   //g_excludeNameDict.statistics();
282   fprintf(stderr,"--- aliasDict stats ----\n");
283   Doxygen::aliasDict.statistics();
284   fprintf(stderr,"--- typedefDict stats ----\n");
285   fprintf(stderr,"--- namespaceAliasDict stats ----\n");
286   Doxygen::namespaceAliasDict.statistics();
287   fprintf(stderr,"--- formulaDict stats ----\n");
288   Doxygen::formulaDict->statistics();
289   fprintf(stderr,"--- formulaNameDict stats ----\n");
290   Doxygen::formulaNameDict->statistics();
291   fprintf(stderr,"--- tagDestinationDict stats ----\n");
292   Doxygen::tagDestinationDict.statistics();
293   fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
294   g_compoundKeywordDict.statistics();
295   fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
296   Doxygen::expandAsDefinedDict.statistics();
297   fprintf(stderr,"--- memGrpInfoDict stats ----\n");
298   Doxygen::memGrpInfoDict.statistics();
299 }
300
301
302
303 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
304                    ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
305 static void findMember(EntryNav *rootNav,
306                        QCString funcDecl,
307                        bool overloaded,
308                        bool isFunc
309                       );
310
311 enum FindBaseClassRelation_Mode
312 {
313   TemplateInstances,
314   DocumentedOnly,
315   Undocumented
316 };
317
318 static bool findClassRelation(
319                            EntryNav *rootNav,
320                            Definition *context,
321                            ClassDef *cd,
322                            BaseInfo *bi,
323                            QDict<int> *templateNames,
324                            /*bool insertUndocumented*/
325                            FindBaseClassRelation_Mode mode,
326                            bool isArtificial
327                           );
328
329 /** A struct contained the data for an STL class */
330 struct STLInfo
331 {
332   const char *className;
333   const char *baseClass1;
334   const char *baseClass2;
335   const char *templType1;
336   const char *templName1;
337   const char *templType2;
338   const char *templName2;
339   bool virtualInheritance;
340   bool iterators;
341 };
342
343 static STLInfo g_stlinfo[] =
344 {
345   // className              baseClass1                      baseClass2             templType1     templName1     templType2    templName2     virtInheritance  // iterators
346   { "allocator",            0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
347   { "array",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE }, // C++11
348   { "auto_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // deprecated
349   { "smart_ptr",            0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
350   { "unique_ptr",           0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
351   { "shared_ptr",           0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++14
352   { "weak_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
353   { "ios_base",             0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
354   { "error_code",           0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
355   { "error_category",       0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
356   { "system_error",         0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
357   { "error_condition",      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
358   { "thread",               0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
359   { "basic_ios",            "ios_base",                     0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
360   { "basic_istream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
361   { "basic_ostream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
362   { "basic_iostream",       "basic_istream<Char>",          "basic_ostream<Char>", "Char",        0,             0,            0,             FALSE,              FALSE },
363   { "basic_ifstream",       "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
364   { "basic_ofstream",       "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
365   { "basic_fstream",        "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
366   { "basic_istringstream",  "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
367   { "basic_ostringstream",  "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
368   { "basic_stringstream",   "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
369   { "ios",                  "basic_ios<char>",              0,                     0,             0,             0,            0,             FALSE,              FALSE },
370   { "wios",                 "basic_ios<wchar_t>",           0,                     0,             0,             0,            0,             FALSE,              FALSE },
371   { "istream",              "basic_istream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
372   { "wistream",             "basic_istream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
373   { "ostream",              "basic_ostream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
374   { "wostream",             "basic_ostream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
375   { "ifstream",             "basic_ifstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
376   { "wifstream",            "basic_ifstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
377   { "ofstream",             "basic_ofstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
378   { "wofstream",            "basic_ofstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
379   { "fstream",              "basic_fstream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
380   { "wfstream",             "basic_fstream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
381   { "istringstream",        "basic_istringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
382   { "wistringstream",       "basic_istringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
383   { "ostringstream",        "basic_ostringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
384   { "wostringstream",       "basic_ostringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
385   { "stringstream",         "basic_stringstream<char>",     0,                     0,             0,             0,            0,             FALSE,              FALSE },
386   { "wstringstream",        "basic_stringstream<wchar_t>",  0,                     0,             0,             0,            0,             FALSE,              FALSE },
387   { "basic_string",         0,                              0,                     "Char",        0,             0,            0,             FALSE,              TRUE  },
388   { "string",               "basic_string<char>",           0,                     0,             0,             0,            0,             FALSE,              TRUE  },
389   { "wstring",              "basic_string<wchar_t>",        0,                     0,             0,             0,            0,             FALSE,              TRUE  },
390   { "complex",              0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
391   { "bitset",               0,                              0,                     "Bits",        0,             0,            0,             FALSE,              FALSE },
392   { "deque",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
393   { "list",                 0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
394   { "forward_list",         0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  }, // C++11
395   { "map",                  0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
396   { "unordered_map",        0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
397   { "multimap",             0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
398   { "unordered_multimap",   0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
399   { "set",                  0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
400   { "unordered_set",        0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
401   { "multiset",             0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
402   { "unordered_multiset",   0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
403   { "vector",               0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
404   { "queue",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
405   { "priority_queue",       0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
406   { "stack",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
407   { "valarray",             0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
408   { "exception",            0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
409   { "bad_alloc",            "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
410   { "bad_cast",             "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
411   { "bad_typeid",           "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
412   { "logic_error",          "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
413   { "ios_base::failure",    "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
414   { "runtime_error",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
415   { "bad_exception",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
416   { "domain_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
417   { "invalid_argument",     "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
418   { "length_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
419   { "out_of_range",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
420   { "range_error",          "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
421   { "overflow_error",       "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
422   { "underflow_error",      "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
423   { 0,                      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }
424 };
425
426 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
427 {
428   Entry *memEntry = new Entry;
429   memEntry->name       = name;
430   memEntry->type       = type;
431   memEntry->protection = Public;
432   memEntry->section    = Entry::VARIABLE_SEC;
433   memEntry->brief      = "STL member";
434   memEntry->hidden     = FALSE;
435   memEntry->artificial = TRUE;
436   //memEntry->parent     = root;
437   //root->addSubEntry(memEntry);
438   EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
439   memEntryNav->setEntry(memEntry);
440   rootNav->addChild(memEntryNav);
441 }
442
443 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
444 {
445   Entry *iteratorClassEntry = new Entry;
446   iteratorClassEntry->fileName  = "[STL]";
447   iteratorClassEntry->startLine = 1;
448   iteratorClassEntry->name      = name;
449   iteratorClassEntry->section   = Entry::CLASS_SEC;
450   iteratorClassEntry->brief     = "STL iterator class";
451   iteratorClassEntry->hidden    = FALSE;
452   iteratorClassEntry->artificial= TRUE;
453   EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
454   iteratorClassEntryNav->setEntry(iteratorClassEntry);
455   classEntryNav->addChild(iteratorClassEntryNav);
456 }
457
458
459 static void addSTLClasses(EntryNav *rootNav)
460 {
461   Entry *namespaceEntry = new Entry;
462   namespaceEntry->fileName  = "[STL]";
463   namespaceEntry->startLine = 1;
464   //namespaceEntry->parent    = rootNav->entry();
465   namespaceEntry->name      = "std";
466   namespaceEntry->section   = Entry::NAMESPACE_SEC;
467   namespaceEntry->brief     = "STL namespace";
468   namespaceEntry->hidden    = FALSE;
469   namespaceEntry->artificial= TRUE;
470   //root->addSubEntry(namespaceEntry);
471   EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
472   namespaceEntryNav->setEntry(namespaceEntry);
473   rootNav->addChild(namespaceEntryNav);
474
475   STLInfo *info = g_stlinfo;
476   while (info->className)
477   {
478     //printf("Adding STL class %s\n",info->className);
479     QCString fullName = info->className;
480     fullName.prepend("std::");
481
482     // add fake Entry for the class
483     Entry *classEntry = new Entry;
484     classEntry->fileName  = "[STL]";
485     classEntry->startLine = 1;
486     classEntry->name      = fullName;
487     //classEntry->parent    = namespaceEntry;
488     classEntry->section   = Entry::CLASS_SEC;
489     classEntry->brief     = "STL class";
490     classEntry->hidden    = FALSE;
491     classEntry->artificial= TRUE;
492     //namespaceEntry->addSubEntry(classEntry);
493     EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
494     classEntryNav->setEntry(classEntry);
495     namespaceEntryNav->addChild(classEntryNav);
496
497     // add template arguments to class
498     if (info->templType1)
499     {
500       ArgumentList *al = new ArgumentList;
501       Argument *a=new Argument;
502       a->type="typename";
503       a->name=info->templType1;
504       al->append(a);
505       if (info->templType2) // another template argument
506       {
507         a=new Argument;
508         a->type="typename";
509         a->name=info->templType2;
510         al->append(a);
511       }
512       classEntry->tArgLists = new QList<ArgumentList>;
513       classEntry->tArgLists->setAutoDelete(TRUE);
514       classEntry->tArgLists->append(al);
515     }
516     // add member variables
517     if (info->templName1)
518     {
519       addSTLMember(classEntryNav,info->templType1,info->templName1);
520     }
521     if (info->templName2)
522     {
523       addSTLMember(classEntryNav,info->templType2,info->templName2);
524     }
525     if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" || fullName=="std::shared_ptr" ||
526         fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
527     {
528       Entry *memEntry = new Entry;
529       memEntry->name       = "operator->";
530       memEntry->args       = "()";
531       memEntry->type       = "T*";
532       memEntry->protection = Public;
533       memEntry->section    = Entry::FUNCTION_SEC;
534       memEntry->brief      = "STL member";
535       memEntry->hidden     = FALSE;
536       memEntry->artificial = FALSE;
537       EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
538       memEntryNav->setEntry(memEntry);
539       classEntryNav->addChild(memEntryNav);
540     }
541     if (info->baseClass1)
542     {
543       classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
544     }
545     if (info->baseClass2)
546     {
547       classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
548     }
549     if (info->iterators)
550     {
551       // add iterator class
552       addSTLIterator(classEntryNav,fullName+"::iterator");
553       addSTLIterator(classEntryNav,fullName+"::const_iterator");
554       addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
555       addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
556     }
557     info++;
558   }
559 }
560
561 //----------------------------------------------------------------------------
562
563 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
564                                               FileDef *fileScope,TagInfo *tagInfo);
565
566 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
567 {
568   if (rootNav->parent()) // add the page to it's scope
569   {
570     QCString scope = rootNav->parent()->name();
571     if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
572     {
573       scope=substitute(scope,".","::");
574     }
575     scope = stripAnonymousNamespaceScope(scope);
576     scope+="::"+pd->name();
577     Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
578     if (d)
579     {
580       pd->setPageScope(d);
581     }
582   }
583 }
584
585 static void addRelatedPage(EntryNav *rootNav)
586 {
587   Entry *root = rootNav->entry();
588   GroupDef *gd=0;
589   QListIterator<Grouping> gli(*root->groups);
590   Grouping *g;
591   for (;(g=gli.current());++gli)
592   {
593     if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
594   }
595   //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
596   QCString doc;
597   if (root->brief.isEmpty())
598   {
599     doc=root->doc+root->inbodyDocs;
600   }
601   else
602   {
603     doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
604   }
605   PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
606       root->docFile,root->docLine,
607       root->sli,
608       gd,rootNav->tagInfo(),
609       root->lang
610      );
611   if (pd)
612   {
613     pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
614     pd->addSectionsToDefinition(root->anchors);
615     pd->setLocalToc(root->localToc);
616     addPageToContext(pd,rootNav);
617   }
618 }
619
620 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
621 {
622   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
623         ((!includeExternal && rootNav->tagInfo()==0) ||
624          ( includeExternal && rootNav->tagInfo()!=0))
625      )
626   {
627     rootNav->loadEntry(g_storage);
628     Entry *root = rootNav->entry();
629
630     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
631         (root->groupDocType!=Entry::GROUPDOC_NORMAL &&  additional))
632     {
633       GroupDef *gd = Doxygen::groupSDict->find(root->name);
634       //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
635       //    root->type.data(),root->name.data(),additional,includeExternal,gd);
636
637       if (gd)
638       {
639         if ( !gd->hasGroupTitle() )
640         {
641           gd->setGroupTitle( root->type );
642         }
643         else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
644         {
645           warn( root->fileName,root->startLine,
646               "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
647               qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
648         }
649         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
650         gd->setDocumentation( root->doc, root->docFile, root->docLine );
651         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
652         gd->addSectionsToDefinition(root->anchors);
653         gd->setRefItems(root->sli);
654         gd->setLanguage(root->lang);
655       }
656       else
657       {
658         if (rootNav->tagInfo())
659         {
660           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
661           gd->setReference(rootNav->tagInfo()->tagName);
662         }
663         else
664         {
665           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
666         }
667         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
668         // allow empty docs for group
669         gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
670         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
671         gd->addSectionsToDefinition(root->anchors);
672         Doxygen::groupSDict->append(root->name,gd);
673         gd->setRefItems(root->sli);
674         gd->setLanguage(root->lang);
675       }
676     }
677
678     rootNav->releaseEntry();
679   }
680   if (rootNav->children())
681   {
682     EntryNavListIterator eli(*rootNav->children());
683     EntryNav *e;
684     for (;(e=eli.current());++eli)
685     {
686       buildGroupListFiltered(e,additional,includeExternal);
687     }
688   }
689 }
690
691 static void buildGroupList(EntryNav *rootNav)
692 {
693   // --- first process only local groups
694   // first process the @defgroups blocks
695   buildGroupListFiltered(rootNav,FALSE,FALSE);
696   // then process the @addtogroup, @weakgroup blocks
697   buildGroupListFiltered(rootNav,TRUE,FALSE);
698
699   // --- then also process external groups
700   // first process the @defgroups blocks
701   buildGroupListFiltered(rootNav,FALSE,TRUE);
702   // then process the @addtogroup, @weakgroup blocks
703   buildGroupListFiltered(rootNav,TRUE,TRUE);
704 }
705
706 static void findGroupScope(EntryNav *rootNav)
707 {
708   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
709       rootNav->parent() && !rootNav->parent()->name().isEmpty())
710   {
711     GroupDef *gd;
712     if ((gd=Doxygen::groupSDict->find(rootNav->name())))
713     {
714       QCString scope = rootNav->parent()->name();
715       if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
716       {
717         scope=substitute(scope,".","::");
718       }
719       scope = stripAnonymousNamespaceScope(scope);
720       scope+="::"+gd->name();
721       Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
722       if (d)
723       {
724         gd->setGroupScope(d);
725       }
726     }
727   }
728   RECURSE_ENTRYTREE(findGroupScope,rootNav);
729 }
730
731 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
732 {
733   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
734   {
735     rootNav->loadEntry(g_storage);
736     Entry *root = rootNav->entry();
737
738     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
739         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
740     {
741       GroupDef *gd;
742       if ((gd=Doxygen::groupSDict->find(root->name)))
743       {
744         //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
745         addGroupToGroups(root,gd);
746       }
747     }
748
749     rootNav->releaseEntry();
750   }
751   if (rootNav->children())
752   {
753     EntryNavListIterator eli(*rootNav->children());
754     EntryNav *e;
755     for (;(e=eli.current());++eli)
756     {
757       organizeSubGroupsFiltered(e,additional);
758     }
759   }
760 }
761
762 static void organizeSubGroups(EntryNav *rootNav)
763 {
764   //printf("Defining groups\n");
765   // first process the @defgroups blocks
766   organizeSubGroupsFiltered(rootNav,FALSE);
767   //printf("Additional groups\n");
768   // then process the @addtogroup, @weakgroup blocks
769   organizeSubGroupsFiltered(rootNav,TRUE);
770 }
771
772 //----------------------------------------------------------------------
773
774 static void buildFileList(EntryNav *rootNav)
775 {
776   if (((rootNav->section()==Entry::FILEDOC_SEC) ||
777         ((rootNav->section() & Entry::FILE_MASK) && Config_getBool(EXTRACT_ALL))) &&
778       !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
779      )
780   {
781     rootNav->loadEntry(g_storage);
782     Entry *root = rootNav->entry();
783
784     bool ambig;
785     FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
786     //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
787     if (fd && !ambig)
788     {
789 #if 0
790       if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
791           (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
792       {
793         warn(
794             root->fileName,root->startLine,
795             "file %s already documented. "
796             "Skipping documentation.",
797             root->name.data()
798             );
799       }
800       else
801 #endif
802       {
803         //printf("Adding documentation!\n");
804         // using FALSE in setDocumentation is small hack to make sure a file
805         // is documented even if a \file command is used without further
806         // documentation
807         fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
808         fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
809         fd->addSectionsToDefinition(root->anchors);
810         fd->setRefItems(root->sli);
811         QListIterator<Grouping> gli(*root->groups);
812         Grouping *g;
813         for (;(g=gli.current());++gli)
814         {
815           GroupDef *gd=0;
816           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
817           {
818             gd->addFile(fd);
819             fd->makePartOfGroup(gd);
820             //printf("File %s: in group %s\n",fd->name().data(),s->data());
821           }
822         }
823       }
824     }
825     else
826     {
827       const char *fn = root->fileName.data();
828       QCString text(4096);
829       text.sprintf("the name `%s' supplied as "
830           "the second argument in the \\file statement ",
831           qPrint(root->name));
832       if (ambig) // name is ambiguous
833       {
834         text+="matches the following input files:\n";
835         text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
836         text+="Please use a more specific name by "
837           "including a (larger) part of the path!";
838       }
839       else // name is not an input file
840       {
841         text+="is not an input file";
842       }
843       warn(fn,root->startLine,text);
844     }
845
846     rootNav->releaseEntry();
847   }
848   RECURSE_ENTRYTREE(buildFileList,rootNav);
849 }
850
851 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
852 {
853   if (
854       (!root->doc.stripWhiteSpace().isEmpty() ||
855        !root->brief.stripWhiteSpace().isEmpty() ||
856        Config_getBool(EXTRACT_ALL)
857       ) && root->protection!=Private
858      )
859   {
860     //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
861
862     bool local=Config_getBool(FORCE_LOCAL_INCLUDES);
863     QCString includeFile = root->includeFile;
864     if (!includeFile.isEmpty() && includeFile.at(0)=='"')
865     {
866       local = TRUE;
867       includeFile=includeFile.mid(1,includeFile.length()-2);
868     }
869     else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
870     {
871       local = FALSE;
872       includeFile=includeFile.mid(1,includeFile.length()-2);
873     }
874
875     bool ambig;
876     FileDef *fd=0;
877     // see if we need to include a verbatim copy of the header file
878     //printf("root->includeFile=%s\n",root->includeFile.data());
879     if (!includeFile.isEmpty() &&
880         (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
881        )
882     { // explicit request
883       QCString text;
884       text.sprintf("the name `%s' supplied as "
885                   "the argument of the \\class, \\struct, \\union, or \\include command ",
886                   qPrint(includeFile)
887                  );
888       if (ambig) // name is ambiguous
889       {
890         text+="matches the following input files:\n";
891         text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
892         text+="Please use a more specific name by "
893             "including a (larger) part of the path!";
894       }
895       else // name is not an input file
896       {
897         text+="is not an input file";
898       }
899       warn(root->fileName,root->startLine,text);
900     }
901     else if (includeFile.isEmpty() && ifd &&
902         // see if the file extension makes sense
903         guessSection(ifd->name())==Entry::HEADER_SEC)
904     { // implicit assumption
905       fd=ifd;
906     }
907
908     // if a file is found, we mark it as a source file.
909     if (fd)
910     {
911       QCString iName = !root->includeName.isEmpty() ?
912                        root->includeName : includeFile;
913       if (!iName.isEmpty()) // user specified include file
914       {
915         if (iName.at(0)=='<') local=FALSE; // explicit override
916         else if (iName.at(0)=='"') local=TRUE;
917         if (iName.at(0)=='"' || iName.at(0)=='<')
918         {
919           iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
920         }
921         if (iName.isEmpty())
922         {
923           iName=fd->name();
924         }
925       }
926       else if (!Config_getList(STRIP_FROM_INC_PATH).isEmpty())
927       {
928         iName=stripFromIncludePath(fd->absFilePath());
929       }
930       else // use name of the file containing the class definition
931       {
932         iName=fd->name();
933       }
934       if (fd->generateSourceFile()) // generate code for header
935       {
936         cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
937       }
938       else // put #include in the class documentation without link
939       {
940         cd->setIncludeFile(0,iName,local,TRUE);
941       }
942     }
943   }
944 }
945
946 #if 0
947 static bool addNamespace(Entry *root,ClassDef *cd)
948 {
949   // see if this class is defined inside a namespace
950   if (root->section & Entry::COMPOUND_MASK)
951   {
952     Entry *e = root->parent;
953     while (e)
954     {
955       if (e->section==Entry::NAMESPACE_SEC)
956       {
957         NamespaceDef *nd=0;
958         QCString nsName = stripAnonymousNamespaceScope(e->name);
959         //printf("addNameSpace() trying: %s\n",nsName.data());
960         if (!nsName.isEmpty() && nsName.at(0)!='@' &&
961             (nd=getResolvedNamespace(nsName))
962            )
963         {
964           cd->setNamespace(nd);
965           cd->setOuterScope(nd);
966           nd->insertClass(cd);
967           return TRUE;
968         }
969       }
970       e=e->parent;
971     }
972   }
973   return FALSE;
974 }
975 #endif
976
977 #if 0
978 static Definition *findScope(Entry *root,int level=0)
979 {
980   if (root==0) return 0;
981   //printf("start findScope name=%s\n",root->name.data());
982   Definition *result=0;
983   if (root->section&Entry::SCOPE_MASK)
984   {
985     result = findScope(root->parent,level+1); // traverse to the root of the tree
986     if (result)
987     {
988       //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
989       // TODO: look at template arguments
990       result = result->findInnerCompound(root->name);
991     }
992     else // reached the global scope
993     {
994       // TODO: look at template arguments
995       result = Doxygen::globalScope->findInnerCompound(root->name);
996       //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
997     }
998   }
999   //printf("end findScope(%s,%d)=%s\n",root->name.data(),
1000   //       level,result==0 ? "<none>" : result->name().data());
1001   return result;
1002 }
1003 #endif
1004
1005 /*! returns the Definition object belonging to the first \a level levels of
1006  *  full qualified name \a name. Creates an artificial scope if the scope is
1007  *  not found and set the parent/child scope relation if the scope is found.
1008  */
1009 static Definition *buildScopeFromQualifiedName(const QCString name,
1010                                                int level,SrcLangExt lang,TagInfo *tagInfo)
1011 {
1012   //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
1013   int i=0;
1014   int p=0,l;
1015   Definition *prevScope=Doxygen::globalScope;
1016   QCString fullScope;
1017   while (i<level)
1018   {
1019     int idx=getScopeFragment(name,p,&l);
1020     if (idx==-1) return prevScope;
1021     QCString nsName = name.mid(idx,l);
1022     if (nsName.isEmpty()) return prevScope;
1023     if (!fullScope.isEmpty()) fullScope+="::";
1024     fullScope+=nsName;
1025     NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
1026     Definition *innerScope = nd;
1027     ClassDef *cd=0;
1028     if (nd==0) cd = getClass(fullScope);
1029     if (nd==0 && cd) // scope is a class
1030     {
1031       innerScope = cd;
1032     }
1033     else if (nd==0 && cd==0 && fullScope.find('<')==-1) // scope is not known and could be a namespace!
1034     {
1035       // introduce bogus namespace
1036       //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
1037       nd=new NamespaceDef(
1038         "[generated]",1,1,fullScope,
1039         tagInfo?tagInfo->tagName:QCString(),
1040         tagInfo?tagInfo->fileName:QCString());
1041       nd->setLanguage(lang);
1042
1043       // add namespace to the list
1044       Doxygen::namespaceSDict->inSort(fullScope,nd);
1045       innerScope = nd;
1046     }
1047     else // scope is a namespace
1048     {
1049     }
1050     if (innerScope)
1051     {
1052       // make the parent/child scope relation
1053       prevScope->addInnerCompound(innerScope);
1054       innerScope->setOuterScope(prevScope);
1055     }
1056     else // current scope is a class, so return only the namespace part...
1057     {
1058       return prevScope;
1059     }
1060     // proceed to the next scope fragment
1061     p=idx+l+2;
1062     prevScope=innerScope;
1063     i++;
1064   }
1065   return prevScope;
1066 }
1067
1068 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
1069                                               FileDef *fileScope,TagInfo *tagInfo)
1070 {
1071   //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
1072   Definition *resultScope=startScope;
1073   if (resultScope==0) resultScope=Doxygen::globalScope;
1074   QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
1075   int l1=0,i1;
1076   i1=getScopeFragment(scope,0,&l1);
1077   if (i1==-1)
1078   {
1079     //printf(">no fragments!\n");
1080     return resultScope;
1081   }
1082   int p=i1+l1,l2=0,i2;
1083   while ((i2=getScopeFragment(scope,p,&l2))!=-1)
1084   {
1085     QCString nestedNameSpecifier = scope.mid(i1,l1);
1086     Definition *orgScope = resultScope;
1087     //printf("  nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
1088     resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
1089     //printf("  resultScope=%p\n",resultScope);
1090     if (resultScope==0)
1091     {
1092       NamespaceSDict *usedNamespaces;
1093       if (orgScope==Doxygen::globalScope && fileScope &&
1094           (usedNamespaces = fileScope->getUsedNamespaces()))
1095         // also search for used namespaces
1096       {
1097         NamespaceSDict::Iterator ni(*usedNamespaces);
1098         NamespaceDef *nd;
1099         for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
1100         {
1101           // restart search within the used namespace
1102           resultScope = findScopeFromQualifiedName(nd,n,fileScope,tagInfo);
1103         }
1104         if (resultScope)
1105         {
1106           // for a nested class A::I in used namespace N, we get
1107           // N::A::I while looking for A, so we should compare
1108           // resultScope->name() against scope.left(i2+l2)
1109           //printf("  -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1110           if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1111           {
1112             break;
1113           }
1114           goto nextFragment;
1115         }
1116       }
1117
1118       // also search for used classes. Complication: we haven't been able
1119       // to put them in the right scope yet, because we are still resolving
1120       // the scope relations!
1121       // Therefore loop through all used classes and see if there is a right
1122       // scope match between the used class and nestedNameSpecifier.
1123       QDictIterator<FileDef> ui(g_usingDeclarations);
1124       FileDef *usedFd;
1125       for (ui.toFirst();(usedFd=ui.current());++ui)
1126       {
1127         //printf("Checking using class %s\n",ui.currentKey());
1128         if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1129         {
1130           // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1131           // so use this instead.
1132           QCString fqn = QCString(ui.currentKey())+
1133                          scope.right(scope.length()-p);
1134           resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),
1135                                                     startScope->getLanguage(),0);
1136           //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1137           if (resultScope)
1138           {
1139             //printf("> Match! resultScope=%s\n",resultScope->name().data());
1140             return resultScope;
1141           }
1142         }
1143       }
1144
1145       //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1146       return 0;
1147     }
1148  nextFragment:
1149     i1=i2;
1150     l1=l2;
1151     p=i2+l2;
1152   }
1153   //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1154   return resultScope;
1155 }
1156
1157 ArgumentList *getTemplateArgumentsFromName(
1158                   const QCString &name,
1159                   const QList<ArgumentList> *tArgLists)
1160 {
1161   if (tArgLists==0) return 0;
1162
1163   QListIterator<ArgumentList> ali(*tArgLists);
1164   // for each scope fragment, check if it is a template and advance through
1165   // the list if so.
1166   int i,p=0;
1167   while ((i=name.find("::",p))!=-1)
1168   {
1169     NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1170     if (nd==0)
1171     {
1172       ClassDef *cd = getClass(name.left(i));
1173       if (cd)
1174       {
1175         if (cd->templateArguments())
1176         {
1177           ++ali;
1178         }
1179       }
1180     }
1181     p=i+2;
1182   }
1183   return ali.current();
1184 }
1185
1186 static
1187 ClassDef::CompoundType convertToCompoundType(int section,uint64 specifier)
1188 {
1189   ClassDef::CompoundType sec=ClassDef::Class;
1190   if (specifier&Entry::Struct)
1191     sec=ClassDef::Struct;
1192   else if (specifier&Entry::Union)
1193     sec=ClassDef::Union;
1194   else if (specifier&Entry::Category)
1195     sec=ClassDef::Category;
1196   else if (specifier&Entry::Interface)
1197     sec=ClassDef::Interface;
1198   else if (specifier&Entry::Protocol)
1199     sec=ClassDef::Protocol;
1200   else if (specifier&Entry::Exception)
1201     sec=ClassDef::Exception;
1202   else if (specifier&Entry::Service)
1203     sec=ClassDef::Service;
1204   else if (specifier&Entry::Singleton)
1205     sec=ClassDef::Singleton;
1206
1207   switch(section)
1208   {
1209     //case Entry::UNION_SEC:
1210     case Entry::UNIONDOC_SEC:
1211       sec=ClassDef::Union;
1212       break;
1213       //case Entry::STRUCT_SEC:
1214     case Entry::STRUCTDOC_SEC:
1215       sec=ClassDef::Struct;
1216       break;
1217       //case Entry::INTERFACE_SEC:
1218     case Entry::INTERFACEDOC_SEC:
1219       sec=ClassDef::Interface;
1220       break;
1221       //case Entry::PROTOCOL_SEC:
1222     case Entry::PROTOCOLDOC_SEC:
1223       sec=ClassDef::Protocol;
1224       break;
1225       //case Entry::CATEGORY_SEC:
1226     case Entry::CATEGORYDOC_SEC:
1227       sec=ClassDef::Category;
1228       break;
1229       //case Entry::EXCEPTION_SEC:
1230     case Entry::EXCEPTIONDOC_SEC:
1231       sec=ClassDef::Exception;
1232       break;
1233     case Entry::SERVICEDOC_SEC:
1234       sec=ClassDef::Service;
1235       break;
1236     case Entry::SINGLETONDOC_SEC:
1237       sec=ClassDef::Singleton;
1238       break;
1239   }
1240   return sec;
1241 }
1242
1243
1244 static void addClassToContext(EntryNav *rootNav)
1245 {
1246   //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1247   rootNav->loadEntry(g_storage);
1248   Entry *root = rootNav->entry();
1249
1250   //NamespaceDef *nd = 0;
1251   FileDef *fd = rootNav->fileDef();
1252
1253   QCString scName;
1254   if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1255   {
1256      scName=rootNav->parent()->name();
1257   }
1258   // name without parent's scope
1259   QCString fullName = root->name;
1260
1261   // strip off any template parameters (but not those for specializations)
1262   fullName=stripTemplateSpecifiersFromScope(fullName);
1263
1264   // name with scope (if not present already)
1265   QCString qualifiedName = fullName;
1266   if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1267   {
1268     qualifiedName.prepend(scName+"::");
1269   }
1270
1271   // see if we already found the class before
1272   ClassDef *cd = getClass(qualifiedName);
1273
1274   Debug::print(Debug::Classes,0, "  Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1275       cd ? qPrint(cd->name()) : qPrint(root->name), qPrint(qualifiedName),cd);
1276
1277   if (cd)
1278   {
1279     fullName=cd->name();
1280     Debug::print(Debug::Classes,0,"  Existing class %s!\n",qPrint(cd->name()));
1281     //if (cd->templateArguments()==0)
1282     //{
1283     //  //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1284     //  cd->setTemplateArguments(tArgList);
1285     //}
1286
1287     cd->setDocumentation(root->doc,root->docFile,root->docLine);
1288     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1289
1290     if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1291     {
1292       cd->setBodySegment(root->bodyLine,root->endBodyLine);
1293       cd->setBodyDef(fd);
1294     }
1295     //cd->setName(fullName); // change name to match docs
1296
1297     if (cd->templateArguments()==0 || (cd->isForwardDeclared() && (root->spec&Entry::ForwardDecl)==0))
1298     {
1299       // this happens if a template class declared with @class is found
1300       // before the actual definition or if a forward declaration has different template
1301       // parameter names.
1302       ArgumentList *tArgList =
1303         getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1304       cd->setTemplateArguments(tArgList);
1305     }
1306
1307     cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1308
1309     cd->setMetaData(root->metaData);
1310   }
1311   else // new class
1312   {
1313     ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1314
1315     QCString className;
1316     QCString namespaceName;
1317     extractNamespaceName(fullName,className,namespaceName);
1318
1319     //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1320     //    fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1321
1322     QCString tagName;
1323     QCString refFileName;
1324     TagInfo *tagInfo = rootNav->tagInfo();
1325     int i;
1326     if (tagInfo)
1327     {
1328       tagName     = tagInfo->tagName;
1329       refFileName = tagInfo->fileName;
1330       if (fullName.find("::")!=-1)
1331         // symbols imported via tag files may come without the parent scope,
1332         // so we artificially create it here
1333       {
1334         buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1335       }
1336     }
1337     ArgumentList *tArgList = 0;
1338     if ((root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java) && (i=fullName.find('<'))!=-1)
1339     {
1340       // a Java/C# generic class looks like a C++ specialization, so we need to split the
1341       // name and template arguments here
1342       tArgList = new ArgumentList;
1343       stringToArgumentList(fullName.mid(i),tArgList);
1344       fullName=fullName.left(i);
1345     }
1346     else
1347     {
1348       tArgList = getTemplateArgumentsFromName(fullName,root->tArgLists);
1349     }
1350     cd=new ClassDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn,
1351         fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1352     Debug::print(Debug::Classes,0,"  New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1353         qPrint(fullName),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
1354     cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1355     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1356     cd->setLanguage(root->lang);
1357     cd->setId(root->id);
1358     cd->setHidden(root->hidden);
1359     cd->setArtificial(root->artificial);
1360     cd->setClassSpecifier(root->spec);
1361     cd->setTypeConstraints(root->typeConstr);
1362     //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1363
1364     //printf("class %s template args=%s\n",fullName.data(),
1365     //    tArgList ? tempArgListToString(tArgList,root->lang).data() : "<none>");
1366     cd->setTemplateArguments(tArgList);
1367     cd->setProtection(root->protection);
1368     cd->setIsStatic(root->stat);
1369
1370     // file definition containing the class cd
1371     cd->setBodySegment(root->bodyLine,root->endBodyLine);
1372     cd->setBodyDef(fd);
1373
1374     cd->setMetaData(root->metaData);
1375
1376     // see if the class is found inside a namespace
1377     //bool found=addNamespace(root,cd);
1378
1379     cd->insertUsedFile(fd);
1380
1381     // add class to the list
1382     //printf("ClassDict.insert(%s)\n",fullName.data());
1383     Doxygen::classSDict->append(fullName,cd);
1384
1385     if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1386     {
1387       //printf("inserting generic '%s' cd=%p\n",fullName.data(),cd);
1388       Doxygen::genericsDict->insert(fullName,cd);
1389     }
1390   }
1391
1392   cd->addSectionsToDefinition(root->anchors);
1393   if (!root->subGrouping) cd->setSubGrouping(FALSE);
1394   if (cd->hasDocumentation())
1395   {
1396     addIncludeFile(cd,fd,root);
1397   }
1398   if (fd && (root->section & Entry::COMPOUND_MASK))
1399   {
1400     //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1401     //    cd->name().data(),
1402     //    fd->name().data(),
1403     //    root->fileName.data()
1404     //   );
1405     cd->setFileDef(fd);
1406     fd->insertClass(cd);
1407   }
1408   addClassToGroups(root,cd);
1409   cd->setRefItems(root->sli);
1410
1411   rootNav->releaseEntry();
1412 }
1413
1414 //----------------------------------------------------------------------
1415 // build a list of all classes mentioned in the documentation
1416 // and all classes that have a documentation block before their definition.
1417 static void buildClassList(EntryNav *rootNav)
1418 {
1419   if (
1420         ((rootNav->section() & Entry::COMPOUND_MASK) ||
1421          rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1422      )
1423   {
1424     addClassToContext(rootNav);
1425   }
1426   RECURSE_ENTRYTREE(buildClassList,rootNav);
1427 }
1428
1429 static void buildClassDocList(EntryNav *rootNav)
1430 {
1431   if (
1432        (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1433      )
1434   {
1435     addClassToContext(rootNav);
1436   }
1437   RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1438 }
1439
1440 static void resolveClassNestingRelations()
1441 {
1442   ClassSDict::Iterator cli(*Doxygen::classSDict);
1443   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1444
1445   bool done=FALSE;
1446   int iteration=0;
1447   while (!done)
1448   {
1449     done=TRUE;
1450     ++iteration;
1451     ClassDef *cd=0;
1452     for (cli.toFirst();(cd=cli.current());++cli)
1453     {
1454       if (!cd->visited)
1455       {
1456         QCString name = stripAnonymousNamespaceScope(cd->name());
1457         //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1458         // also add class to the correct structural context
1459         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1460                                                  name,cd->getFileDef(),0);
1461         if (d)
1462         {
1463           //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1464           d->addInnerCompound(cd);
1465           cd->setOuterScope(d);
1466           cd->visited=TRUE;
1467           done=FALSE;
1468         }
1469         //else
1470         //{
1471         //  printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1472         //}
1473       }
1474     }
1475   }
1476
1477   //give warnings for unresolved compounds
1478   ClassDef *cd=0;
1479   for (cli.toFirst();(cd=cli.current());++cli)
1480   {
1481     if (!cd->visited)
1482     {
1483       QCString name = stripAnonymousNamespaceScope(cd->name());
1484       //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1485       /// create the scope artificially
1486       // anyway, so we can at least relate scopes properly.
1487       Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1488       if (d!=cd && !cd->getDefFileName().isEmpty())
1489                  // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1490                  // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1491                  // also avoid warning for stuff imported via a tagfile.
1492       {
1493         d->addInnerCompound(cd);
1494         cd->setOuterScope(d);
1495         warn(cd->getDefFileName(),cd->getDefLine(),
1496             "Internal inconsistency: scope for class %s not "
1497             "found!",name.data()
1498             );
1499       }
1500     }
1501   }
1502 }
1503
1504 void distributeClassGroupRelations()
1505 {
1506   //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
1507   //if (!inlineGroupedClasses) return;
1508   //printf("** distributeClassGroupRelations()\n");
1509
1510   ClassSDict::Iterator cli(*Doxygen::classSDict);
1511   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1512
1513   ClassDef *cd;
1514   for (cli.toFirst();(cd=cli.current());++cli)
1515   {
1516     //printf("Checking %s\n",cd->name().data());
1517     // distribute the group to nested classes as well
1518     if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1519     {
1520       //printf("  Candidate for merging\n");
1521       ClassSDict::Iterator ncli(*cd->getClassSDict());
1522       ClassDef *ncd;
1523       GroupDef *gd = cd->partOfGroups()->at(0);
1524       for (ncli.toFirst();(ncd=ncli.current());++ncli)
1525       {
1526         if (ncd->partOfGroups()==0)
1527         {
1528           //printf("  Adding %s to group '%s'\n",ncd->name().data(),
1529           //    gd->groupTitle());
1530           ncd->makePartOfGroup(gd);
1531           gd->addClass(ncd);
1532         }
1533       }
1534       cd->visited=TRUE; // only visit every class once
1535     }
1536   }
1537 }
1538
1539 //----------------------------
1540
1541 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1542 {
1543   QCString fullName = removeAnonymousScopes(templ->name());
1544   if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1545   fullName+="."+fieldName;
1546   ClassDef *cd = new ClassDef(templ->getDefFileName(),
1547                               templ->getDefLine(),
1548                               templ->getDefColumn(),
1549                               fullName,
1550                               templ->compoundType());
1551   cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1552   cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1553   cd->setLanguage(templ->getLanguage());
1554   cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1555   cd->setBodyDef(templ->getBodyDef());
1556
1557   cd->setOuterScope(rootCd->getOuterScope());
1558   if (rootCd->getOuterScope()!=Doxygen::globalScope)
1559   {
1560     rootCd->getOuterScope()->addInnerCompound(cd);
1561   }
1562
1563   FileDef *fd = templ->getFileDef();
1564   if (fd)
1565   {
1566     cd->setFileDef(fd);
1567     fd->insertClass(cd);
1568   }
1569   GroupList *groups = rootCd->partOfGroups();
1570   if ( groups!=0 )
1571   {
1572     GroupListIterator gli(*groups);
1573     GroupDef *gd;
1574     for (gli.toFirst();(gd=gli.current());++gli)
1575     {
1576       cd->makePartOfGroup(gd);
1577       gd->addClass(cd);
1578     }
1579   }
1580   //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1581   Doxygen::classSDict->append(fullName,cd);
1582
1583   MemberList *ml = templ->getMemberList(MemberListType_pubAttribs);
1584   if (ml)
1585   {
1586     MemberListIterator li(*ml);
1587     MemberDef *md;
1588     for (li.toFirst();(md=li.current());++li)
1589     {
1590       //printf("    Member %s type=%s\n",md->name().data(),md->typeString());
1591       MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1592                                      md->typeString(),md->name(),md->argsString(),md->excpString(),
1593                                      md->protection(),md->virtualness(),md->isStatic(),Member,
1594                                      md->memberType(),
1595                                      0,0,"");
1596       imd->setMemberClass(cd);
1597       imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1598       imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1599       imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1600       imd->setMemberSpecifiers(md->getMemberSpecifiers());
1601       imd->setMemberGroupId(md->getMemberGroupId());
1602       imd->setInitializer(md->initializer());
1603       imd->setMaxInitLines(md->initializerLines());
1604       imd->setBitfields(md->bitfieldString());
1605       imd->setLanguage(md->getLanguage());
1606       cd->insertMember(imd);
1607     }
1608   }
1609   return cd;
1610 }
1611
1612 /** Look through the members of class \a cd and its public members.
1613  *  If there is a member m of a tag less struct/union,
1614  *  then we create a duplicate of the struct/union with the name of the
1615  *  member to identify it.
1616  *  So if cd has name S, then the tag less struct/union will get name S.m
1617  *  Since tag less structs can be nested we need to call this function
1618  *  recursively. Later on we need to patch the member types so we keep
1619  *  track of the hierarchy of classes we create.
1620  */
1621 static void processTagLessClasses(ClassDef *rootCd,
1622                                   ClassDef *cd,
1623                                   ClassDef *tagParentCd,
1624                                   const QCString &prefix,int count)
1625 {
1626   //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1627   //printf("checking members for %s\n",cd->name().data());
1628   if (cd->getClassSDict())
1629   {
1630     MemberList *ml = cd->getMemberList(MemberListType_pubAttribs);
1631     if (ml)
1632     {
1633       MemberListIterator li(*ml);
1634       MemberDef *md;
1635       for (li.toFirst();(md=li.current());++li)
1636       {
1637         QCString type = md->typeString();
1638         if (type.find("::@")!=-1) // member of tag less struct/union
1639         {
1640           ClassSDict::Iterator it(*cd->getClassSDict());
1641           ClassDef *icd;
1642           for (it.toFirst();(icd=it.current());++it)
1643           {
1644             //printf("  member %s: type='%s'\n",md->name().data(),type.data());
1645             //printf("  comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1646             if (type.find(icd->name())!=-1) // matching tag less struct/union
1647             {
1648               QCString name = md->name();
1649               if (name.at(0)=='@') name = "__unnamed__";
1650               if (!prefix.isEmpty()) name.prepend(prefix+".");
1651               //printf("    found %s for class %s\n",name.data(),cd->name().data());
1652               ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1653               processTagLessClasses(rootCd,icd,ncd,name,count+1);
1654               //printf("    addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1655               tagParentCd->addTaggedInnerClass(ncd);
1656               ncd->setTagLessReference(icd);
1657
1658               // replace tag-less type for generated/original member
1659               // by newly created class name.
1660               // note the difference between changing cd and tagParentCd.
1661               // for the initial call this is the same pointer, but for
1662               // recursive calls cd is the original tag-less struct (of which
1663               // there is only one instance) and tagParentCd is the newly
1664               // generated tagged struct of which there can be multiple instances!
1665               MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1666               if (pml)
1667               {
1668                 MemberListIterator pli(*pml);
1669                 MemberDef *pmd;
1670                 for (pli.toFirst();(pmd=pli.current());++pli)
1671                 {
1672                   if (pmd->name()==md->name())
1673                   {
1674                     pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1675                     //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1676                   }
1677                 }
1678               }
1679             }
1680           }
1681         }
1682       }
1683     }
1684   }
1685 }
1686
1687 static void findTagLessClasses(ClassDef *cd)
1688 {
1689   if (cd->getClassSDict())
1690   {
1691     ClassSDict::Iterator it(*cd->getClassSDict());
1692     ClassDef *icd;
1693     for (it.toFirst();(icd=it.current());++it)
1694     {
1695       if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1696       {
1697         findTagLessClasses(icd);
1698       }
1699     }
1700   }
1701
1702   processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1703 }
1704
1705 static void findTagLessClasses()
1706 {
1707   ClassSDict::Iterator cli(*Doxygen::classSDict);
1708   ClassDef *cd;
1709   for (cli.toFirst();(cd=cli.current());++cli) // for each class
1710   {
1711     Definition *scope = cd->getOuterScope();
1712     if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1713     {
1714       findTagLessClasses(cd);
1715     }
1716   }
1717 }
1718
1719
1720 //----------------------------------------------------------------------
1721 // build a list of all namespaces mentioned in the documentation
1722 // and all namespaces that have a documentation block before their definition.
1723 static void buildNamespaceList(EntryNav *rootNav)
1724 {
1725   if (
1726        (rootNav->section()==Entry::NAMESPACE_SEC ||
1727         rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1728         rootNav->section()==Entry::PACKAGEDOC_SEC
1729        ) &&
1730        !rootNav->name().isEmpty()
1731      )
1732   {
1733     rootNav->loadEntry(g_storage);
1734     Entry *root = rootNav->entry();
1735
1736     //printf("** buildNamespaceList(%s)\n",root->name.data());
1737
1738     QCString fName = root->name;
1739     if (root->section==Entry::PACKAGEDOC_SEC)
1740     {
1741       fName=substitute(fName,".","::");
1742     }
1743
1744     QCString fullName = stripAnonymousNamespaceScope(fName);
1745     if (!fullName.isEmpty())
1746     {
1747       //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1748       //        root->fileName.data(), root->startLine);
1749       NamespaceDef *nd;
1750       if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1751       {
1752         nd->setDocumentation(root->doc,root->docFile,root->docLine);
1753         nd->setName(fullName); // change name to match docs
1754         nd->addSectionsToDefinition(root->anchors);
1755         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1756         if (nd->getLanguage()==SrcLangExt_Unknown)
1757         {
1758           nd->setLanguage(root->lang);
1759         }
1760         if (rootNav->tagInfo()==0) // if we found the namespace in a tag file
1761                                    // and also in a project file, then remove
1762                                    // the tag file reference
1763         {
1764           nd->setReference("");
1765           nd->setFileName(fullName);
1766         }
1767         nd->setMetaData(root->metaData);
1768
1769         // file definition containing the namespace nd
1770         FileDef *fd=rootNav->fileDef();
1771         // insert the namespace in the file definition
1772         if (fd) fd->insertNamespace(nd);
1773         addNamespaceToGroups(root,nd);
1774         nd->setRefItems(root->sli);
1775       }
1776       else // fresh namespace
1777       {
1778         QCString tagName;
1779         QCString tagFileName;
1780         TagInfo *tagInfo = rootNav->tagInfo();
1781         if (tagInfo)
1782         {
1783           tagName     = tagInfo->tagName;
1784           tagFileName = tagInfo->fileName;
1785         }
1786         //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1787         NamespaceDef *nd=new NamespaceDef(tagInfo?tagName:root->fileName,root->startLine,
1788                              root->startColumn,fullName,tagName,tagFileName,
1789                              root->type,root->spec&Entry::Published);
1790         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1791         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1792         nd->addSectionsToDefinition(root->anchors);
1793         nd->setHidden(root->hidden);
1794         nd->setArtificial(root->artificial);
1795         nd->setLanguage(root->lang);
1796         nd->setId(root->id);
1797         nd->setMetaData(root->metaData);
1798
1799         //printf("Adding namespace to group\n");
1800         addNamespaceToGroups(root,nd);
1801         nd->setRefItems(root->sli);
1802
1803         // file definition containing the namespace nd
1804         FileDef *fd=rootNav->fileDef();
1805         // insert the namespace in the file definition
1806         if (fd) fd->insertNamespace(nd);
1807
1808         // the empty string test is needed for extract all case
1809         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1810         nd->insertUsedFile(fd);
1811         nd->setBodySegment(root->bodyLine,root->endBodyLine);
1812         nd->setBodyDef(fd);
1813         // add class to the list
1814         Doxygen::namespaceSDict->inSort(fullName,nd);
1815
1816         // also add namespace to the correct structural context
1817         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName,0,tagInfo);
1818         //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1819         if (d==0) // we didn't find anything, create the scope artificially
1820                   // anyway, so we can at least relate scopes properly.
1821         {
1822           Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1823           d->addInnerCompound(nd);
1824           nd->setOuterScope(d);
1825           // TODO: Due to the order in which the tag file is written
1826           // a nested class can be found before its parent!
1827         }
1828         else
1829         {
1830           d->addInnerCompound(nd);
1831           nd->setOuterScope(d);
1832         }
1833       }
1834     }
1835
1836     rootNav->releaseEntry();
1837   }
1838   RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1839 }
1840
1841 //----------------------------------------------------------------------
1842
1843 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1844                               const QCString &name)
1845 {
1846   NamespaceDef *usingNd =0;
1847   if (unl)
1848   {
1849     //printf("Found namespace dict %d\n",unl->count());
1850     NamespaceSDict::Iterator unli(*unl);
1851     NamespaceDef *und;
1852     for (unli.toFirst();(und=unli.current());++unli)
1853     {
1854       QCString uScope=und->name()+"::";
1855       usingNd = getResolvedNamespace(uScope+name);
1856       //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1857     }
1858   }
1859   return usingNd;
1860 }
1861
1862 static void findUsingDirectives(EntryNav *rootNav)
1863 {
1864   if (rootNav->section()==Entry::USINGDIR_SEC)
1865   {
1866     rootNav->loadEntry(g_storage);
1867     Entry *root = rootNav->entry();
1868
1869     //printf("Found using directive %s at line %d of %s\n",
1870     //    root->name.data(),root->startLine,root->fileName.data());
1871     QCString name=substitute(root->name,".","::");
1872     if (name.right(2)=="::")
1873     {
1874       name=name.left(name.length()-2);
1875     }
1876     if (!name.isEmpty())
1877     {
1878       NamespaceDef *usingNd = 0;
1879       NamespaceDef *nd = 0;
1880       FileDef      *fd = rootNav->fileDef();
1881       QCString nsName;
1882
1883       // see if the using statement was found inside a namespace or inside
1884       // the global file scope.
1885       if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1886           (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1887          )
1888       {
1889         nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1890         if (!nsName.isEmpty())
1891         {
1892           nd = getResolvedNamespace(nsName);
1893         }
1894       }
1895
1896       // find the scope in which the `using' namespace is defined by prepending
1897       // the possible scopes in which the using statement was found, starting
1898       // with the most inner scope and going to the most outer scope (i.e.
1899       // file scope).
1900       int scopeOffset = nsName.length();
1901       do
1902       {
1903         QCString scope=scopeOffset>0 ?
1904                       nsName.left(scopeOffset)+"::" : QCString();
1905         usingNd = getResolvedNamespace(scope+name);
1906         //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1907         if (scopeOffset==0)
1908         {
1909           scopeOffset=-1;
1910         }
1911         else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1912         {
1913           scopeOffset=0;
1914         }
1915       } while (scopeOffset>=0 && usingNd==0);
1916
1917       if (usingNd==0 && nd) // not found, try used namespaces in this scope
1918                             // or in one of the parent namespace scopes
1919       {
1920         NamespaceDef *pnd = nd;
1921         while (pnd && usingNd==0)
1922         {
1923           // also try with one of the used namespaces found earlier
1924           usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1925
1926           // goto the parent
1927           Definition *s = pnd->getOuterScope();
1928           if (s && s->definitionType()==Definition::TypeNamespace)
1929           {
1930             pnd = (NamespaceDef*)s;
1931           }
1932           else
1933           {
1934             pnd = 0;
1935           }
1936         }
1937       }
1938       if (usingNd==0 && fd) // still nothing, also try used namespace in the
1939                             // global scope
1940       {
1941         usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1942       }
1943
1944       //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1945
1946       // add the namespace the correct scope
1947       if (usingNd)
1948       {
1949         //printf("using fd=%p nd=%p\n",fd,nd);
1950         if (nd)
1951         {
1952           //printf("Inside namespace %s\n",nd->name().data());
1953           nd->addUsingDirective(usingNd);
1954         }
1955         else if (fd)
1956         {
1957           //printf("Inside file %s\n",fd->name().data());
1958           fd->addUsingDirective(usingNd);
1959         }
1960       }
1961       else // unknown namespace, but add it anyway.
1962       {
1963         //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1964         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1965         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1966         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1967         nd->addSectionsToDefinition(root->anchors);
1968         //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1969         nd->setHidden(root->hidden);
1970         nd->setArtificial(TRUE);
1971         nd->setLanguage(root->lang);
1972         nd->setId(root->id);
1973         nd->setMetaData(root->metaData);
1974
1975         QListIterator<Grouping> gli(*root->groups);
1976         Grouping *g;
1977         for (;(g=gli.current());++gli)
1978         {
1979           GroupDef *gd=0;
1980           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1981             gd->addNamespace(nd);
1982         }
1983
1984         // insert the namespace in the file definition
1985         if (fd)
1986         {
1987           fd->insertNamespace(nd);
1988           fd->addUsingDirective(nd);
1989         }
1990
1991         // the empty string test is needed for extract all case
1992         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1993         nd->insertUsedFile(fd);
1994         // add class to the list
1995         Doxygen::namespaceSDict->inSort(name,nd);
1996         nd->setRefItems(root->sli);
1997       }
1998     }
1999
2000     rootNav->releaseEntry();
2001   }
2002   RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
2003 }
2004
2005 //----------------------------------------------------------------------
2006
2007 static void buildListOfUsingDecls(EntryNav *rootNav)
2008 {
2009   if (rootNav->section()==Entry::USINGDECL_SEC &&
2010       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2011      )
2012   {
2013     rootNav->loadEntry(g_storage);
2014     Entry *root = rootNav->entry();
2015
2016     QCString name = substitute(root->name,".","::");
2017
2018     if (g_usingDeclarations.find(name)==0)
2019     {
2020       FileDef *fd = rootNav->fileDef();
2021       if (fd)
2022       {
2023         g_usingDeclarations.insert(name,fd);
2024       }
2025     }
2026
2027     rootNav->releaseEntry();
2028   }
2029   RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
2030 }
2031
2032
2033 static void findUsingDeclarations(EntryNav *rootNav)
2034 {
2035   if (rootNav->section()==Entry::USINGDECL_SEC &&
2036       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2037      )
2038   {
2039     rootNav->loadEntry(g_storage);
2040     Entry *root = rootNav->entry();
2041
2042     //printf("Found using declaration %s at line %d of %s inside section %x\n",
2043     //   root->name.data(),root->startLine,root->fileName.data(),
2044     //   rootNav->parent()->section());
2045     if (!root->name.isEmpty())
2046     {
2047       ClassDef *usingCd = 0;
2048       NamespaceDef *nd = 0;
2049       FileDef      *fd = rootNav->fileDef();
2050       QCString scName;
2051
2052       // see if the using statement was found inside a namespace or inside
2053       // the global file scope.
2054       if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
2055       {
2056         scName=rootNav->parent()->name();
2057         if (!scName.isEmpty())
2058         {
2059           nd = getResolvedNamespace(scName);
2060         }
2061       }
2062
2063       // Assume the using statement was used to import a class.
2064       // Find the scope in which the `using' namespace is defined by prepending
2065       // the possible scopes in which the using statement was found, starting
2066       // with the most inner scope and going to the most outer scope (i.e.
2067       // file scope).
2068
2069       QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2070       usingCd = getClass(name); // try direct lookup first, this is needed to get
2071                                 // builtin STL classes to properly resolve, e.g.
2072                                 // vector -> std::vector
2073       if (usingCd==0)
2074       {
2075         usingCd = getResolvedClass(nd,fd,name); // try via resolving (see also bug757509)
2076       }
2077       if (usingCd==0)
2078       {
2079         usingCd = Doxygen::hiddenClasses->find(name); // check if it is already hidden
2080       }
2081
2082       //printf("%s -> %p\n",root->name.data(),usingCd);
2083       if (usingCd==0) // definition not in the input => add an artificial class
2084       {
2085         Debug::print(Debug::Classes,0,"  New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
2086              qPrint(name),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
2087         usingCd = new ClassDef(
2088                      "<using>",1,1,
2089                      name,
2090                      ClassDef::Class);
2091         Doxygen::hiddenClasses->append(root->name,usingCd);
2092         usingCd->setArtificial(TRUE);
2093         usingCd->setLanguage(root->lang);
2094       }
2095       else
2096       {
2097         Debug::print(Debug::Classes,0,"  Found used class %s in scope=%s\n",
2098             qPrint(usingCd->name()),
2099                         nd?qPrint(nd->name()):
2100                         fd?qPrint(fd->name()):
2101                         "<unknown>");
2102       }
2103
2104       if (nd)
2105       {
2106         //printf("Inside namespace %s\n",nd->name().data());
2107         nd->addUsingDeclaration(usingCd);
2108       }
2109       else if (fd)
2110       {
2111         //printf("Inside file %s\n",fd->name().data());
2112         fd->addUsingDeclaration(usingCd);
2113       }
2114     }
2115
2116     rootNav->releaseEntry();
2117   }
2118   RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
2119 }
2120
2121 //----------------------------------------------------------------------
2122
2123 static void findUsingDeclImports(EntryNav *rootNav)
2124 {
2125   if (rootNav->section()==Entry::USINGDECL_SEC &&
2126       (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
2127      )
2128   {
2129     //printf("Found using declaration %s inside section %x\n",
2130     //    rootNav->name().data(), rootNav->parent()->section());
2131     QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
2132     fullName=stripAnonymousNamespaceScope(fullName);
2133     fullName=stripTemplateSpecifiersFromScope(fullName);
2134     ClassDef *cd = getClass(fullName);
2135     if (cd)
2136     {
2137       //printf("found class %s\n",cd->name().data());
2138       int i=rootNav->name().find("::");
2139       if (i!=-1)
2140       {
2141         QCString scope=rootNav->name().left(i);
2142         QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
2143         ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2144         if (bcd)
2145         {
2146           //printf("found class %s memName=%s\n",bcd->name().data(),memName.data());
2147           MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2148           if (mndict)
2149           {
2150             MemberNameInfo *mni = mndict->find(memName);
2151             if (mni)
2152             {
2153               MemberNameInfoIterator mnii(*mni);
2154               MemberInfo *mi;
2155               for ( ; (mi=mnii.current()) ; ++mnii )
2156               {
2157                 MemberDef *md = mi->memberDef;
2158                 if (md && md->protection()!=Private)
2159                 {
2160
2161                   rootNav->loadEntry(g_storage);
2162                   Entry *root = rootNav->entry();
2163
2164                   //printf("found member %s\n",mni->memberName());
2165                   MemberDef *newMd = 0;
2166                   {
2167                     QCString fileName = root->fileName;
2168                     if (fileName.isEmpty() && rootNav->tagInfo())
2169                     {
2170                       fileName = rootNav->tagInfo()->tagName;
2171                     }
2172                     ArgumentList *templAl = md->templateArguments();
2173                     ArgumentList *al = md->templateArguments();
2174                     newMd = new MemberDef(
2175                       fileName,root->startLine,root->startColumn,
2176                       md->typeString(),memName,md->argsString(),
2177                       md->excpString(),root->protection,root->virt,
2178                       md->isStatic(),Member,md->memberType(),
2179                       templAl,al,root->metaData
2180                       );
2181                   }
2182                   newMd->setMemberClass(cd);
2183                   cd->insertMember(newMd);
2184                   if (!root->doc.isEmpty() || !root->brief.isEmpty())
2185                   {
2186                     newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2187                     newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2188                     newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2189                   }
2190                   else
2191                   {
2192                     newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2193                     newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2194                     newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2195                   }
2196                   newMd->setDefinition(md->definition());
2197                   newMd->enableCallGraph(root->callGraph);
2198                   newMd->enableCallerGraph(root->callerGraph);
2199                   newMd->enableReferencedByRelation(root->referencedByRelation);
2200                   newMd->enableReferencesRelation(root->referencesRelation);
2201                   newMd->setBitfields(md->bitfieldString());
2202                   newMd->addSectionsToDefinition(root->anchors);
2203                   newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2204                   newMd->setBodyDef(md->getBodyDef());
2205                   newMd->setInitializer(md->initializer());
2206                   newMd->setMaxInitLines(md->initializerLines());
2207                   newMd->setMemberGroupId(root->mGrpId);
2208                   newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2209                   newMd->setLanguage(root->lang);
2210                   newMd->setId(root->id);
2211
2212                   rootNav->releaseEntry();
2213                 }
2214               }
2215             }
2216           }
2217         }
2218       }
2219     }
2220
2221   }
2222   RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2223 }
2224
2225 //----------------------------------------------------------------------
2226
2227 static void findIncludedUsingDirectives()
2228 {
2229   // first mark all files as not visited
2230   FileNameListIterator fnli(*Doxygen::inputNameList);
2231   FileName *fn;
2232   for (fnli.toFirst();(fn=fnli.current());++fnli)
2233   {
2234     FileNameIterator fni(*fn);
2235     FileDef *fd;
2236     for (;(fd=fni.current());++fni)
2237     {
2238       fd->visited=FALSE;
2239     }
2240   }
2241   // then recursively add using directives found in #include files
2242   // to files that have not been visited.
2243   for (fnli.toFirst();(fn=fnli.current());++fnli)
2244   {
2245     FileNameIterator fni(*fn);
2246     FileDef *fd;
2247     for (fni.toFirst();(fd=fni.current());++fni)
2248     {
2249       if (!fd->visited)
2250       {
2251         //printf("----- adding using directives for file %s\n",fd->name().data());
2252         fd->addIncludedUsingDirectives();
2253       }
2254     }
2255   }
2256 }
2257
2258 //----------------------------------------------------------------------
2259
2260 static MemberDef *addVariableToClass(
2261     EntryNav *rootNav,
2262     ClassDef *cd,
2263     MemberType mtype,
2264     const QCString &name,
2265     bool fromAnnScope,
2266     MemberDef *fromAnnMemb,
2267     Protection prot,
2268     Relationship related)
2269 {
2270   Entry *root = rootNav->entry();
2271
2272   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2273   QCString scopeSeparator="::";
2274   SrcLangExt lang = cd->getLanguage();
2275   if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2276   {
2277     qualScope = substitute(qualScope,"::",".");
2278     scopeSeparator=".";
2279   }
2280   Debug::print(Debug::Variables,0,
2281       "  class variable:\n"
2282       "    `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2283       qPrint(root->type),
2284       qPrint(qualScope),
2285       qPrint(name),
2286       qPrint(root->args),
2287       root->protection,
2288       fromAnnScope,
2289       qPrint(root->initializer)
2290               );
2291
2292   QCString def;
2293   if (!root->type.isEmpty())
2294   {
2295     if (related || mtype==MemberType_Friend || Config_getBool(HIDE_SCOPE_NAMES))
2296     {
2297       if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2298       {
2299         def="using "+name+" = "+root->type.mid(7);
2300       }
2301       else
2302       {
2303         def=root->type+" "+name+root->args;
2304       }
2305     }
2306     else
2307     {
2308       if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2309       {
2310         def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2311       }
2312       else
2313       {
2314         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2315       }
2316     }
2317   }
2318   else
2319   {
2320     if (Config_getBool(HIDE_SCOPE_NAMES))
2321     {
2322       def=name+root->args;
2323     }
2324     else
2325     {
2326       def=qualScope+scopeSeparator+name+root->args;
2327     }
2328   }
2329   def.stripPrefix("static ");
2330
2331   // see if the member is already found in the same scope
2332   // (this may be the case for a static member that is initialized
2333   //  outside the class)
2334   MemberName *mn=Doxygen::memberNameSDict->find(name);
2335   if (mn)
2336   {
2337     MemberNameIterator mni(*mn);
2338     MemberDef *md;
2339     for (mni.toFirst();(md=mni.current());++mni)
2340     {
2341       //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2342       //    md->getClassDef(),cd,root->type.data(),md->typeString());
2343       if (md->getClassDef()==cd &&
2344           removeRedundantWhiteSpace(root->type)==md->typeString())
2345         // member already in the scope
2346       {
2347
2348         if (root->lang==SrcLangExt_ObjC &&
2349             root->mtype==Property &&
2350             md->memberType()==MemberType_Variable)
2351         { // Objective-C 2.0 property
2352           // turn variable into a property
2353           md->setProtection(root->protection);
2354           cd->reclassifyMember(md,MemberType_Property);
2355         }
2356         addMemberDocs(rootNav,md,def,0,FALSE);
2357         //printf("    Member already found!\n");
2358         return md;
2359       }
2360     }
2361   }
2362
2363   QCString fileName = root->fileName;
2364   if (fileName.isEmpty() && rootNav->tagInfo())
2365   {
2366     fileName = rootNav->tagInfo()->tagName;
2367   }
2368
2369   // new member variable, typedef or enum value
2370   MemberDef *md=new MemberDef(
2371       fileName,root->startLine,root->startColumn,
2372       root->type,name,root->args,root->exception,
2373       prot,Normal,root->stat,related,
2374       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0, root->metaData);
2375   md->setTagInfo(rootNav->tagInfo());
2376   md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2377   //md->setDefFile(root->fileName);
2378   //md->setDefLine(root->startLine);
2379   md->setDocumentation(root->doc,root->docFile,root->docLine);
2380   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2381   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2382   md->setDefinition(def);
2383   md->setBitfields(root->bitfields);
2384   md->addSectionsToDefinition(root->anchors);
2385   md->setFromAnonymousScope(fromAnnScope);
2386   md->setFromAnonymousMember(fromAnnMemb);
2387   //md->setIndentDepth(indentDepth);
2388   md->setBodySegment(root->bodyLine,root->endBodyLine);
2389   md->setInitializer(root->initializer);
2390   md->setMaxInitLines(root->initLines);
2391   md->setMemberGroupId(root->mGrpId);
2392   md->setMemberSpecifiers(root->spec);
2393   md->setReadAccessor(root->read);
2394   md->setWriteAccessor(root->write);
2395   md->enableCallGraph(root->callGraph);
2396   md->enableCallerGraph(root->callerGraph);
2397   md->enableReferencedByRelation(root->referencedByRelation);
2398   md->enableReferencesRelation(root->referencesRelation);
2399   md->setHidden(root->hidden);
2400   md->setArtificial(root->artificial);
2401   md->setLanguage(root->lang);
2402   md->setId(root->id);
2403   addMemberToGroups(root,md);
2404   //if (root->mGrpId!=-1)
2405   //{
2406   //  printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2407   //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
2408   //
2409   md->setBodyDef(rootNav->fileDef());
2410
2411   //printf("    Adding member=%s\n",md->name().data());
2412   // add the member to the global list
2413   if (mn)
2414   {
2415     mn->append(md);
2416   }
2417   else // new variable name
2418   {
2419     mn = new MemberName(name);
2420     mn->append(md);
2421     //printf("Adding memberName=%s\n",mn->memberName());
2422     //Doxygen::memberNameDict.insert(name,mn);
2423     //Doxygen::memberNameList.append(mn);
2424     Doxygen::memberNameSDict->append(name,mn);
2425     // add the member to the class
2426   }
2427   //printf("    New member adding to %s (%p)!\n",cd->name().data(),cd);
2428   cd->insertMember(md);
2429   md->setRefItems(root->sli);
2430
2431   //TODO: insert FileDef instead of filename strings.
2432   cd->insertUsedFile(rootNav->fileDef());
2433   rootNav->changeSection(Entry::EMPTY_SEC);
2434   return md;
2435 }
2436
2437 //----------------------------------------------------------------------
2438
2439 static MemberDef *addVariableToFile(
2440     EntryNav *rootNav,
2441     MemberType mtype,
2442     const QCString &scope,
2443     const QCString &name,
2444     bool fromAnnScope,
2445     /*int indentDepth,*/
2446     MemberDef *fromAnnMemb)
2447 {
2448   Entry *root = rootNav->entry();
2449   Debug::print(Debug::Variables,0,
2450       "  global variable:\n"
2451       "    type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2452       qPrint(root->type),
2453       qPrint(scope),
2454       qPrint(name),
2455       qPrint(root->args),
2456       root->protection,
2457       mtype,
2458       root->lang
2459               );
2460
2461   FileDef *fd = rootNav->fileDef();
2462
2463   // see if we have a typedef that should hide a struct or union
2464   if (mtype==MemberType_Typedef && Config_getBool(TYPEDEF_HIDES_STRUCT))
2465   {
2466     QCString type = root->type;
2467     type.stripPrefix("typedef ");
2468     if (type.left(7)=="struct " || type.left(6)=="union ")
2469     {
2470       type.stripPrefix("struct ");
2471       type.stripPrefix("union ");
2472       static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2473       int l,s;
2474       s = re.match(type,0,&l);
2475       if (s>=0)
2476       {
2477         QCString typeValue = type.mid(s,l);
2478         ClassDef *cd = getClass(typeValue);
2479         if (cd)
2480         {
2481           // this typedef should hide compound name cd, so we
2482           // change the name that is displayed from cd.
2483           cd->setClassName(name);
2484           cd->setDocumentation(root->doc,root->docFile,root->docLine);
2485           cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2486           return 0;
2487         }
2488       }
2489     }
2490   }
2491
2492   // see if the function is inside a namespace
2493   NamespaceDef *nd = 0;
2494   if (!scope.isEmpty())
2495   {
2496     if (scope.find('@')!=-1) return 0; // anonymous scope!
2497     //nscope=removeAnonymousScopes(scope);
2498     //if (!nscope.isEmpty())
2499     //{
2500     nd = getResolvedNamespace(scope);
2501     //}
2502   }
2503   QCString def;
2504
2505   // determine the definition of the global variable
2506   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' &&
2507       !Config_getBool(HIDE_SCOPE_NAMES)
2508      )
2509     // variable is inside a namespace, so put the scope before the name
2510   {
2511     SrcLangExt lang = nd->getLanguage();
2512     QCString sep=getLanguageSpecificSeparator(lang);
2513
2514     if (!root->type.isEmpty())
2515     {
2516       if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2517       {
2518         def="using "+nd->name()+sep+name+" = "+root->type;
2519       }
2520       else // normal member
2521       {
2522         def=root->type+" "+nd->name()+sep+name+root->args;
2523       }
2524     }
2525     else
2526     {
2527       def=nd->name()+sep+name+root->args;
2528     }
2529   }
2530   else
2531   {
2532     if (!root->type.isEmpty() && !root->name.isEmpty())
2533     {
2534       if (name.at(0)=='@') // dummy variable representing anonymous union
2535       {
2536         def=root->type;
2537       }
2538       else
2539       {
2540         if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2541         {
2542           def="using "+root->name+" = "+root->type.mid(7);
2543         }
2544         else // normal member
2545         {
2546           def=root->type+" "+name+root->args;
2547         }
2548       }
2549     }
2550     else
2551     {
2552       def=name+root->args;
2553     }
2554   }
2555   def.stripPrefix("static ");
2556
2557   MemberName *mn=Doxygen::functionNameSDict->find(name);
2558   if (mn)
2559   {
2560     //QCString nscope=removeAnonymousScopes(scope);
2561     //NamespaceDef *nd=0;
2562     //if (!nscope.isEmpty())
2563     if (!scope.isEmpty())
2564     {
2565       nd = getResolvedNamespace(scope);
2566     }
2567     MemberNameIterator mni(*mn);
2568     MemberDef *md;
2569     for (mni.toFirst();(md=mni.current());++mni)
2570     {
2571       if (
2572           ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2573             root->fileName==md->getFileDef()->absFilePath()
2574            ) // both variable names in the same file
2575            || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2576           )
2577           && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2578           && !md->isEnumerate() // in C# an enum value and enum can have the same name
2579          )
2580         // variable already in the scope
2581       {
2582         bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2583                           md->argsString()!=root->args &&
2584                           root->args.find('[')!=-1;
2585         bool staticsInDifferentFiles =
2586                           root->stat && md->isStatic() &&
2587                           root->fileName!=md->getDefFileName();
2588
2589         if (md->getFileDef() &&
2590             !isPHPArray && // not a php array
2591             !staticsInDifferentFiles
2592            )
2593           // not a php array variable
2594         {
2595
2596           Debug::print(Debug::Variables,0,
2597               "    variable already found: scope=%s\n",qPrint(md->getOuterScope()->name()));
2598           addMemberDocs(rootNav,md,def,0,FALSE);
2599           md->setRefItems(root->sli);
2600           return md;
2601         }
2602       }
2603     }
2604   }
2605
2606   QCString fileName = root->fileName;
2607   if (fileName.isEmpty() && rootNav->tagInfo())
2608   {
2609     fileName = rootNav->tagInfo()->tagName;
2610   }
2611
2612   Debug::print(Debug::Variables,0,
2613     "    new variable, nd=%s tagInfo=%p!\n",nd?qPrint(nd->name()):"<global>",rootNav->tagInfo());
2614   // new global variable, enum value or typedef
2615   MemberDef *md=new MemberDef(
2616       fileName,root->startLine,root->startColumn,
2617       root->type,name,root->args,0,
2618       root->protection, Normal,root->stat,Member,
2619       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0, root->metaData);
2620   md->setTagInfo(rootNav->tagInfo());
2621   md->setMemberSpecifiers(root->spec);
2622   md->setDocumentation(root->doc,root->docFile,root->docLine);
2623   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2624   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2625   md->addSectionsToDefinition(root->anchors);
2626   md->setFromAnonymousScope(fromAnnScope);
2627   md->setFromAnonymousMember(fromAnnMemb);
2628   md->setInitializer(root->initializer);
2629   md->setMaxInitLines(root->initLines);
2630   md->setMemberGroupId(root->mGrpId);
2631   md->setDefinition(def);
2632   md->setLanguage(root->lang);
2633   md->setId(root->id);
2634   md->enableCallGraph(root->callGraph);
2635   md->enableCallerGraph(root->callerGraph);
2636   md->enableReferencedByRelation(root->referencedByRelation);
2637   md->enableReferencesRelation(root->referencesRelation);
2638   md->setExplicitExternal(root->explicitExternal);
2639   //md->setOuterScope(fd);
2640   if (!root->explicitExternal)
2641   {
2642     md->setBodySegment(root->bodyLine,root->endBodyLine);
2643     md->setBodyDef(fd);
2644   }
2645   addMemberToGroups(root,md);
2646
2647   md->setRefItems(root->sli);
2648   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2649   {
2650     md->setNamespace(nd);
2651     nd->insertMember(md);
2652   }
2653
2654   // add member to the file (we do this even if we have already inserted
2655   // it into the namespace.
2656   if (fd)
2657   {
2658     md->setFileDef(fd);
2659     fd->insertMember(md);
2660   }
2661
2662   // add member definition to the list of globals
2663   if (mn)
2664   {
2665     mn->append(md);
2666   }
2667   else
2668   {
2669     mn = new MemberName(name);
2670     mn->append(md);
2671     Doxygen::functionNameSDict->append(name,mn);
2672   }
2673   rootNav->changeSection(Entry::EMPTY_SEC);
2674   return md;
2675 }
2676
2677 /*! See if the return type string \a type is that of a function pointer
2678  *  \returns -1 if this is not a function pointer variable or
2679  *           the index at which the closing brace of (...*name) was found.
2680  */
2681 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2682 {
2683   if (lang == SrcLangExt_Fortran || lang == SrcLangExt_VHDL)
2684   {
2685     return -1; // Fortran and VHDL do not have function pointers
2686   }
2687   static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2688   int i=-1,l;
2689   int bb=type.find('<');
2690   int be=type.findRev('>');
2691   if (!type.isEmpty() &&             // return type is non-empty
2692       (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2693       type.find("operator")==-1 &&   // not an operator
2694       (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2695                                     // not a function pointer return type
2696       !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2697      )
2698   {
2699     if (pLength) *pLength=l;
2700     //printf("findFunctionPtr=%d\n",i);
2701     return i;
2702   }
2703   else
2704   {
2705     //printf("findFunctionPtr=%d\n",-1);
2706     return -1;
2707   }
2708 }
2709
2710
2711 /*! Returns TRUE iff \a type is a class within scope \a context.
2712  *  Used to detect variable declarations that look like function prototypes.
2713  */
2714 static bool isVarWithConstructor(EntryNav *rootNav)
2715 {
2716   static QRegExp initChars("[0-9\"'&*!^]+");
2717   static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2718   bool result=FALSE;
2719   bool typeIsClass;
2720   QCString type;
2721   Definition *ctx = 0;
2722   FileDef *fd = 0;
2723   int ti;
2724
2725   //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2726   rootNav->loadEntry(g_storage);
2727   Entry *root = rootNav->entry();
2728
2729   if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2730   { // inside a class
2731     result=FALSE;
2732     goto done;
2733   }
2734   else if ((fd = rootNav->fileDef()) &&
2735             (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2736           )
2737   { // inside a .c file
2738     result=FALSE;
2739     goto done;
2740   }
2741   if (root->type.isEmpty())
2742   {
2743     result=FALSE;
2744     goto done;
2745   }
2746   if (!rootNav->parent()->name().isEmpty())
2747   {
2748     ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2749   }
2750   type = root->type;
2751   // remove qualifiers
2752   findAndRemoveWord(type,"const");
2753   findAndRemoveWord(type,"static");
2754   findAndRemoveWord(type,"volatile");
2755   //if (type.left(6)=="const ") type=type.right(type.length()-6);
2756   typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2757   if (!typeIsClass && (ti=type.find('<'))!=-1)
2758   {
2759     typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2760   }
2761   if (typeIsClass) // now we still have to check if the arguments are
2762                    // types or values. Since we do not have complete type info
2763                    // we need to rely on heuristics :-(
2764   {
2765     //printf("typeIsClass\n");
2766     ArgumentList *al = root->argList;
2767     if (al==0 || al->isEmpty())
2768     {
2769       result=FALSE; // empty arg list -> function prototype.
2770       goto done;
2771     }
2772     ArgumentListIterator ali(*al);
2773     Argument *a;
2774     for (ali.toFirst();(a=ali.current());++ali)
2775     {
2776       if (!a->name.isEmpty() || !a->defval.isEmpty())
2777       {
2778         if (a->name.find(initChars)==0)
2779         {
2780           result=TRUE;
2781         }
2782         else
2783         {
2784           result=FALSE; // arg has (type,name) pair -> function prototype
2785         }
2786         goto done;
2787       }
2788       if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0)
2789       {
2790         result=FALSE; // arg type is a known type
2791         goto done;
2792       }
2793       if (checkIfTypedef(ctx,fd,a->type))
2794       {
2795          //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2796          result=FALSE; // argument is a typedef
2797          goto done;
2798       }
2799       if (a->type.at(a->type.length()-1)=='*' ||
2800           a->type.at(a->type.length()-1)=='&')
2801                      // type ends with * or & => pointer or reference
2802       {
2803         result=FALSE;
2804         goto done;
2805       }
2806       if (a->type.find(initChars)==0)
2807       {
2808         result=TRUE; // argument type starts with typical initializer char
2809         goto done;
2810       }
2811       QCString resType=resolveTypeDef(ctx,a->type);
2812       if (resType.isEmpty()) resType=a->type;
2813       int len;
2814       if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2815       {
2816         resType=resType.left(len);
2817         //printf("resType=%s\n",resType.data());
2818         if (resType=="int"    || resType=="long" || resType=="float" ||
2819             resType=="double" || resType=="char" || resType=="signed" ||
2820             resType=="const"  || resType=="unsigned" || resType=="void")
2821         {
2822           result=FALSE; // type keyword -> function prototype
2823           goto done;
2824         }
2825       }
2826     }
2827     result=TRUE;
2828   }
2829
2830 done:
2831   //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2832   //                                          root->type.data(),result);
2833   rootNav->releaseEntry();
2834   return result;
2835 }
2836
2837 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2838 {
2839     static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE);
2840
2841     rootNav->loadEntry(g_storage);
2842     Entry *root = rootNav->entry();
2843
2844     Debug::print(Debug::Variables,0,
2845                   "VARIABLE_SEC: \n"
2846                   "  type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2847                    qPrint(root->type),
2848                    qPrint(root->name),
2849                    qPrint(root->args),
2850                    root->bodyLine,
2851                    root->mGrpId,
2852                    qPrint(root->relates)
2853                 );
2854     //printf("root->parent->name=%s\n",root->parent->name.data());
2855
2856     if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2857         (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2858     {
2859       // recover from parse error caused by redundant braces
2860       // like in "int *(var[10]);", which is parsed as
2861       // type="" name="int *" args="(var[10])"
2862
2863       root->type=root->name;
2864       static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2865       int l=0;
2866       int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2867       if (i!=-1)
2868       {
2869         root->name=root->args.mid(i,l);
2870         root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2871       }
2872       //printf("new: type=`%s' name=`%s' args=`%s'\n",
2873       //    root->type.data(),root->name.data(),root->args.data());
2874     }
2875     else
2876     {
2877       int i=isFuncPtr;
2878       if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2879       Debug::print(Debug::Variables,0,"  functionPtr? %s\n",i!=-1?"yes":"no");
2880       if (i!=-1) // function pointer
2881       {
2882         int ai = root->type.find('[',i);
2883         if (ai>i) // function pointer array
2884         {
2885           root->args.prepend(root->type.right(root->type.length()-ai));
2886           root->type=root->type.left(ai);
2887         }
2888         else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2889         {
2890           root->type=root->type.left(root->type.length()-1);
2891           root->args.prepend(") ");
2892           //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2893         }
2894       }
2895     }
2896
2897     QCString scope,name=removeRedundantWhiteSpace(root->name);
2898
2899     // find the scope of this variable
2900     EntryNav *p = rootNav->parent();
2901     while ((p->section() & Entry::SCOPE_MASK))
2902     {
2903       QCString scopeName = p->name();
2904       if (!scopeName.isEmpty())
2905       {
2906         scope.prepend(scopeName);
2907         break;
2908       }
2909       p=p->parent();
2910     }
2911
2912     MemberType mtype;
2913     QCString type=root->type.stripWhiteSpace();
2914     ClassDef *cd=0;
2915     bool isRelated=FALSE;
2916     bool isMemberOf=FALSE;
2917
2918     QCString classScope=stripAnonymousNamespaceScope(scope);
2919     classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2920     QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2921
2922     if (root->name.findRev("::")!=-1)
2923     {
2924       if (root->type=="friend class" || root->type=="friend struct" ||
2925           root->type=="friend union")
2926       {
2927          cd=getClass(scope);
2928          if (cd)
2929          {
2930            addVariableToClass(rootNav,  // entry
2931                               cd,    // class to add member to
2932                               MemberType_Friend, // type of member
2933                               name, // name of the member
2934                               FALSE,  // from Anonymous scope
2935                               0,      // anonymous member
2936                               Public, // protection
2937                               Member  // related to a class
2938                              );
2939          }
2940       }
2941       goto nextMember;
2942                /* skip this member, because it is a
2943                 * static variable definition (always?), which will be
2944                 * found in a class scope as well, but then we know the
2945                 * correct protection level, so only then it will be
2946                 * inserted in the correct list!
2947                 */
2948     }
2949
2950     if (type=="@")
2951       mtype=MemberType_EnumValue;
2952     else if (type.left(8)=="typedef ")
2953       mtype=MemberType_Typedef;
2954     else if (type.left(7)=="friend ")
2955       mtype=MemberType_Friend;
2956     else if (root->mtype==Property)
2957       mtype=MemberType_Property;
2958     else if (root->mtype==Event)
2959       mtype=MemberType_Event;
2960     else if (type.find("sequence<") != -1)
2961       mtype=sliceOpt ? MemberType_Sequence : MemberType_Typedef;
2962     else if (type.find("dictionary<") != -1)
2963       mtype=sliceOpt ? MemberType_Dictionary : MemberType_Typedef;
2964     else
2965       mtype=MemberType_Variable;
2966
2967     if (!root->relates.isEmpty()) // related variable
2968     {
2969       isRelated=TRUE;
2970       isMemberOf=(root->relatesType == MemberOf);
2971       if (getClass(root->relates)==0 && !scope.isEmpty())
2972         scope=mergeScopes(scope,root->relates);
2973       else
2974         scope=root->relates;
2975     }
2976
2977     cd=getClass(scope);
2978     if (cd==0 && classScope!=scope) cd=getClass(classScope);
2979     if (cd)
2980     {
2981       MemberDef *md=0;
2982
2983       // if cd is an anonymous (=tag less) scope we insert the member
2984       // into a non-anonymous parent scope as well. This is needed to
2985       // be able to refer to it using \var or \fn
2986
2987       //int indentDepth=0;
2988       int si=scope.find('@');
2989       //int anonyScopes = 0;
2990       //bool added=FALSE;
2991
2992       static bool inlineSimpleStructs = Config_getBool(INLINE_SIMPLE_STRUCTS);
2993       if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2994       {
2995         QCString pScope;
2996         ClassDef *pcd=0;
2997         pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2998         if (!pScope.isEmpty())
2999           pScope.prepend(annScopePrefix);
3000         else if (annScopePrefix.length()>2)
3001           pScope=annScopePrefix.left(annScopePrefix.length()-2);
3002         if (name.at(0)!='@')
3003         {
3004           if (!pScope.isEmpty() && (pcd=getClass(pScope)))
3005           {
3006             md=addVariableToClass(rootNav,  // entry
3007                                   pcd,   // class to add member to
3008                                   mtype, // member type
3009                                   name,  // member name
3010                                   TRUE,  // from anonymous scope
3011                                   0,     // from anonymous member
3012                                   root->protection,
3013                                   isMemberOf ? Foreign : isRelated ? Related : Member
3014                                  );
3015             //added=TRUE;
3016           }
3017           else // anonymous scope inside namespace or file => put variable in the global scope
3018           {
3019             if (mtype==MemberType_Variable)
3020             {
3021               md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0);
3022             }
3023             //added=TRUE;
3024           }
3025         }
3026       }
3027
3028       //printf("name=`%s' scope=%s scope.right=%s\n",
3029       //                   name.data(),scope.data(),
3030       //                   scope.right(scope.length()-si).data());
3031       addVariableToClass(rootNav,   // entry
3032                          cd,     // class to add member to
3033                          mtype,  // member type
3034                          name,   // name of the member
3035                          FALSE,  // from anonymous scope
3036                          md,     // from anonymous member
3037                          root->protection,
3038                          isMemberOf ? Foreign : isRelated ? Related : Member);
3039     }
3040     else if (!name.isEmpty()) // global variable
3041     {
3042       //printf("Inserting member in global scope %s!\n",scope.data());
3043       addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
3044     }
3045
3046 nextMember:
3047     rootNav->releaseEntry();
3048 }
3049
3050 //----------------------------------------------------------------------
3051 // Searches the Entry tree for typedef documentation sections.
3052 // If found they are stored in their class or in the global list.
3053 static void buildTypedefList(EntryNav *rootNav)
3054 {
3055   //printf("buildVarList(%s)\n",rootNav->name().data());
3056   if (!rootNav->name().isEmpty() &&
3057       rootNav->section()==Entry::VARIABLE_SEC &&
3058       rootNav->type().find("typedef ")!=-1 // its a typedef
3059      )
3060   {
3061     addVariable(rootNav);
3062   }
3063   if (rootNav->children())
3064   {
3065     EntryNavListIterator eli(*rootNav->children());
3066     EntryNav *e;
3067     for (;(e=eli.current());++eli)
3068     {
3069       if (e->section()!=Entry::ENUM_SEC)
3070       {
3071         buildTypedefList(e);
3072       }
3073     }
3074   }
3075 }
3076
3077 //----------------------------------------------------------------------
3078 // Searches the Entry tree for sequence documentation sections.
3079 // If found they are stored in the global list.
3080 static void buildSequenceList(EntryNav *rootNav)
3081 {
3082   if (!rootNav->name().isEmpty() &&
3083       rootNav->section()==Entry::VARIABLE_SEC &&
3084       rootNav->type().find("sequence<")!=-1 // it's a sequence
3085      )
3086   {
3087     addVariable(rootNav);
3088   }
3089   if (rootNav->children())
3090   {
3091     EntryNavListIterator eli(*rootNav->children());
3092     EntryNav *e;
3093     for (;(e=eli.current());++eli)
3094     {
3095       if (e->section()!=Entry::ENUM_SEC)
3096       {
3097         buildSequenceList(e);
3098       }
3099     }
3100   }
3101 }
3102
3103 //----------------------------------------------------------------------
3104 // Searches the Entry tree for dictionary documentation sections.
3105 // If found they are stored in the global list.
3106 static void buildDictionaryList(EntryNav *rootNav)
3107 {
3108   if (!rootNav->name().isEmpty() &&
3109       rootNav->section()==Entry::VARIABLE_SEC &&
3110       rootNav->type().find("dictionary<")!=-1 // it's a dictionary
3111      )
3112   {
3113     addVariable(rootNav);
3114   }
3115   if (rootNav->children())
3116   {
3117     EntryNavListIterator eli(*rootNav->children());
3118     EntryNav *e;
3119     for (;(e=eli.current());++eli)
3120     {
3121       if (e->section()!=Entry::ENUM_SEC)
3122       {
3123         buildDictionaryList(e);
3124       }
3125     }
3126   }
3127 }
3128
3129 //----------------------------------------------------------------------
3130 // Searches the Entry tree for Variable documentation sections.
3131 // If found they are stored in their class or in the global list.
3132
3133 static void buildVarList(EntryNav *rootNav)
3134 {
3135   //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
3136   int isFuncPtr=-1;
3137   if (!rootNav->name().isEmpty() &&
3138       (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
3139       (
3140        (rootNav->section()==Entry::VARIABLE_SEC    // it's a variable
3141        ) ||
3142        (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable
3143         (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
3144        ) ||
3145        (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
3146         isVarWithConstructor(rootNav)
3147        )
3148       )
3149      ) // documented variable
3150   {
3151     addVariable(rootNav,isFuncPtr);
3152   }
3153   if (rootNav->children())
3154   {
3155     EntryNavListIterator eli(*rootNav->children());
3156     EntryNav *e;
3157     for (;(e=eli.current());++eli)
3158     {
3159       if (e->section()!=Entry::ENUM_SEC)
3160       {
3161         buildVarList(e);
3162       }
3163     }
3164   }
3165 }
3166
3167 //----------------------------------------------------------------------
3168 // Searches the Entry tree for Interface sections (UNO IDL only).
3169 // If found they are stored in their service or in the global list.
3170 //
3171
3172 static void addInterfaceOrServiceToServiceOrSingleton(
3173         EntryNav *const rootNav,
3174         ClassDef *const cd,
3175         QCString const& rname)
3176 {
3177   Entry *const root = rootNav->entry();
3178   FileDef *const fd = rootNav->fileDef();
3179   enum MemberType const type = (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC)
3180       ? MemberType_Interface
3181       : MemberType_Service;
3182   QCString fileName = root->fileName;
3183   if (fileName.isEmpty() && rootNav->tagInfo())
3184   {
3185     fileName = rootNav->tagInfo()->tagName;
3186   }
3187   MemberDef *const md = new MemberDef(
3188       fileName, root->startLine, root->startColumn, root->type, rname,
3189       "", "", root->protection, root->virt, root->stat, Member,
3190       type, 0, root->argList, root->metaData);
3191   md->setTagInfo(rootNav->tagInfo());
3192   md->setMemberClass(cd);
3193   md->setDocumentation(root->doc,root->docFile,root->docLine);
3194   md->setDocsForDefinition(false);
3195   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3196   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3197   md->setBodySegment(root->bodyLine,root->endBodyLine);
3198   md->setMemberSpecifiers(root->spec);
3199   md->setMemberGroupId(root->mGrpId);
3200   md->setTypeConstraints(root->typeConstr);
3201   md->setLanguage(root->lang);
3202   md->setBodyDef(fd);
3203   md->setFileDef(fd);
3204   md->addSectionsToDefinition(root->anchors);
3205   QCString const def = root->type + " " + rname;
3206   md->setDefinition(def);
3207   md->enableCallGraph(root->callGraph);
3208   md->enableCallerGraph(root->callerGraph);
3209   md->enableReferencedByRelation(root->referencedByRelation);
3210   md->enableReferencesRelation(root->referencesRelation);
3211
3212   Debug::print(Debug::Functions,0,
3213       "  Interface Member:\n"
3214       "    `%s' `%s' proto=%d\n"
3215       "    def=`%s'\n",
3216       qPrint(root->type),
3217       qPrint(rname),
3218       root->proto,
3219       qPrint(def)
3220               );
3221
3222   // add member to the global list of all members
3223   MemberName *mn;
3224   if ((mn=Doxygen::memberNameSDict->find(rname)))
3225   {
3226     mn->append(md);
3227   }
3228   else
3229   {
3230     mn = new MemberName(rname);
3231     mn->append(md);
3232     Doxygen::memberNameSDict->append(rname,mn);
3233   }
3234
3235   // add member to the class cd
3236   cd->insertMember(md);
3237   // also add the member as a "base" (to get nicer diagrams)
3238   // "optional" interface/service get Protected which turns into dashed line
3239   BaseInfo base(rname,
3240           (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3241   findClassRelation(rootNav,cd,cd,&base,0,DocumentedOnly,true)
3242   || findClassRelation(rootNav,cd,cd,&base,0,Undocumented,true);
3243   // add file to list of used files
3244   cd->insertUsedFile(fd);
3245
3246   addMemberToGroups(root,md);
3247   rootNav->changeSection(Entry::EMPTY_SEC);
3248   md->setRefItems(root->sli);
3249 }
3250
3251 static void buildInterfaceAndServiceList(EntryNav *const rootNav)
3252 {
3253   if (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
3254       rootNav->section()==Entry::INCLUDED_SERVICE_SEC)
3255   {
3256     rootNav->loadEntry(g_storage);
3257     Entry *const root = rootNav->entry();
3258
3259     Debug::print(Debug::Functions,0,
3260                  "EXPORTED_INTERFACE_SEC:\n"
3261                  "  `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3262                  qPrint(root->type),
3263                  qPrint(rootNav->parent()->name()),
3264                  qPrint(root->name),
3265                  qPrint(root->args),
3266                  qPrint(root->relates),
3267                  root->relatesType,
3268                  qPrint(root->fileName),
3269                  root->startLine,
3270                  root->bodyLine,
3271                  root->tArgLists ? (int)root->tArgLists->count() : -1,
3272                  root->mGrpId,
3273                  root->spec,
3274                  root->proto,
3275                  qPrint(root->docFile)
3276                 );
3277
3278     QCString const rname = removeRedundantWhiteSpace(root->name);
3279
3280     if (!rname.isEmpty())
3281     {
3282       QCString const scope = rootNav->parent()->name();
3283       ClassDef *const cd = getClass(scope);
3284       assert(cd);
3285       if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3286                  (ClassDef::Service   == cd->compoundType()) ||
3287                  (ClassDef::Singleton == cd->compoundType())))
3288       {
3289         addInterfaceOrServiceToServiceOrSingleton(rootNav,cd,rname);
3290       }
3291       else
3292       {
3293         assert(false); // was checked by scanner.l
3294       }
3295     }
3296     else if (rname.isEmpty())
3297     {
3298       warn(root->fileName,root->startLine,
3299            "Illegal member name found.");
3300     }
3301
3302     rootNav->releaseEntry();
3303   }
3304   // can only have these in IDL anyway
3305   switch (rootNav->lang())
3306   {
3307     case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3308     case SrcLangExt_IDL:
3309         RECURSE_ENTRYTREE(buildInterfaceAndServiceList,rootNav);
3310         break;
3311     default:
3312         return; // nothing to do here
3313   }
3314 }
3315
3316
3317 //----------------------------------------------------------------------
3318 // Searches the Entry tree for Function sections.
3319 // If found they are stored in their class or in the global list.
3320
3321 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
3322                   const QCString &rname,bool isFriend)
3323 {
3324   Entry *root = rootNav->entry();
3325   FileDef *fd=rootNav->fileDef();
3326
3327   int l;
3328   static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3329   int ts=root->type.find('<');
3330   int te=root->type.findRev('>');
3331   int i=re.match(root->type,0,&l);
3332   if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
3333   {
3334     i=-1;
3335   }
3336
3337   if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3338       !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3339   {
3340     root->args+=root->type.right(root->type.length()-i-l);
3341     root->type=root->type.left(i+l);
3342   }
3343
3344   QCString name=removeRedundantWhiteSpace(rname);
3345   if (name.left(2)=="::") name=name.right(name.length()-2);
3346
3347   MemberType mtype;
3348   if (isFriend)                 mtype=MemberType_Friend;
3349   else if (root->mtype==Signal) mtype=MemberType_Signal;
3350   else if (root->mtype==Slot)   mtype=MemberType_Slot;
3351   else if (root->mtype==DCOP)   mtype=MemberType_DCOP;
3352   else                          mtype=MemberType_Function;
3353
3354   // strip redundant template specifier for constructors
3355   if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3356      name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3357   {
3358     name=name.left(i);
3359   }
3360
3361   QCString fileName = root->fileName;
3362   if (fileName.isEmpty() && rootNav->tagInfo())
3363   {
3364     fileName = rootNav->tagInfo()->tagName;
3365   }
3366
3367   //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
3368   //    root->name.data(),root->args.data(),argListToString(root->argList).data()
3369   //   );
3370
3371   // adding class member
3372   MemberDef *md=new MemberDef(
3373       fileName,root->startLine,root->startColumn,
3374       root->type,name,root->args,root->exception,
3375       root->protection,root->virt,
3376       root->stat && root->relatesType != MemberOf,
3377       root->relates.isEmpty() ? Member :
3378           root->relatesType == MemberOf ? Foreign : Related,
3379       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,root->argList, root->metaData);
3380   md->setTagInfo(rootNav->tagInfo());
3381   md->setMemberClass(cd);
3382   md->setDocumentation(root->doc,root->docFile,root->docLine);
3383   md->setDocsForDefinition(!root->proto);
3384   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3385   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3386   md->setBodySegment(root->bodyLine,root->endBodyLine);
3387   md->setMemberSpecifiers(root->spec);
3388   md->setMemberGroupId(root->mGrpId);
3389   md->setTypeConstraints(root->typeConstr);
3390   md->setLanguage(root->lang);
3391   md->setId(root->id);
3392   md->setBodyDef(fd);
3393   md->setFileDef(fd);
3394   //md->setScopeTemplateArguments(root->tArgList);
3395   md->addSectionsToDefinition(root->anchors);
3396   QCString def;
3397   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3398   SrcLangExt lang = cd->getLanguage();
3399   QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3400   if (scopeSeparator!="::")
3401   {
3402     qualScope = substitute(qualScope,"::",scopeSeparator);
3403   }
3404   if (lang==SrcLangExt_PHP)
3405   {
3406     // for PHP we use Class::method and Namespace\method
3407     scopeSeparator="::";
3408   }
3409   if (!root->relates.isEmpty() || isFriend || Config_getBool(HIDE_SCOPE_NAMES))
3410   {
3411     if (!root->type.isEmpty())
3412     {
3413       if (root->argList)
3414       {
3415         def=root->type+" "+name;
3416       }
3417       else
3418       {
3419         def=root->type+" "+name+root->args;
3420       }
3421     }
3422     else
3423     {
3424       if (root->argList)
3425       {
3426         def=name;
3427       }
3428       else
3429       {
3430         def=name+root->args;
3431       }
3432     }
3433   }
3434   else
3435   {
3436     if (!root->type.isEmpty())
3437     {
3438       if (root->argList)
3439       {
3440         def=root->type+" "+qualScope+scopeSeparator+name;
3441       }
3442       else
3443       {
3444         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3445       }
3446     }
3447     else
3448     {
3449       if (root->argList)
3450       {
3451         def=qualScope+scopeSeparator+name;
3452       }
3453       else
3454       {
3455         def=qualScope+scopeSeparator+name+root->args;
3456       }
3457     }
3458   }
3459   if (def.left(7)=="friend ") def=def.right(def.length()-7);
3460   md->setDefinition(def);
3461   md->enableCallGraph(root->callGraph);
3462   md->enableCallerGraph(root->callerGraph);
3463   md->enableReferencedByRelation(root->referencedByRelation);
3464   md->enableReferencesRelation(root->referencesRelation);
3465
3466   Debug::print(Debug::Functions,0,
3467       "  Func Member:\n"
3468       "    `%s' `%s'::`%s' `%s' proto=%d\n"
3469       "    def=`%s'\n",
3470       qPrint(root->type),
3471       qPrint(qualScope),
3472       qPrint(rname),
3473       qPrint(root->args),
3474       root->proto,
3475       qPrint(def)
3476               );
3477
3478   // add member to the global list of all members
3479   //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3480   MemberName *mn;
3481   if ((mn=Doxygen::memberNameSDict->find(name)))
3482   {
3483     mn->append(md);
3484   }
3485   else
3486   {
3487     mn = new MemberName(name);
3488     mn->append(md);
3489     Doxygen::memberNameSDict->append(name,mn);
3490   }
3491
3492   // add member to the class cd
3493   cd->insertMember(md);
3494   // add file to list of used files
3495   cd->insertUsedFile(fd);
3496
3497   addMemberToGroups(root,md);
3498   rootNav->changeSection(Entry::EMPTY_SEC);
3499   md->setRefItems(root->sli);
3500 }
3501
3502
3503 static void buildFunctionList(EntryNav *rootNav)
3504 {
3505   if (rootNav->section()==Entry::FUNCTION_SEC)
3506   {
3507     rootNav->loadEntry(g_storage);
3508     Entry *root = rootNav->entry();
3509
3510     Debug::print(Debug::Functions,0,
3511                  "FUNCTION_SEC:\n"
3512                  "  `%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",
3513                  qPrint(root->type),
3514                  qPrint(rootNav->parent()->name()),
3515                  qPrint(root->name),
3516                  qPrint(root->args),
3517                  qPrint(root->relates),
3518                  root->relatesType,
3519                  qPrint(root->fileName),
3520                  root->startLine,
3521                  root->bodyLine,
3522                  root->tArgLists ? (int)root->tArgLists->count() : -1,
3523                  root->mGrpId,
3524                  root->spec,
3525                  root->proto,
3526                  qPrint(root->docFile)
3527                 );
3528
3529     bool isFriend=root->type.find("friend ")!=-1;
3530     QCString rname = removeRedundantWhiteSpace(root->name);
3531     //printf("rname=%s\n",rname.data());
3532
3533     QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3534     if (!rname.isEmpty() && scope.find('@')==-1)
3535     {
3536       ClassDef *cd=0;
3537       // check if this function's parent is a class
3538       scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3539
3540       FileDef *rfd=rootNav->fileDef();
3541
3542       int memIndex=rname.findRev("::");
3543
3544       cd=getClass(scope);
3545       if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3546       {
3547         // strip scope from name
3548         rname=rname.right(rname.length()-rootNav->parent()->name().length()-2);
3549       }
3550
3551       NamespaceDef *nd = 0;
3552       bool isMember=FALSE;
3553       if (memIndex!=-1)
3554       {
3555         int ts=rname.find('<');
3556         int te=rname.find('>');
3557         if (memIndex>0 && (ts==-1 || te==-1))
3558         {
3559           // note: the following code was replaced by inMember=TRUE to deal with a
3560           // function rname='X::foo' of class X inside a namespace also called X...
3561           // bug id 548175
3562           //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3563           //isMember = nd==0;
3564           //if (nd)
3565           //{
3566           //  // strip namespace scope from name
3567           //  scope=rname.left(memIndex);
3568           //  rname=rname.right(rname.length()-memIndex-2);
3569           //}
3570           isMember = TRUE;
3571         }
3572         else
3573         {
3574           isMember=memIndex<ts || memIndex>te;
3575         }
3576       }
3577
3578       static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3579       int ts=root->type.find('<');
3580       int te=root->type.findRev('>');
3581       int ti;
3582       if (!rootNav->parent()->name().isEmpty() &&
3583           (rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
3584           cd &&
3585           // do some fuzzy things to exclude function pointers
3586           (root->type.isEmpty() ||
3587            ((ti=root->type.find(re,0))==-1 ||      // type does not contain ..(..*
3588             (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3589            root->args.find(")[")!=-1) ||           // and args not )[.. -> function pointer
3590            root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3591            cd->getLanguage()!=SrcLangExt_Cpp                               // language other than C
3592           )
3593          )
3594       {
3595         Debug::print(Debug::Functions,0,"  --> member %s of class %s!\n",
3596             qPrint(rname),qPrint(cd->name()));
3597         addMethodToClass(rootNav,cd,rname,isFriend);
3598       }
3599       else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK)
3600                  || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3601                 ) &&
3602                !isMember &&
3603                (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3604                root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3605               )
3606       // no member => unrelated function
3607       {
3608         /* check the uniqueness of the function name in the file.
3609          * A file could contain a function prototype and a function definition
3610          * or even multiple function prototypes.
3611          */
3612         bool found=FALSE;
3613         MemberName *mn;
3614         MemberDef *md=0;
3615         if ((mn=Doxygen::functionNameSDict->find(rname)))
3616         {
3617           Debug::print(Debug::Functions,0,"  --> function %s already found!\n",qPrint(rname));
3618           MemberNameIterator mni(*mn);
3619           for (mni.toFirst();(!found && (md=mni.current()));++mni)
3620           {
3621             NamespaceDef *mnd = md->getNamespaceDef();
3622             NamespaceDef *rnd = 0;
3623             //printf("root namespace=%s\n",rootNav->parent()->name().data());
3624             QCString fullScope = scope;
3625             QCString parentScope = rootNav->parent()->name();
3626             if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3627             {
3628               if (!scope.isEmpty()) fullScope.prepend("::");
3629               fullScope.prepend(parentScope);
3630             }
3631             //printf("fullScope=%s\n",fullScope.data());
3632             rnd = getResolvedNamespace(fullScope);
3633             FileDef *mfd = md->getFileDef();
3634             QCString nsName,rnsName;
3635             if (mnd)  nsName = mnd->name().copy();
3636             if (rnd) rnsName = rnd->name().copy();
3637             //printf("matching arguments for %s%s %s%s\n",
3638             //    md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3639             ArgumentList *mdAl = md->argumentList();
3640             ArgumentList *mdTempl = md->templateArguments();
3641
3642             // in case of template functions, we need to check if the
3643             // functions have the same number of template parameters
3644             bool sameNumTemplateArgs = TRUE;
3645             bool matchingReturnTypes = TRUE;
3646             if (mdTempl!=0 && root->tArgLists)
3647             {
3648               if (mdTempl->count()!=root->tArgLists->getLast()->count())
3649               {
3650                 sameNumTemplateArgs = FALSE;
3651               }
3652               if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3653               {
3654                 matchingReturnTypes = FALSE;
3655               }
3656             }
3657
3658             bool staticsInDifferentFiles =
3659                     root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3660
3661             if (
3662                 matchArguments2(md->getOuterScope(),mfd,mdAl,
3663                                 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3664                                 FALSE) &&
3665                 sameNumTemplateArgs &&
3666                 matchingReturnTypes &&
3667                 !staticsInDifferentFiles
3668                )
3669             {
3670               GroupDef *gd=0;
3671               if (root->groups->getFirst()!=0)
3672               {
3673                 gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
3674               }
3675               //printf("match!\n");
3676               //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3677               // see if we need to create a new member
3678               found=(mnd && rnd && nsName==rnsName) ||   // members are in the same namespace
3679                     ((mnd==0 && rnd==0 && mfd!=0 &&       // no external reference and
3680                       mfd->absFilePath()==root->fileName // prototype in the same file
3681                      )
3682                     );
3683               // otherwise, allow a duplicate global member with the same argument list
3684               if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3685               {
3686                 // member is already in the group, so we don't want to add it again.
3687                 found=TRUE;
3688               }
3689
3690               //printf("combining function with prototype found=%d in namespace %s\n",
3691               //    found,nsName.data());
3692
3693               if (found)
3694               {
3695                 // merge argument lists
3696                 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
3697                 // merge documentation
3698                 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3699                 {
3700                   ArgumentList *argList = new ArgumentList;
3701                   stringToArgumentList(root->args,argList);
3702                   if (root->proto)
3703                   {
3704                     //printf("setDeclArgumentList to %p\n",argList);
3705                     md->setDeclArgumentList(argList);
3706                   }
3707                   else
3708                   {
3709                     md->setArgumentList(argList);
3710                   }
3711                 }
3712
3713                 md->setDocumentation(root->doc,root->docFile,root->docLine);
3714                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3715                 md->setDocsForDefinition(!root->proto);
3716                 if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3717                 {
3718                   md->setBodySegment(root->bodyLine,root->endBodyLine);
3719                   md->setBodyDef(rfd);
3720                 }
3721
3722                 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3723                 {
3724                   md->setArgsString(root->args);
3725                 }
3726                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3727
3728                 md->addSectionsToDefinition(root->anchors);
3729
3730                 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3731                 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3732                 md->enableReferencedByRelation(md->hasReferencedByRelation() || root->referencedByRelation);
3733                 md->enableReferencesRelation(md->hasReferencesRelation() || root->referencesRelation);
3734
3735                 // merge ingroup specifiers
3736                 if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
3737                 {
3738                   addMemberToGroups(root,md);
3739                 }
3740                 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3741                 {
3742                   //printf("existing member is grouped, new member not\n");
3743                   root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3744                 }
3745                 else if (md->getGroupDef()!=0 && root->groups->getFirst()!=0)
3746                 {
3747                   //printf("both members are grouped\n");
3748                 }
3749
3750                 // if md is a declaration and root is the corresponding
3751                 // definition, then turn md into a definition.
3752                 if (md->isPrototype() && !root->proto)
3753                 {
3754                   md->setPrototype(FALSE);
3755                 }
3756               }
3757             }
3758           }
3759         }
3760         if (!found) /* global function is unique with respect to the file */
3761         {
3762           Debug::print(Debug::Functions,0,"  --> new function %s found!\n",qPrint(rname));
3763           //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3764           //       root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3765
3766           // new global function
3767           ArgumentList *tArgList = root->tArgLists ? root->tArgLists->getLast() : 0;
3768           QCString name=removeRedundantWhiteSpace(rname);
3769           md=new MemberDef(
3770               root->fileName,root->startLine,root->startColumn,
3771               root->type,name,root->args,root->exception,
3772               root->protection,root->virt,root->stat,Member,
3773               MemberType_Function,tArgList,root->argList,root->metaData);
3774
3775           md->setTagInfo(rootNav->tagInfo());
3776           md->setLanguage(root->lang);
3777           md->setId(root->id);
3778           //md->setDefFile(root->fileName);
3779           //md->setDefLine(root->startLine);
3780           md->setDocumentation(root->doc,root->docFile,root->docLine);
3781           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3782           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3783           md->setPrototype(root->proto);
3784           md->setDocsForDefinition(!root->proto);
3785           md->setTypeConstraints(root->typeConstr);
3786           //md->setBody(root->body);
3787           md->setBodySegment(root->bodyLine,root->endBodyLine);
3788           FileDef *fd=rootNav->fileDef();
3789           md->setBodyDef(fd);
3790           md->addSectionsToDefinition(root->anchors);
3791           md->setMemberSpecifiers(root->spec);
3792           md->setMemberGroupId(root->mGrpId);
3793
3794           // see if the function is inside a namespace that was not part of
3795           // the name already (in that case nd should be non-zero already)
3796           if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3797           {
3798             //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3799             QCString nscope=rootNav->parent()->name();
3800             if (!nscope.isEmpty())
3801             {
3802               nd = getResolvedNamespace(nscope);
3803             }
3804           }
3805
3806           if (!scope.isEmpty())
3807           {
3808             QCString sep = getLanguageSpecificSeparator(root->lang);
3809             if (sep!="::")
3810             {
3811               scope = substitute(scope,"::",sep);
3812             }
3813             scope+=sep;
3814           }
3815
3816           QCString def;
3817           if (!root->type.isEmpty())
3818           {
3819             if (root->argList)
3820             {
3821               def=root->type+" "+scope+name;
3822             }
3823             else
3824             {
3825               def=root->type+" "+scope+name+root->args;
3826             }
3827           }
3828           else
3829           {
3830             if (root->argList)
3831             {
3832               def=scope+name.copy();
3833             }
3834             else
3835             {
3836               def=scope+name+root->args;
3837             }
3838           }
3839           Debug::print(Debug::Functions,0,
3840                      "  Global Function:\n"
3841                      "    `%s' `%s'::`%s' `%s' proto=%d\n"
3842                      "    def=`%s'\n",
3843                      qPrint(root->type),
3844                      qPrint(rootNav->parent()->name()),
3845                      qPrint(rname),
3846                      qPrint(root->args),
3847                      root->proto,
3848                      qPrint(def)
3849                     );
3850           md->setDefinition(def);
3851           md->enableCallGraph(root->callGraph);
3852           md->enableCallerGraph(root->callerGraph);
3853           md->enableReferencedByRelation(root->referencedByRelation);
3854           md->enableReferencesRelation(root->referencesRelation);
3855           //if (root->mGrpId!=-1)
3856           //{
3857           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
3858           //}
3859
3860           md->setRefItems(root->sli);
3861           if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3862           {
3863             // add member to namespace
3864             md->setNamespace(nd);
3865             nd->insertMember(md);
3866           }
3867           if (fd)
3868           {
3869             // add member to the file (we do this even if we have already
3870             // inserted it into the namespace)
3871             md->setFileDef(fd);
3872             fd->insertMember(md);
3873           }
3874
3875           // add member to the list of file members
3876           //printf("Adding member=%s\n",md->name().data());
3877           MemberName *mn;
3878           if ((mn=Doxygen::functionNameSDict->find(name)))
3879           {
3880             mn->append(md);
3881           }
3882           else
3883           {
3884             mn = new MemberName(name);
3885             mn->append(md);
3886             Doxygen::functionNameSDict->append(name,mn);
3887           }
3888           addMemberToGroups(root,md);
3889           if (root->relatesType == Simple) // if this is a relatesalso command,
3890                                            // allow find Member to pick it up
3891           {
3892             rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished
3893                                                       // with this entry.
3894
3895           }
3896         }
3897         else
3898         {
3899           FileDef *fd=rootNav->fileDef();
3900           if (fd)
3901           {
3902             // add member to the file (we do this even if we have already
3903             // inserted it into the namespace)
3904             fd->insertMember(md);
3905           }
3906         }
3907
3908         //printf("unrelated function %d `%s' `%s' `%s'\n",
3909         //    root->parent->section,root->type.data(),rname.data(),root->args.data());
3910       }
3911       else
3912       {
3913           Debug::print(Debug::Functions,0,"  --> %s not processed!\n",qPrint(rname));
3914       }
3915     }
3916     else if (rname.isEmpty())
3917     {
3918         warn(root->fileName,root->startLine,
3919              "Illegal member name found."
3920             );
3921     }
3922
3923     rootNav->releaseEntry();
3924   }
3925   RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3926 }
3927
3928 //----------------------------------------------------------------------
3929
3930 static void findFriends()
3931 {
3932   //printf("findFriends()\n");
3933   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3934   MemberName *fn;
3935   for (;(fn=fnli.current());++fnli) // for each global function name
3936   {
3937     //printf("Function name=`%s'\n",fn->memberName());
3938     MemberName *mn;
3939     if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3940     { // there are members with the same name
3941       //printf("Function name is also a member name\n");
3942       MemberNameIterator fni(*fn);
3943       MemberDef *fmd;
3944       for (;(fmd=fni.current());++fni) // for each function with that name
3945       {
3946         MemberNameIterator mni(*mn);
3947         MemberDef *mmd;
3948         for (;(mmd=mni.current());++mni) // for each member with that name
3949         {
3950           //printf("Checking for matching arguments
3951           //        mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3952           //    mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3953           ArgumentList *mmdAl = mmd->argumentList();
3954           ArgumentList *fmdAl = fmd->argumentList();
3955           if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3956               matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl,
3957                               fmd->getOuterScope(), fmd->getFileDef(), fmdAl,
3958                               TRUE
3959                              )
3960
3961              ) // if the member is related and the arguments match then the
3962                // function is actually a friend.
3963           {
3964             mergeArguments(mmdAl,fmdAl);
3965             if (!fmd->documentation().isEmpty())
3966             {
3967               mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3968             }
3969             else if (!mmd->documentation().isEmpty())
3970             {
3971               fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3972             }
3973             if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3974             {
3975               mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3976             }
3977             else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3978             {
3979               fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3980             }
3981             if (!fmd->inbodyDocumentation().isEmpty())
3982             {
3983               mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3984             }
3985             else if (!mmd->inbodyDocumentation().isEmpty())
3986             {
3987               fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3988             }
3989             //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3990             if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3991             {
3992               mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3993               mmd->setBodyDef(fmd->getBodyDef());
3994               //mmd->setBodyMember(fmd);
3995             }
3996             else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3997             {
3998               fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3999               fmd->setBodyDef(mmd->getBodyDef());
4000               //fmd->setBodyMember(mmd);
4001             }
4002             mmd->setDocsForDefinition(fmd->isDocsForDefinition());
4003
4004             mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
4005             mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
4006             mmd->enableReferencedByRelation(mmd->hasReferencedByRelation() || fmd->hasReferencedByRelation());
4007             mmd->enableReferencesRelation(mmd->hasReferencesRelation() || fmd->hasReferencesRelation());
4008
4009             fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
4010             fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
4011             fmd->enableReferencedByRelation(mmd->hasReferencedByRelation() || fmd->hasReferencedByRelation());
4012             fmd->enableReferencesRelation(mmd->hasReferencesRelation() || fmd->hasReferencesRelation());
4013           }
4014         }
4015       }
4016     }
4017   }
4018 }
4019
4020 //----------------------------------------------------------------------
4021
4022 static void transferFunctionDocumentation()
4023 {
4024   //printf("---- transferFunctionDocumentation()\n");
4025
4026   // find matching function declaration and definitions.
4027   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4028   MemberName *mn;
4029   for (;(mn=mnli.current());++mnli)
4030   {
4031     //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
4032     MemberDef *mdef=0,*mdec=0;
4033     MemberNameIterator mni1(*mn);
4034     /* find a matching function declaration and definition for this function */
4035     for (;(mdec=mni1.current());++mni1)
4036     {
4037       if (mdec->isPrototype() ||
4038           (mdec->isVariable() && mdec->isExternal())
4039          )
4040       {
4041         MemberNameIterator mni2(*mn);
4042         for (;(mdef=mni2.current());++mni2)
4043         {
4044           combineDeclarationAndDefinition(mdec,mdef);
4045         }
4046       }
4047     }
4048   }
4049 }
4050
4051 //----------------------------------------------------------------------
4052
4053 static void transferFunctionReferences()
4054 {
4055   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4056   MemberName *mn;
4057   for (;(mn=mnli.current());++mnli)
4058   {
4059     MemberDef *md,*mdef=0,*mdec=0;
4060     MemberNameIterator mni(*mn);
4061     /* find a matching function declaration and definition for this function */
4062     for (;(md=mni.current());++mni)
4063     {
4064       if (md->isPrototype())
4065         mdec=md;
4066       else if (md->isVariable() && md->isExternal())
4067         mdec=md;
4068
4069       if (md->isFunction() && !md->isStatic() && !md->isPrototype())
4070         mdef=md;
4071       else if (md->isVariable() && !md->isExternal() && !md->isStatic())
4072         mdef=md;
4073     }
4074     if (mdef && mdec)
4075     {
4076       ArgumentList *mdefAl = mdef->argumentList();
4077       ArgumentList *mdecAl = mdec->argumentList();
4078       if (
4079           matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
4080                           mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
4081                           TRUE
4082             )
4083          ) /* match found */
4084       {
4085         MemberSDict *defDict = mdef->getReferencesMembers();
4086         MemberSDict *decDict = mdec->getReferencesMembers();
4087         if (defDict!=0)
4088         {
4089           MemberSDict::IteratorDict msdi(*defDict);
4090           MemberDef *rmd;
4091           for (msdi.toFirst();(rmd=msdi.current());++msdi)
4092           {
4093             if (decDict==0 || decDict->find(rmd->name())==0)
4094             {
4095               mdec->addSourceReferences(rmd);
4096             }
4097           }
4098         }
4099         if (decDict!=0)
4100         {
4101           MemberSDict::IteratorDict msdi(*decDict);
4102           MemberDef *rmd;
4103           for (msdi.toFirst();(rmd=msdi.current());++msdi)
4104           {
4105             if (defDict==0 || defDict->find(rmd->name())==0)
4106             {
4107               mdef->addSourceReferences(rmd);
4108             }
4109           }
4110         }
4111
4112         defDict = mdef->getReferencedByMembers();
4113         decDict = mdec->getReferencedByMembers();
4114         if (defDict!=0)
4115         {
4116           MemberSDict::IteratorDict msdi(*defDict);
4117           MemberDef *rmd;
4118           for (msdi.toFirst();(rmd=msdi.current());++msdi)
4119           {
4120             if (decDict==0 || decDict->find(rmd->name())==0)
4121             {
4122               mdec->addSourceReferencedBy(rmd);
4123             }
4124           }
4125         }
4126         if (decDict!=0)
4127         {
4128           MemberSDict::IteratorDict msdi(*decDict);
4129           MemberDef *rmd;
4130           for (msdi.toFirst();(rmd=msdi.current());++msdi)
4131           {
4132             if (defDict==0 || defDict->find(rmd->name())==0)
4133             {
4134               mdef->addSourceReferencedBy(rmd);
4135             }
4136           }
4137         }
4138       }
4139     }
4140   }
4141 }
4142
4143 //----------------------------------------------------------------------
4144
4145 static void transferRelatedFunctionDocumentation()
4146 {
4147   // find match between function declaration and definition for
4148   // related functions
4149   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4150   MemberName *mn;
4151   for (mnli.toFirst();(mn=mnli.current());++mnli)
4152   {
4153     MemberDef *md;
4154     MemberNameIterator mni(*mn);
4155     /* find a matching function declaration and definition for this function */
4156     for (mni.toFirst();(md=mni.current());++mni) // for each global function
4157     {
4158       //printf("  Function `%s'\n",md->name().data());
4159       MemberName *rmn;
4160       if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
4161       {
4162         //printf("  Member name found\n");
4163         MemberDef *rmd;
4164         MemberNameIterator rmni(*rmn);
4165         for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
4166         {
4167           ArgumentList *mdAl = md->argumentList();
4168           ArgumentList *rmdAl = rmd->argumentList();
4169           //printf("  Member found: related=`%d'\n",rmd->isRelated());
4170           if ((rmd->isRelated() || rmd->isForeign()) && // related function
4171               matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4172                               rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
4173                               TRUE
4174                              )
4175              )
4176           {
4177             //printf("  Found related member `%s'\n",md->name().data());
4178             if (rmd->relatedAlso())
4179               md->setRelatedAlso(rmd->relatedAlso());
4180             else if (rmd->isForeign())
4181               md->makeForeign();
4182             else
4183               md->makeRelated();
4184           }
4185         }
4186       }
4187     }
4188   }
4189 }
4190
4191 //----------------------------------------------------------------------
4192
4193 /*! make a dictionary of all template arguments of class cd
4194  * that are part of the base class name.
4195  * Example: A template class A with template arguments <R,S,T>
4196  * that inherits from B<T,T,S> will have T and S in the dictionary.
4197  */
4198 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
4199 {
4200   QDict<int> *templateNames = new QDict<int>(17);
4201   templateNames->setAutoDelete(TRUE);
4202   static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
4203   if (templateArguments)
4204   {
4205     ArgumentListIterator ali(*templateArguments);
4206     Argument *arg;
4207     int count=0;
4208     for (ali.toFirst();(arg=ali.current());++ali,count++)
4209     {
4210       int i,p=0,l;
4211       while ((i=re.match(name,p,&l))!=-1)
4212       {
4213         QCString n = name.mid(i,l);
4214         if (n==arg->name)
4215         {
4216           if (templateNames->find(n)==0)
4217           {
4218             templateNames->insert(n,new int(count));
4219           }
4220         }
4221         p=i+l;
4222       }
4223     }
4224   }
4225   return templateNames;
4226 }
4227
4228 /*! Searches a class from within \a context and \a cd and returns its
4229  *  definition if found (otherwise 0 is returned).
4230  */
4231 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
4232 {
4233   ClassDef *result=0;
4234   if (cd==0)
4235   {
4236     return result;
4237   }
4238   FileDef *fd=cd->getFileDef();
4239   if (context && cd!=context)
4240   {
4241     result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
4242   }
4243   if (result==0)
4244   {
4245     result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
4246   }
4247   if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4248   {
4249     result = getClass(name);
4250   }
4251   if (result==0 &&
4252       (cd->getLanguage()==SrcLangExt_CSharp || cd->getLanguage()==SrcLangExt_Java) &&
4253       name.find('<')!=-1)
4254   {
4255     result = Doxygen::genericsDict->find(name);
4256   }
4257   //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4258   //       name.data(),
4259   //       context ? context->name().data() : "<none>",
4260   //       cd      ? cd->name().data()      : "<none>",
4261   //       result  ? result->name().data()  : "<none>",
4262   //       Doxygen::classSDict->find(name)
4263   //      );
4264   return result;
4265 }
4266
4267
4268 static void findUsedClassesForClass(EntryNav *rootNav,
4269                            Definition *context,
4270                            ClassDef *masterCd,
4271                            ClassDef *instanceCd,
4272                            bool isArtificial,
4273                            ArgumentList *actualArgs=0,
4274                            QDict<int> *templateNames=0
4275                            )
4276 {
4277   masterCd->visited=TRUE;
4278   ArgumentList *formalArgs = masterCd->templateArguments();
4279   if (masterCd->memberNameInfoSDict())
4280   {
4281     MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
4282     MemberNameInfo *mni;
4283     for (;(mni=mnili.current());++mnili)
4284     {
4285       MemberNameInfoIterator mnii(*mni);
4286       MemberInfo *mi;
4287       for (mnii.toFirst();(mi=mnii.current());++mnii)
4288       {
4289         MemberDef *md=mi->memberDef;
4290         if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4291         {
4292           //printf("    Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
4293           QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4294           QCString typedefValue = resolveTypeDef(masterCd,type);
4295           if (!typedefValue.isEmpty())
4296           {
4297             type = typedefValue;
4298           }
4299           int pos=0;
4300           QCString usedClassName;
4301           QCString templSpec;
4302           bool found=FALSE;
4303           // the type can contain template variables, replace them if present
4304           if (actualArgs)
4305           {
4306             type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4307           }
4308
4309           //printf("      template substitution gives=%s\n",type.data());
4310           while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
4311           {
4312             // find the type (if any) that matches usedClassName
4313             ClassDef *typeCd = getResolvedClass(masterCd,
4314                 masterCd->getFileDef(),
4315                 usedClassName,
4316                 0,0,
4317                 FALSE,TRUE
4318                 );
4319             //printf("====>  usedClassName=%s -> typeCd=%s\n",
4320             //     usedClassName.data(),typeCd?typeCd->name().data():"<none>");
4321             if (typeCd)
4322             {
4323               usedClassName = typeCd->name();
4324             }
4325
4326             int sp=usedClassName.find('<');
4327             if (sp==-1) sp=0;
4328             int si=usedClassName.findRev("::",sp);
4329             if (si!=-1)
4330             {
4331               // replace any namespace aliases
4332               replaceNamespaceAliases(usedClassName,si);
4333             }
4334             // add any template arguments to the class
4335             QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4336             //printf("    usedName=%s\n",usedName.data());
4337
4338             bool delTempNames=FALSE;
4339             if (templateNames==0)
4340             {
4341               templateNames = getTemplateArgumentsInName(formalArgs,usedName);
4342               delTempNames=TRUE;
4343             }
4344             BaseInfo bi(usedName,Public,Normal);
4345             findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
4346
4347             if (masterCd->templateArguments())
4348             {
4349               ArgumentListIterator ali(*masterCd->templateArguments());
4350               Argument *arg;
4351               int count=0;
4352               for (ali.toFirst();(arg=ali.current());++ali,++count)
4353               {
4354                 if (arg->name==usedName) // type is a template argument
4355                 {
4356                   found=TRUE;
4357                   Debug::print(Debug::Classes,0,"    New used class `%s'\n", qPrint(usedName));
4358
4359                   ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
4360                   if (usedCd==0)
4361                   {
4362                     usedCd = new ClassDef(
4363                         masterCd->getDefFileName(),masterCd->getDefLine(),
4364                         masterCd->getDefColumn(),
4365                         usedName,
4366                         ClassDef::Class);
4367                     //printf("making %s a template argument!!!\n",usedCd->name().data());
4368                     usedCd->makeTemplateArgument();
4369                     usedCd->setUsedOnly(TRUE);
4370                     usedCd->setLanguage(masterCd->getLanguage());
4371                     Doxygen::hiddenClasses->append(usedName,usedCd);
4372                   }
4373                   if (isArtificial) usedCd->setArtificial(TRUE);
4374                   Debug::print(Debug::Classes,0,"      Adding used class `%s' (1)\n", qPrint(usedCd->name()));
4375                   instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4376                   usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4377                 }
4378               }
4379             }
4380
4381             if (!found)
4382             {
4383               ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4384               //printf("Looking for used class %s: result=%s master=%s\n",
4385               //    usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
4386
4387               if (usedCd)
4388               {
4389                 found=TRUE;
4390                 Debug::print(Debug::Classes,0,"    Adding used class `%s' (2)\n", qPrint(usedCd->name()));
4391                 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
4392                 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4393               }
4394             }
4395             if (delTempNames)
4396             {
4397               delete templateNames;
4398               templateNames=0;
4399             }
4400           }
4401           if (!found && !type.isEmpty()) // used class is not documented in any scope
4402           {
4403             ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4404             if (usedCd==0 && !Config_getBool(HIDE_UNDOC_RELATIONS))
4405             {
4406               if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4407               {
4408                 type+=md->argsString();
4409               }
4410               Debug::print(Debug::Classes,0,"  New undocumented used class `%s'\n", qPrint(type));
4411               usedCd = new ClassDef(
4412                   masterCd->getDefFileName(),masterCd->getDefLine(),
4413                   masterCd->getDefColumn(),
4414                   type,ClassDef::Class);
4415               usedCd->setUsedOnly(TRUE);
4416               usedCd->setLanguage(masterCd->getLanguage());
4417               Doxygen::hiddenClasses->append(type,usedCd);
4418             }
4419             if (usedCd)
4420             {
4421               if (isArtificial) usedCd->setArtificial(TRUE);
4422               Debug::print(Debug::Classes,0,"    Adding used class `%s' (3)\n", qPrint(usedCd->name()));
4423               instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4424               usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4425             }
4426           }
4427         }
4428       }
4429     }
4430   }
4431   else
4432   {
4433     //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4434   }
4435 }
4436
4437 static void findBaseClassesForClass(
4438       EntryNav *rootNav,
4439       Definition *context,
4440       ClassDef *masterCd,
4441       ClassDef *instanceCd,
4442       FindBaseClassRelation_Mode mode,
4443       bool isArtificial,
4444       ArgumentList *actualArgs=0,
4445       QDict<int> *templateNames=0
4446     )
4447 {
4448   Entry *root = rootNav->entry();
4449   //if (masterCd->visited) return;
4450   masterCd->visited=TRUE;
4451   // The base class could ofcouse also be a non-nested class
4452   ArgumentList *formalArgs = masterCd->templateArguments();
4453   QListIterator<BaseInfo> bii(*root->extends);
4454   BaseInfo *bi=0;
4455   for (bii.toFirst();(bi=bii.current());++bii)
4456   {
4457     //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4458     //    masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4459     bool delTempNames=FALSE;
4460     if (templateNames==0)
4461     {
4462       templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4463       delTempNames=TRUE;
4464     }
4465     BaseInfo tbi(bi->name,bi->prot,bi->virt);
4466     if (actualArgs) // substitute the formal template arguments of the base class
4467     {
4468       tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4469     }
4470     //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4471
4472     if (mode==DocumentedOnly)
4473     {
4474       // find a documented base class in the correct scope
4475       if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4476       {
4477         // 1.8.2: decided to show inheritance relations even if not documented,
4478         //        we do make them artificial, so they do not appear in the index
4479         //if (!Config_getBool(HIDE_UNDOC_RELATIONS))
4480         bool b = Config_getBool(HIDE_UNDOC_RELATIONS) ? TRUE : isArtificial;
4481         //{
4482           // no documented base class -> try to find an undocumented one
4483           findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4484         //}
4485       }
4486     }
4487     else if (mode==TemplateInstances)
4488     {
4489       findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4490     }
4491     if (delTempNames)
4492     {
4493       delete templateNames;
4494       templateNames=0;
4495     }
4496   }
4497 }
4498
4499 //----------------------------------------------------------------------
4500
4501 static bool findTemplateInstanceRelation(Entry *root,
4502             Definition *context,
4503             ClassDef *templateClass,const QCString &templSpec,
4504             QDict<int> *templateNames,
4505             bool isArtificial)
4506 {
4507   Debug::print(Debug::Classes,0,"    derived from template %s with parameters %s\n",
4508          qPrint(templateClass->name()),qPrint(templSpec));
4509   //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4510   //    templateClass->name().data(),templSpec.data());
4511   //if (templateNames)
4512   //{
4513   //  QDictIterator<int> qdi(*templateNames);
4514   //  int *tempArgIndex;
4515   //  for (;(tempArgIndex=qdi.current());++qdi)
4516   //  {
4517   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4518   //  }
4519   //}
4520   //printf("\n");
4521
4522   bool existingClass = (templSpec ==
4523                         tempArgListToString(templateClass->templateArguments(),root->lang)
4524                        );
4525   if (existingClass) return TRUE;
4526
4527   bool freshInstance=FALSE;
4528   ClassDef *instanceClass = templateClass->insertTemplateInstance(
4529                      root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4530   if (isArtificial) instanceClass->setArtificial(TRUE);
4531   instanceClass->setLanguage(root->lang);
4532
4533   if (freshInstance)
4534   {
4535     Debug::print(Debug::Classes,0,"      found fresh instance '%s'!\n",qPrint(instanceClass->name()));
4536     Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4537     instanceClass->setTemplateBaseClassNames(templateNames);
4538
4539     // search for new template instances caused by base classes of
4540     // instanceClass
4541     EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4542     if (templateRootNav)
4543     {
4544       bool unloadNeeded=FALSE;
4545       Entry *templateRoot = templateRootNav->entry();
4546       if (templateRoot==0) // not yet loaded
4547       {
4548         templateRootNav->loadEntry(g_storage);
4549         templateRoot = templateRootNav->entry();
4550         ASSERT(templateRoot!=0); // now it should really be loaded
4551         unloadNeeded=TRUE;
4552       }
4553
4554       Debug::print(Debug::Classes,0,"        template root found %s templSpec=%s!\n",
4555           qPrint(templateRoot->name),qPrint(templSpec));
4556       ArgumentList *templArgs = new ArgumentList;
4557       stringToArgumentList(templSpec,templArgs);
4558       findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4559           TemplateInstances,isArtificial,templArgs,templateNames);
4560
4561       findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4562           isArtificial,templArgs,templateNames);
4563       delete templArgs;
4564
4565       if (unloadNeeded) // still cleanup to do
4566       {
4567         templateRootNav->releaseEntry();
4568       }
4569     }
4570     else
4571     {
4572       Debug::print(Debug::Classes,0,"        no template root entry found!\n");
4573       // TODO: what happened if we get here?
4574     }
4575
4576     //Debug::print(Debug::Classes,0,"    Template instance %s : \n",instanceClass->name().data());
4577     //ArgumentList *tl = templateClass->templateArguments();
4578   }
4579   else
4580   {
4581     Debug::print(Debug::Classes,0,"      instance already exists!\n");
4582   }
4583   return TRUE;
4584 }
4585
4586 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4587 {
4588   QCString n=name;
4589   int index=n.find('<');
4590   if (index!=-1)
4591   {
4592     n=n.left(index);
4593   }
4594   bool result = rightScopeMatch(scope,n);
4595   return result;
4596 }
4597
4598 /*! Searches for the end of a template in prototype \a s starting from
4599  *  character position \a startPos. If the end was found the position
4600  *  of the closing \> is returned, otherwise -1 is returned.
4601  *
4602  *  Handles exotic cases such as
4603  *  \code
4604  *    Class<(id<0)>
4605  *    Class<bits<<2>
4606  *    Class<"<">
4607  *    Class<'<'>
4608  *    Class<(")<")>
4609  *  \endcode
4610  */
4611 static int findEndOfTemplate(const QCString &s,int startPos)
4612 {
4613   // locate end of template
4614   int e=startPos;
4615   int brCount=1;
4616   int roundCount=0;
4617   int len = s.length();
4618   bool insideString=FALSE;
4619   bool insideChar=FALSE;
4620   char pc = 0;
4621   while (e<len && brCount!=0)
4622   {
4623     char c=s.at(e);
4624     switch(c)
4625     {
4626       case '<':
4627         if (!insideString && !insideChar)
4628         {
4629           if (e<len-1 && s.at(e+1)=='<')
4630             e++;
4631           else if (roundCount==0)
4632             brCount++;
4633         }
4634         break;
4635       case '>':
4636         if (!insideString && !insideChar)
4637         {
4638           if (e<len-1 && s.at(e+1)=='>')
4639             e++;
4640           else if (roundCount==0)
4641             brCount--;
4642         }
4643         break;
4644       case '(':
4645         if (!insideString && !insideChar)
4646           roundCount++;
4647         break;
4648       case ')':
4649         if (!insideString && !insideChar)
4650           roundCount--;
4651         break;
4652       case '"':
4653         if (!insideChar)
4654         {
4655           if (insideString && pc!='\\')
4656             insideString=FALSE;
4657           else
4658             insideString=TRUE;
4659         }
4660         break;
4661       case '\'':
4662         if (!insideString)
4663         {
4664           if (insideChar && pc!='\\')
4665             insideChar=FALSE;
4666           else
4667             insideChar=TRUE;
4668         }
4669         break;
4670     }
4671     pc = c;
4672     e++;
4673   }
4674   return brCount==0 ? e : -1;
4675 }
4676
4677 static bool findClassRelation(
4678                            EntryNav *rootNav,
4679                            Definition *context,
4680                            ClassDef *cd,
4681                            BaseInfo *bi,
4682                            QDict<int> *templateNames,
4683                            FindBaseClassRelation_Mode mode,
4684                            bool isArtificial
4685                           )
4686 {
4687   //printf("findClassRelation(class=%s base=%s templateNames=",
4688   //    cd->name().data(),bi->name.data());
4689   //if (templateNames)
4690   //{
4691   //  QDictIterator<int> qdi(*templateNames);
4692   //  int *tempArgIndex;
4693   //  for (;(tempArgIndex=qdi.current());++qdi)
4694   //  {
4695   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4696   //  }
4697   //}
4698   //printf("\n");
4699
4700   Entry *root = rootNav->entry();
4701
4702   QCString biName=bi->name;
4703   bool explicitGlobalScope=FALSE;
4704   //printf("findClassRelation: biName=`%s'\n",biName.data());
4705   if (biName.left(2)=="::") // explicit global scope
4706   {
4707      biName=biName.right(biName.length()-2);
4708      explicitGlobalScope=TRUE;
4709   }
4710
4711   EntryNav *parentNode=rootNav->parent();
4712   bool lastParent=FALSE;
4713   do // for each parent scope, starting with the largest scope
4714      // (in case of nested classes)
4715   {
4716     QCString scopeName= parentNode ? parentNode->name().data() : "";
4717     int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4718     do // try all parent scope prefixes, starting with the largest scope
4719     {
4720       //printf("scopePrefix=`%s' biName=`%s'\n",
4721       //    scopeName.left(scopeOffset).data(),biName.data());
4722
4723       QCString baseClassName=biName;
4724       if (scopeOffset>0)
4725       {
4726         baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4727       }
4728       //QCString stripped;
4729       //baseClassName=stripTemplateSpecifiersFromScope
4730       //                    (removeRedundantWhiteSpace(baseClassName),TRUE,
4731       //                    &stripped);
4732       MemberDef *baseClassTypeDef=0;
4733       QCString templSpec;
4734       ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4735                                            cd->getFileDef(),
4736                                            baseClassName,
4737                                            &baseClassTypeDef,
4738                                            &templSpec,
4739                                            mode==Undocumented,
4740                                            TRUE
4741                                           );
4742       //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4743       //    baseClassName.data(),baseClass,cd,explicitGlobalScope);
4744       //printf("    scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4745       //                    cd ? cd->name().data():"<none>",
4746       //                    baseClassName.data(),
4747       //                    baseClass?baseClass->name().data():"<none>",
4748       //                    templSpec.data()
4749       //      );
4750       //if (baseClassName.left(root->name.length())!=root->name ||
4751       //    baseClassName.at(root->name.length())!='<'
4752       //   ) // Check for base class with the same name.
4753       //     // If found then look in the outer scope for a match
4754       //     // and prevent recursion.
4755       if (!isRecursiveBaseClass(rootNav->name(),baseClassName)
4756           || explicitGlobalScope
4757           // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4758           // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4759           || (rootNav->lang()==SrcLangExt_IDL &&
4760               (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
4761                rootNav->section()==Entry::INCLUDED_SERVICE_SEC)))
4762       {
4763         Debug::print(
4764             Debug::Classes,0,"    class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4765             qPrint(baseClassName),
4766             qPrint(rootNav->name()),
4767             (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4768             (bi->virt==Normal)?"normal":"virtual",
4769             qPrint(templSpec)
4770            );
4771
4772         int i=baseClassName.find('<');
4773         int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4774         if (si==-1) si=0;
4775         if (baseClass==0 && (root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java))
4776         {
4777           // for Java/C# strip the template part before looking for matching
4778           baseClass = Doxygen::genericsDict->find(baseClassName.left(i));
4779           //printf("looking for '%s' result=%p\n",baseClassName.data(),baseClass);
4780         }
4781         if (baseClass==0 && i!=-1)
4782           // base class has template specifiers
4783         {
4784           // TODO: here we should try to find the correct template specialization
4785           // but for now, we only look for the unspecializated base class.
4786           int e=findEndOfTemplate(baseClassName,i+1);
4787           //printf("baseClass==0 i=%d e=%d\n",i,e);
4788           if (e!=-1) // end of template was found at e
4789           {
4790             templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4791             baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4792             baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4793                 cd->getFileDef(),
4794                 baseClassName,
4795                 &baseClassTypeDef,
4796                 0, //&templSpec,
4797                 mode==Undocumented,
4798                 TRUE
4799                 );
4800             //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4801             //      baseClass,baseClassName.data(),templSpec.data());
4802           }
4803         }
4804         else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4805                                                     // know it is a template, so see if
4806                                                     // we can also link to the explicit
4807                                                     // instance (for instance if a class
4808                                                     // derived from a template argument)
4809         {
4810           //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4811           ClassDef *templClass=getClass(baseClass->name()+templSpec);
4812           if (templClass)
4813           {
4814             // use the template instance instead of the template base.
4815             baseClass = templClass;
4816             templSpec.resize(0);
4817           }
4818         }
4819
4820         //printf("cd=%p baseClass=%p\n",cd,baseClass);
4821         bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4822         //printf("1. found=%d\n",found);
4823         if (!found && si!=-1)
4824         {
4825           QCString tmpTemplSpec;
4826           // replace any namespace aliases
4827           replaceNamespaceAliases(baseClassName,si);
4828           baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4829                                      cd->getFileDef(),
4830                                      baseClassName,
4831                                      &baseClassTypeDef,
4832                                      &tmpTemplSpec,
4833                                      mode==Undocumented,
4834                                      TRUE
4835                                     );
4836           found=baseClass!=0 && baseClass!=cd;
4837           if (found) templSpec = tmpTemplSpec;
4838         }
4839         //printf("2. found=%d\n",found);
4840
4841         //printf("root->name=%s biName=%s baseClassName=%s\n",
4842         //        root->name.data(),biName.data(),baseClassName.data());
4843         //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4844         //{
4845         //  baseClassName+="-g";
4846         //}
4847
4848         if (!found)
4849         {
4850           baseClass=findClassWithinClassContext(context,cd,baseClassName);
4851           //printf("findClassWithinClassContext(%s,%s)=%p\n",
4852           //    cd->name().data(),baseClassName.data(),baseClass);
4853           found = baseClass!=0 && baseClass!=cd;
4854
4855         }
4856         if (!found)
4857         {
4858           // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4859           // the class name also in the alias mapping.
4860           QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4861           if (aliasName) // see if it is indeed a class.
4862           {
4863             baseClass=getClass(*aliasName);
4864             found = baseClass!=0 && baseClass!=cd;
4865           }
4866         }
4867         bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4868         // make templSpec canonical
4869         // warning: the following line doesn't work for Mixin classes (see bug 560623)
4870         // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4871
4872         //printf("3. found=%d\n",found);
4873         if (found)
4874         {
4875           Debug::print(Debug::Classes,0,"    Documented base class `%s' templSpec=%s\n",qPrint(biName),qPrint(templSpec));
4876           // add base class to this class
4877
4878           // if templSpec is not empty then we should "instantiate"
4879           // the template baseClass. A new ClassDef should be created
4880           // to represent the instance. To be able to add the (instantiated)
4881           // members and documentation of a template class
4882           // (inserted in that template class at a later stage),
4883           // the template should know about its instances.
4884           // the instantiation process, should be done in a recursive way,
4885           // since instantiating a template may introduce new inheritance
4886           // relations.
4887           if (!templSpec.isEmpty() && mode==TemplateInstances)
4888           {
4889             // if baseClass is actually a typedef then we should not
4890             // instantiate it, since typedefs are in a different namespace
4891             // see bug531637 for an example where this would otherwise hang
4892             // doxygen
4893             if (baseClassTypeDef==0)
4894             {
4895               //printf("       => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4896               findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4897             }
4898           }
4899           else if (mode==DocumentedOnly || mode==Undocumented)
4900           {
4901             //printf("       => insert base class\n");
4902             QCString usedName;
4903             if (baseClassTypeDef || cd->isCSharp())
4904             {
4905               usedName=biName;
4906               //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4907             }
4908             static bool sipSupport = Config_getBool(SIP_SUPPORT);
4909             if (sipSupport) bi->prot=Public;
4910             if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4911             {
4912               cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4913               // add this class as super class to the base class
4914               baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4915             }
4916             else
4917             {
4918               warn(root->fileName,root->startLine,
4919                   "Detected potential recursive class relation "
4920                   "between class %s and base class %s!",
4921                   cd->name().data(),baseClass->name().data()
4922                   );
4923             }
4924           }
4925           return TRUE;
4926         }
4927         else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4928         {
4929           Debug::print(Debug::Classes,0,
4930                        "    New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4931                        qPrint(biName),qPrint(baseClassName),qPrint(templSpec),isArtificial
4932                       );
4933           baseClass=0;
4934           if (isATemplateArgument)
4935           {
4936             baseClass=Doxygen::hiddenClasses->find(baseClassName);
4937             if (baseClass==0)
4938             {
4939               baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4940                                  baseClassName,
4941                                  ClassDef::Class);
4942               Doxygen::hiddenClasses->append(baseClassName,baseClass);
4943               if (isArtificial) baseClass->setArtificial(TRUE);
4944               baseClass->setLanguage(root->lang);
4945             }
4946           }
4947           else
4948           {
4949             baseClass=Doxygen::classSDict->find(baseClassName);
4950             //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4951             //    baseClassName.data(),baseClass,biName.data(),templSpec.data());
4952             if (baseClass==0)
4953             {
4954               baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4955                   baseClassName,
4956                   ClassDef::Class);
4957               Doxygen::classSDict->append(baseClassName,baseClass);
4958               if (isArtificial) baseClass->setArtificial(TRUE);
4959               baseClass->setLanguage(root->lang);
4960               int si = baseClassName.findRev("::");
4961               if (si!=-1) // class is nested
4962               {
4963                 Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,rootNav->tagInfo());
4964                 if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4965                 {
4966                   baseClass->setArtificial(TRUE); // see bug678139
4967                 }
4968               }
4969             }
4970           }
4971           if (biName.right(2)=="-p")
4972           {
4973             biName="<"+biName.left(biName.length()-2)+">";
4974           }
4975           // add base class to this class
4976           cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4977           // add this class as super class to the base class
4978           baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4979           // the undocumented base was found in this file
4980           baseClass->insertUsedFile(rootNav->fileDef());
4981           baseClass->setOuterScope(Doxygen::globalScope);
4982           if (baseClassName.right(2)=="-p")
4983           {
4984             baseClass->setCompoundType(ClassDef::Protocol);
4985           }
4986           return TRUE;
4987         }
4988         else
4989         {
4990           Debug::print(Debug::Classes,0,"    Base class `%s' not found\n",qPrint(biName));
4991         }
4992       }
4993       else
4994       {
4995         if (mode!=TemplateInstances)
4996         {
4997           warn(root->fileName,root->startLine,
4998               "Detected potential recursive class relation "
4999               "between class %s and base class %s!\n",
5000               root->name.data(),baseClassName.data()
5001               );
5002         }
5003         // for mode==TemplateInstance this case is quite common and
5004         // indicates a relation between a template class and a template
5005         // instance with the same name.
5006       }
5007       if (scopeOffset==0)
5008       {
5009         scopeOffset=-1;
5010       }
5011       else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
5012       {
5013         scopeOffset=0;
5014       }
5015       //printf("new scopeOffset=`%d'",scopeOffset);
5016     } while (scopeOffset>=0);
5017
5018     if (parentNode==0)
5019     {
5020       lastParent=TRUE;
5021     }
5022     else
5023     {
5024       parentNode=parentNode->parent();
5025     }
5026   } while (lastParent);
5027
5028   return FALSE;
5029 }
5030
5031 //----------------------------------------------------------------------
5032 // Computes the base and super classes for each class in the tree
5033
5034 static bool isClassSection(EntryNav *rootNav)
5035 {
5036   if ( !rootNav->name().isEmpty() )
5037   {
5038     if (rootNav->section() & Entry::COMPOUND_MASK)
5039          // is it a compound (class, struct, union, interface ...)
5040     {
5041       return TRUE;
5042     }
5043     else if (rootNav->section() & Entry::COMPOUNDDOC_MASK)
5044          // is it a documentation block with inheritance info.
5045     {
5046       rootNav->loadEntry(g_storage);
5047       Entry *root = rootNav->entry();
5048       bool extends = root->extends->count()>0;
5049       rootNav->releaseEntry();
5050       if (extends) return TRUE;
5051     }
5052   }
5053   return FALSE;
5054 }
5055
5056
5057 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
5058  */
5059 static void findClassEntries(EntryNav *rootNav)
5060 {
5061   if (isClassSection(rootNav))
5062   {
5063     g_classEntries.insert(rootNav->name(),rootNav);
5064   }
5065   RECURSE_ENTRYTREE(findClassEntries,rootNav);
5066 }
5067
5068 static QCString extractClassName(EntryNav *rootNav)
5069 {
5070   // strip any anonymous scopes first
5071   QCString bName=stripAnonymousNamespaceScope(rootNav->name());
5072   bName=stripTemplateSpecifiersFromScope(bName);
5073   int i;
5074   if ((rootNav->lang()==SrcLangExt_CSharp || rootNav->lang()==SrcLangExt_Java) &&
5075       (i=bName.find('<'))!=-1)
5076   {
5077     // a Java/C# generic class looks like a C++ specialization, so we need to strip the
5078     // template part before looking for matches
5079     bName=bName.left(i);
5080   }
5081   return bName;
5082 }
5083
5084 /*! Using the dictionary build by findClassEntries(), this
5085  *  function will look for additional template specialization that
5086  *  exists as inheritance relations only. These instances will be
5087  *  added to the template they are derived from.
5088  */
5089 static void findInheritedTemplateInstances()
5090 {
5091   ClassSDict::Iterator cli(*Doxygen::classSDict);
5092   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5093   QDictIterator<EntryNav> edi(g_classEntries);
5094   EntryNav *rootNav;
5095   for (;(rootNav=edi.current());++edi)
5096   {
5097     ClassDef *cd;
5098     QCString bName = extractClassName(rootNav);
5099     Debug::print(Debug::Classes,0,"  Inheritance: Class %s : \n",qPrint(bName));
5100     if ((cd=getClass(bName)))
5101     {
5102       rootNav->loadEntry(g_storage);
5103       //printf("Class %s %d\n",cd->name().data(),root->extends->count());
5104       findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
5105       rootNav->releaseEntry();
5106     }
5107   }
5108 }
5109
5110 static void findUsedTemplateInstances()
5111 {
5112   ClassSDict::Iterator cli(*Doxygen::classSDict);
5113   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5114   QDictIterator<EntryNav> edi(g_classEntries);
5115   EntryNav *rootNav;
5116   for (;(rootNav=edi.current());++edi)
5117   {
5118     ClassDef *cd;
5119     QCString bName = extractClassName(rootNav);
5120     Debug::print(Debug::Classes,0,"  Usage: Class %s : \n",qPrint(bName));
5121     if ((cd=getClass(bName)))
5122     {
5123       rootNav->loadEntry(g_storage);
5124       findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
5125       cd->addTypeConstraints();
5126       rootNav->releaseEntry();
5127     }
5128   }
5129 }
5130
5131 static void computeClassRelations()
5132 {
5133   ClassSDict::Iterator cli(*Doxygen::classSDict);
5134   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5135   QDictIterator<EntryNav> edi(g_classEntries);
5136   EntryNav *rootNav;
5137   for (;(rootNav=edi.current());++edi)
5138   {
5139     ClassDef *cd;
5140
5141     rootNav->loadEntry(g_storage);
5142     Entry *root = rootNav->entry();
5143     QCString bName = extractClassName(rootNav);
5144     Debug::print(Debug::Classes,0,"  Relations: Class %s : \n",qPrint(bName));
5145     if ((cd=getClass(bName)))
5146     {
5147       findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
5148     }
5149     int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
5150     if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
5151         bName.right(2)!="::")
5152     {
5153       if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
5154           (guessSection(root->fileName)==Entry::HEADER_SEC ||
5155            Config_getBool(EXTRACT_LOCAL_CLASSES)) && // not defined in source file
5156            protectionLevelVisible(root->protection) && // hidden by protection
5157            !Config_getBool(HIDE_UNDOC_CLASSES) // undocumented class are visible
5158          )
5159         warn_undoc(
5160                    root->fileName,root->startLine,
5161                    "Compound %s is not documented.",
5162                    root->name.data()
5163              );
5164     }
5165
5166     rootNav->releaseEntry();
5167   }
5168 }
5169
5170 static void computeTemplateClassRelations()
5171 {
5172   QDictIterator<EntryNav> edi(g_classEntries);
5173   EntryNav *rootNav;
5174   for (;(rootNav=edi.current());++edi)
5175   {
5176     rootNav->loadEntry(g_storage);
5177     Entry *root = rootNav->entry();
5178
5179     QCString bName=stripAnonymousNamespaceScope(root->name);
5180     bName=stripTemplateSpecifiersFromScope(bName);
5181     ClassDef *cd=getClass(bName);
5182     // strip any anonymous scopes first
5183     QDict<ClassDef> *templInstances = 0;
5184     if (cd && (templInstances=cd->getTemplateInstances()))
5185     {
5186       Debug::print(Debug::Classes,0,"  Template class %s : \n",qPrint(cd->name()));
5187       QDictIterator<ClassDef> tdi(*templInstances);
5188       ClassDef *tcd;
5189       for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
5190       {
5191         Debug::print(Debug::Classes,0,"    Template instance %s : \n",qPrint(tcd->name()));
5192         QCString templSpec = tdi.currentKey();
5193         ArgumentList *templArgs = new ArgumentList;
5194         stringToArgumentList(templSpec,templArgs);
5195         QList<BaseInfo> *baseList=root->extends;
5196         QListIterator<BaseInfo> it(*baseList);
5197         BaseInfo *bi;
5198         for (;(bi=it.current());++it) // for each base class of the template
5199         {
5200           // check if the base class is a template argument
5201           BaseInfo tbi(bi->name,bi->prot,bi->virt);
5202           ArgumentList *tl = cd->templateArguments();
5203           if (tl)
5204           {
5205             QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
5206             QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
5207             // for each template name that we inherit from we need to
5208             // substitute the formal with the actual arguments
5209             QDict<int> *actualTemplateNames = new QDict<int>(17);
5210             actualTemplateNames->setAutoDelete(TRUE);
5211             QDictIterator<int> qdi(*templateNames);
5212             for (qdi.toFirst();qdi.current();++qdi)
5213             {
5214               int templIndex = *qdi.current();
5215               Argument *actArg = 0;
5216               if (templIndex<(int)templArgs->count())
5217               {
5218                 actArg=templArgs->at(templIndex);
5219               }
5220               if (actArg!=0 &&
5221                   baseClassNames!=0 &&
5222                   baseClassNames->find(actArg->type)!=0 &&
5223                   actualTemplateNames->find(actArg->type)==0
5224                  )
5225               {
5226                 actualTemplateNames->insert(actArg->type,new int(templIndex));
5227               }
5228             }
5229             delete templateNames;
5230
5231             tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
5232             // find a documented base class in the correct scope
5233             if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
5234             {
5235               // no documented base class -> try to find an undocumented one
5236               findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
5237             }
5238             delete actualTemplateNames;
5239           }
5240         }
5241         delete templArgs;
5242       } // class has no base classes
5243     }
5244
5245     rootNav->releaseEntry();
5246   }
5247 }
5248
5249 //-----------------------------------------------------------------------
5250 // compute the references (anchors in HTML) for each function in the file
5251
5252 static void computeMemberReferences()
5253 {
5254   ClassSDict::Iterator cli(*Doxygen::classSDict);
5255   ClassDef *cd=0;
5256   for (cli.toFirst();(cd=cli.current());++cli)
5257   {
5258     cd->computeAnchors();
5259   }
5260   FileNameListIterator fnli(*Doxygen::inputNameList);
5261   FileName *fn;
5262   for (fnli.toFirst();(fn=fnli.current());++fnli)
5263   {
5264     FileNameIterator fni(*fn);
5265     FileDef *fd;
5266     for (;(fd=fni.current());++fni)
5267     {
5268       fd->computeAnchors();
5269     }
5270   }
5271   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5272   NamespaceDef *nd=0;
5273   for (nli.toFirst();(nd=nli.current());++nli)
5274   {
5275     nd->computeAnchors();
5276   }
5277   GroupSDict::Iterator gli(*Doxygen::groupSDict);
5278   GroupDef *gd;
5279   for (gli.toFirst();(gd=gli.current());++gli)
5280   {
5281     gd->computeAnchors();
5282   }
5283 }
5284
5285 //----------------------------------------------------------------------
5286
5287 static void addListReferences()
5288 {
5289   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
5290   MemberName *mn=0;
5291   for (mnli.toFirst();(mn=mnli.current());++mnli)
5292   {
5293     MemberNameIterator mni(*mn);
5294     MemberDef *md=0;
5295     for (mni.toFirst();(md=mni.current());++mni)
5296     {
5297       md->visited=FALSE;
5298     }
5299   }
5300   MemberNameSDict::Iterator fmnli(*Doxygen::functionNameSDict);
5301   for (fmnli.toFirst();(mn=fmnli.current());++fmnli)
5302   {
5303     MemberNameIterator mni(*mn);
5304     MemberDef *md=0;
5305     for (mni.toFirst();(md=mni.current());++mni)
5306     {
5307       md->visited=FALSE;
5308     }
5309   }
5310
5311   ClassSDict::Iterator cli(*Doxygen::classSDict);
5312   ClassDef *cd=0;
5313   for (cli.toFirst();(cd=cli.current());++cli)
5314   {
5315     cd->addListReferences();
5316   }
5317
5318   FileNameListIterator fnli(*Doxygen::inputNameList);
5319   FileName *fn;
5320   for (fnli.toFirst();(fn=fnli.current());++fnli)
5321   {
5322     FileNameIterator fni(*fn);
5323     FileDef *fd;
5324     for (;(fd=fni.current());++fni)
5325     {
5326       fd->addListReferences();
5327     }
5328   }
5329
5330   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5331   NamespaceDef *nd=0;
5332   for (nli.toFirst();(nd=nli.current());++nli)
5333   {
5334     nd->addListReferences();
5335   }
5336
5337   GroupSDict::Iterator gli(*Doxygen::groupSDict);
5338   GroupDef *gd;
5339   for (gli.toFirst();(gd=gli.current());++gli)
5340   {
5341     gd->addListReferences();
5342   }
5343
5344   PageSDict::Iterator pdi(*Doxygen::pageSDict);
5345   PageDef *pd=0;
5346   for (pdi.toFirst();(pd=pdi.current());++pdi)
5347   {
5348     QCString name = pd->getOutputFileBase();
5349     if (pd->getGroupDef())
5350     {
5351       name = pd->getGroupDef()->getOutputFileBase();
5352     }
5353     {
5354       QList<ListItemInfo> *xrefItems = pd->xrefListItems();
5355       addRefItem(xrefItems,
5356           name,
5357           theTranslator->trPage(TRUE,TRUE),
5358           name,pd->title(),0,0);
5359     }
5360   }
5361
5362   DirSDict::Iterator ddi(*Doxygen::directories);
5363   DirDef *dd = 0;
5364   for (ddi.toFirst();(dd=ddi.current());++ddi)
5365   {
5366     QCString name = dd->getOutputFileBase();
5367     //if (dd->getGroupDef())
5368     //{
5369     //  name = dd->getGroupDef()->getOutputFileBase();
5370     //}
5371     QList<ListItemInfo> *xrefItems = dd->xrefListItems();
5372     addRefItem(xrefItems,
5373         name,
5374         theTranslator->trDir(TRUE,TRUE),
5375         name,dd->displayName(),0,0);
5376   }
5377 }
5378
5379 //----------------------------------------------------------------------
5380
5381 static void generateXRefPages()
5382 {
5383   QDictIterator<RefList> di(*Doxygen::xrefLists);
5384   RefList *rl;
5385   for (di.toFirst();(rl=di.current());++di)
5386   {
5387     rl->generatePage();
5388   }
5389 }
5390
5391 //----------------------------------------------------------------------
5392 // Copy the documentation in entry `root' to member definition `md' and
5393 // set the function declaration of the member to `funcDecl'. If the boolean
5394 // over_load is set the standard overload text is added.
5395
5396 static void addMemberDocs(EntryNav *rootNav,
5397                    MemberDef *md, const char *funcDecl,
5398                    ArgumentList *al,
5399                    bool over_load,
5400                    NamespaceSDict *
5401                   )
5402 {
5403   Entry *root = rootNav->entry();
5404   //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
5405   //     root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
5406   QCString fDecl=funcDecl;
5407   // strip extern specifier
5408   fDecl.stripPrefix("extern ");
5409   md->setDefinition(fDecl);
5410   md->enableCallGraph(root->callGraph);
5411   md->enableCallerGraph(root->callerGraph);
5412   md->enableReferencedByRelation(root->referencedByRelation);
5413   md->enableReferencesRelation(root->referencesRelation);
5414   ClassDef     *cd=md->getClassDef();
5415   NamespaceDef *nd=md->getNamespaceDef();
5416   QCString fullName;
5417   if (cd)
5418     fullName = cd->name();
5419   else if (nd)
5420     fullName = nd->name();
5421
5422   if (!fullName.isEmpty()) fullName+="::";
5423   fullName+=md->name();
5424   FileDef *rfd=rootNav->fileDef();
5425
5426   // TODO determine scope based on root not md
5427   Definition *rscope = md->getOuterScope();
5428
5429   ArgumentList *mdAl = md->argumentList();
5430   if (al)
5431   {
5432     //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5433     mergeArguments(mdAl,al,!root->doc.isEmpty());
5434   }
5435   else
5436   {
5437     if (
5438           matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
5439                            rscope,rfd,root->argList,
5440                            TRUE
5441                          )
5442        )
5443     {
5444       //printf("merging arguments (2)\n");
5445       mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
5446     }
5447   }
5448   if (over_load)  // the \overload keyword was used
5449   {
5450     QCString doc=getOverloadDocs();
5451     if (!root->doc.isEmpty())
5452     {
5453       doc+="<p>";
5454       doc+=root->doc;
5455     }
5456     md->setDocumentation(doc,root->docFile,root->docLine);
5457     md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5458     md->setDocsForDefinition(!root->proto);
5459   }
5460   else
5461   {
5462     //printf("overwrite!\n");
5463     md->setDocumentation(root->doc,root->docFile,root->docLine);
5464     md->setDocsForDefinition(!root->proto);
5465
5466     //printf("overwrite!\n");
5467     md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5468
5469     if (
5470         (md->inbodyDocumentation().isEmpty() ||
5471          !rootNav->parent()->name().isEmpty()
5472         ) && !root->inbodyDocs.isEmpty()
5473        )
5474     {
5475       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5476     }
5477   }
5478
5479   //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5480   //    md->initializer().data(),md->initializer().isEmpty(),
5481   //    root->initializer.data(),root->initializer.isEmpty()
5482   //   );
5483   if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5484   {
5485     //printf("setInitializer\n");
5486     md->setInitializer(root->initializer);
5487   }
5488
5489   md->setMaxInitLines(root->initLines);
5490
5491   if (rfd)
5492   {
5493     if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5494        )
5495     {
5496       //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5497       md->setBodySegment(root->bodyLine,root->endBodyLine);
5498       md->setBodyDef(rfd);
5499     }
5500
5501     md->setRefItems(root->sli);
5502   }
5503
5504   md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5505   md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5506   md->enableReferencedByRelation(md->hasReferencedByRelation() || root->referencedByRelation);
5507   md->enableReferencesRelation(md->hasReferencesRelation() || root->referencesRelation);
5508
5509   md->mergeMemberSpecifiers(root->spec);
5510   md->addSectionsToDefinition(root->anchors);
5511   addMemberToGroups(root,md);
5512   if (cd) cd->insertUsedFile(rfd);
5513   //printf("root->mGrpId=%d\n",root->mGrpId);
5514   if (root->mGrpId!=-1)
5515   {
5516     if (md->getMemberGroupId()!=-1)
5517     {
5518       if (md->getMemberGroupId()!=root->mGrpId)
5519       {
5520         warn(
5521              root->fileName,root->startLine,
5522              "member %s belongs to two different groups. The second "
5523              "one found here will be ignored.",
5524              md->name().data()
5525             );
5526       }
5527     }
5528     else // set group id
5529     {
5530       //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5531       md->setMemberGroupId(root->mGrpId);
5532     }
5533   }
5534 }
5535
5536 //----------------------------------------------------------------------
5537 // find a class definition given the scope name and (optionally) a
5538 // template list specifier
5539
5540 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5541                          const char *scopeName)
5542 {
5543   ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5544   return tcd;
5545 }
5546
5547
5548 //----------------------------------------------------------------------
5549 // Adds the documentation contained in `root' to a global function
5550 // with name `name' and argument list `args' (for overloading) and
5551 // function declaration `decl' to the corresponding member definition.
5552
5553 static bool findGlobalMember(EntryNav *rootNav,
5554                            const QCString &namespaceName,
5555                            const char *type,
5556                            const char *name,
5557                            const char *tempArg,
5558                            const char *,
5559                            const char *decl)
5560 {
5561   Entry *root = rootNav->entry();
5562   Debug::print(Debug::FindMembers,0,
5563        "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5564           qPrint(namespaceName),qPrint(type),qPrint(name),qPrint(tempArg),qPrint(decl));
5565   QCString n=name;
5566   if (n.isEmpty()) return FALSE;
5567   if (n.find("::")!=-1) return FALSE; // skip undefined class members
5568   MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5569   if (mn==0)
5570   {
5571     mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5572   }
5573   if (mn) // function name defined
5574   {
5575     Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5576     //int count=0;
5577     MemberNameIterator mni(*mn);
5578     MemberDef *md;
5579     bool found=FALSE;
5580     for (mni.toFirst();(md=mni.current()) && !found;++mni)
5581     {
5582       NamespaceDef *nd=md->getNamespaceDef();
5583
5584       //printf("Namespace namespaceName=%s nd=%s\n",
5585       //    namespaceName.data(),nd ? nd->name().data() : "<none>");
5586
5587       FileDef *fd=rootNav->fileDef();
5588       //printf("File %s\n",fd ? fd->name().data() : "<none>");
5589       NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5590       //SDict<Definition> *cl = fd ? fd->getUsedClasses()    : 0;
5591       //printf("NamespaceList %p\n",nl);
5592
5593       // search in the list of namespaces that are imported via a
5594       // using declaration
5595       bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5596
5597       if ((namespaceName.isEmpty() && nd==0) ||  // not in a namespace
5598           (nd && nd->name()==namespaceName) ||   // or in the same namespace
5599           viaUsingDirective                      // member in `using' namespace
5600          )
5601       {
5602         Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5603             qPrint(md->name()),qPrint(namespaceName));
5604
5605         NamespaceDef *rnd = 0;
5606         if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5607
5608         ArgumentList *mdAl = md->argumentList();
5609         bool matching=
5610           (mdAl==0 && root->argList->count()==0) ||
5611           md->isVariable() || md->isTypedef() || /* in case of function pointers */
5612           matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl,
5613                           rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5614                           FALSE);
5615
5616         // for template members we need to check if the number of
5617         // template arguments is the same, otherwise we are dealing with
5618         // different functions.
5619         if (matching && root->tArgLists)
5620         {
5621           ArgumentList *mdTempl = md->templateArguments();
5622           if (mdTempl)
5623           {
5624             if (root->tArgLists->getLast()->count()!=mdTempl->count())
5625             {
5626               matching=FALSE;
5627             }
5628           }
5629         }
5630
5631         //printf("%s<->%s\n",
5632         //    argListToString(md->argumentList()).data(),
5633         //    argListToString(root->argList).data());
5634
5635         // for static members we also check if the comment block was found in
5636         // the same file. This is needed because static members with the same
5637         // name can be in different files. Thus it would be wrong to just
5638         // put the comment block at the first syntactically matching member.
5639         if (matching && md->isStatic() &&
5640             md->getDefFileName()!=root->fileName &&
5641             mn->count()>1)
5642         {
5643           matching = FALSE;
5644         }
5645
5646         // for template member we also need to check the return type
5647         if (md->templateArguments()!=0 && root->tArgLists!=0)
5648         {
5649           //printf("Comparing return types '%s'<->'%s'\n",
5650           //    md->typeString(),type);
5651           if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
5652               qstrcmp(md->typeString(),type)!=0)
5653           {
5654             //printf(" ---> no matching\n");
5655             matching = FALSE;
5656           }
5657         }
5658
5659         if (matching) // add docs to the member
5660         {
5661           Debug::print(Debug::FindMembers,0,"5. Match found\n");
5662           addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5663           found=TRUE;
5664         }
5665       }
5666     }
5667     if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5668     {
5669       QCString fullFuncDecl=decl;
5670       if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5671       QCString warnMsg =
5672          QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5673       if (mn->count()>0)
5674       {
5675         warnMsg+="\nPossible candidates:\n";
5676         for (mni.toFirst();(md=mni.current());++mni)
5677         {
5678           warnMsg+=" '";
5679           warnMsg+=substitute(md->declaration(),"%","%%");
5680           warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5681                    " of file"+md->getDefFileName()+"\n";
5682         }
5683       }
5684       warn(root->fileName,root->startLine,warnMsg);
5685     }
5686   }
5687   else // got docs for an undefined member!
5688   {
5689     if (root->type!="friend class" &&
5690         root->type!="friend struct" &&
5691         root->type!="friend union" &&
5692         root->type!="friend" &&
5693         (!Config_getBool(TYPEDEF_HIDES_STRUCT) ||
5694          root->type.find("typedef ")==-1)
5695        )
5696     {
5697       warn(root->fileName,root->startLine,
5698            "documented symbol `%s' was not declared or defined.",decl
5699           );
5700     }
5701   }
5702   return TRUE;
5703 }
5704
5705 static bool isSpecialization(
5706                   const QList<ArgumentList> &srcTempArgLists,
5707                   const QList<ArgumentList> &dstTempArgLists
5708     )
5709 {
5710     QListIterator<ArgumentList> srclali(srcTempArgLists);
5711     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5712     for (;srclali.current();++srclali,++dstlali)
5713     {
5714       ArgumentList *sal = srclali.current();
5715       ArgumentList *dal = dstlali.current();
5716       if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5717     }
5718     return FALSE;
5719 }
5720
5721 static bool scopeIsTemplate(Definition *d)
5722 {
5723   bool result=FALSE;
5724   if (d && d->definitionType()==Definition::TypeClass)
5725   {
5726     result = ((ClassDef*)d)->templateArguments() || scopeIsTemplate(d->getOuterScope());
5727   }
5728   return result;
5729 }
5730
5731 static QCString substituteTemplatesInString(
5732     const QList<ArgumentList> &srcTempArgLists,
5733     const QList<ArgumentList> &dstTempArgLists,
5734     ArgumentList *funcTempArgList, // can be used to match template specializations
5735     const QCString &src
5736     )
5737 {
5738   QCString dst;
5739   QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5740   //printf("type=%s\n",sa->type.data());
5741   int i,p=0,l;
5742   while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5743   {
5744     bool found=FALSE;
5745     dst+=src.mid(p,i-p);
5746     QCString name=src.mid(i,l);
5747
5748     QListIterator<ArgumentList> srclali(srcTempArgLists);
5749     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5750     for (;srclali.current() && !found;++srclali,++dstlali)
5751     {
5752       ArgumentListIterator tsali(*srclali.current());
5753       ArgumentListIterator tdali(*dstlali.current());
5754       ArgumentListIterator *fali=0;
5755       Argument *tsa =0,*tda=0, *fa=0;
5756       if (funcTempArgList)
5757       {
5758         fali = new ArgumentListIterator(*funcTempArgList);
5759         fa = fali->current();
5760       }
5761
5762       for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5763       {
5764         tda = tdali.current();
5765         //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5766         //    tsa->type.data(),tsa->name.data(),
5767         //    tda->type.data(),tda->name.data());
5768         if (name==tsa->name)
5769         {
5770           if (tda && tda->name.isEmpty())
5771           {
5772             int vc=0;
5773             if (tda->type.left(6)=="class ") vc=6;
5774             else if (tda->type.left(9)=="typename ") vc=9;
5775             if (vc>0) // convert type=="class T" to type=="class" name=="T"
5776             {
5777               tda->name = tda->type.mid(vc);
5778               tda->type = tda->type.left(vc-1);
5779             }
5780           }
5781           if (tda && !tda->name.isEmpty())
5782           {
5783             name=tda->name; // substitute
5784             found=TRUE;
5785           }
5786           else if (fa)
5787           {
5788             name=fa->type;
5789             found=TRUE;
5790           }
5791         }
5792         if (tda)
5793           ++tdali;
5794         else if (fali)
5795         { ++(*fali); fa=fali->current(); }
5796       }
5797
5798       delete fali;
5799       //printf("   srcList='%s' dstList='%s faList='%s'\n",
5800       //  argListToString(srclali.current()).data(),
5801       //  argListToString(dstlali.current()).data(),
5802       //  funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5803     }
5804     dst+=name;
5805     p=i+l;
5806   }
5807   dst+=src.right(src.length()-p);
5808   //printf("  substituteTemplatesInString(%s)=%s\n",
5809   //    src.data(),dst.data());
5810   return dst;
5811 }
5812
5813 static void substituteTemplatesInArgList(
5814                   const QList<ArgumentList> &srcTempArgLists,
5815                   const QList<ArgumentList> &dstTempArgLists,
5816                   ArgumentList *src,
5817                   ArgumentList *dst,
5818                   ArgumentList *funcTempArgs = 0
5819                  )
5820 {
5821   ArgumentListIterator sali(*src);
5822   ArgumentListIterator dali(*dst);
5823   Argument *sa=0;
5824   Argument *da=dali.current();
5825
5826   for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5827   {
5828     QCString dstType = substituteTemplatesInString(
5829                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5830                                   sa->type);
5831     QCString dstArray = substituteTemplatesInString(
5832                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5833                                   sa->array);
5834     if (da==0)
5835     {
5836       da=new Argument(*sa);
5837       dst->append(da);
5838       da->type=dstType;
5839       da->array=dstArray;
5840       da=0;
5841     }
5842     else
5843     {
5844       da->type=dstType;
5845       da->type=dstArray;
5846       ++dali;
5847       da=dali.current();
5848     }
5849   }
5850   dst->constSpecifier     = src->constSpecifier;
5851   dst->volatileSpecifier  = src->volatileSpecifier;
5852   dst->pureSpecifier      = src->pureSpecifier;
5853   dst->trailingReturnType = substituteTemplatesInString(
5854                              srcTempArgLists,dstTempArgLists,
5855                              funcTempArgs,src->trailingReturnType);
5856   //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5857   //    argListToString(src).data(),argListToString(dst).data()
5858   //    );
5859 }
5860
5861
5862
5863 /*! This function tries to find a member (in a documented class/file/namespace)
5864  * that corresponds to the function/variable declaration given in \a funcDecl.
5865  *
5866  * The boolean \a overloaded is used to specify whether or not a standard
5867  * overload documentation line should be generated.
5868  *
5869  * The boolean \a isFunc is a hint that indicates that this is a function
5870  * instead of a variable or typedef.
5871  */
5872 static void findMember(EntryNav *rootNav,
5873                        QCString funcDecl,
5874                        bool overloaded,
5875                        bool isFunc
5876                       )
5877 {
5878   Entry *root = rootNav->entry();
5879
5880   Debug::print(Debug::FindMembers,0,
5881                "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5882                "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5883                "spec=%lld lang=%x\n",
5884                root,qPrint(funcDecl),qPrint(root->relates),overloaded,isFunc,root->mGrpId,
5885                root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5886                root->spec,root->lang
5887               );
5888
5889   QCString scopeName;
5890   QCString className;
5891   QCString namespaceName;
5892   QCString funcType;
5893   QCString funcName;
5894   QCString funcArgs;
5895   QCString funcTempList;
5896   QCString exceptions;
5897   QCString funcSpec;
5898   bool isRelated=FALSE;
5899   bool isMemberOf=FALSE;
5900   bool isFriend=FALSE;
5901   bool done;
5902   do
5903   {
5904     done=TRUE;
5905     if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5906     {
5907       isFriend=TRUE;
5908       done=FALSE;
5909     }
5910     if (funcDecl.stripPrefix("inline "))
5911     {
5912       root->spec|=Entry::Inline;
5913       done=FALSE;
5914     }
5915     if (funcDecl.stripPrefix("explicit "))
5916     {
5917       root->spec|=Entry::Explicit;
5918       done=FALSE;
5919     }
5920     if (funcDecl.stripPrefix("mutable "))
5921     {
5922       root->spec|=Entry::Mutable;
5923       done=FALSE;
5924     }
5925     if (funcDecl.stripPrefix("virtual "))
5926     {
5927       done=FALSE;
5928     }
5929   } while (!done);
5930
5931   // delete any ; from the function declaration
5932   int sep;
5933   while ((sep=funcDecl.find(';'))!=-1)
5934   {
5935     funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5936   }
5937
5938   // make sure the first character is a space to simplify searching.
5939   if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5940
5941   // remove some superfluous spaces
5942   funcDecl= substitute(
5943               substitute(
5944                 substitute(funcDecl,"~ ","~"),
5945                 ":: ","::"
5946               ),
5947               " ::","::"
5948             ).stripWhiteSpace();
5949
5950   //printf("funcDecl=`%s'\n",funcDecl.data());
5951   if (isFriend && funcDecl.left(6)=="class ")
5952   {
5953     //printf("friend class\n");
5954     funcDecl=funcDecl.right(funcDecl.length()-6);
5955     funcName = funcDecl.copy();
5956   }
5957   else if (isFriend && funcDecl.left(7)=="struct ")
5958   {
5959     funcDecl=funcDecl.right(funcDecl.length()-7);
5960     funcName = funcDecl.copy();
5961   }
5962   else
5963   {
5964     // extract information from the declarations
5965     parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5966                 funcArgs,funcTempList,exceptions
5967                );
5968   }
5969   //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5970   //    scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5971
5972   // the class name can also be a namespace name, we decide this later.
5973   // if a related class name is specified and the class name could
5974   // not be derived from the function declaration, then use the
5975   // related field.
5976   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5977   //    scopeName.data(),className.data(),namespaceName.data());
5978   if (!root->relates.isEmpty())
5979   {                             // related member, prefix user specified scope
5980     isRelated=TRUE;
5981     isMemberOf=(root->relatesType == MemberOf);
5982     if (getClass(root->relates)==0 && !scopeName.isEmpty())
5983     {
5984       scopeName= mergeScopes(scopeName,root->relates);
5985     }
5986     else
5987     {
5988       scopeName = root->relates;
5989     }
5990   }
5991
5992   if (root->relates.isEmpty() && rootNav->parent() &&
5993       ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5994        (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5995       ) &&
5996       !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName
5997                                      // with the scope in which it was found
5998   {
5999     QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
6000     if (!scopeName.isEmpty() &&
6001         (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
6002     {
6003       scopeName = joinedName;
6004     }
6005     else
6006     {
6007       scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
6008     }
6009   }
6010   else // see if we can prefix a namespace or class that is used from the file
6011   {
6012      FileDef *fd=rootNav->fileDef();
6013      if (fd)
6014      {
6015        NamespaceSDict *fnl = fd->getUsedNamespaces();
6016        if (fnl)
6017        {
6018          QCString joinedName;
6019          NamespaceDef *fnd;
6020          NamespaceSDict::Iterator nsdi(*fnl);
6021          for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
6022          {
6023            joinedName = fnd->name()+"::"+scopeName;
6024            if (Doxygen::namespaceSDict->find(joinedName))
6025            {
6026              scopeName=joinedName;
6027              break;
6028            }
6029          }
6030        }
6031      }
6032   }
6033   scopeName=stripTemplateSpecifiersFromScope(
6034       removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
6035
6036   // funcSpec contains the last template specifiers of the given scope.
6037   // If this method does not have any template arguments or they are
6038   // empty while funcSpec is not empty we assume this is a
6039   // specialization of a method. If not, we clear the funcSpec and treat
6040   // this as a normal method of a template class.
6041   if (!(root->tArgLists &&
6042         root->tArgLists->count()>0 &&
6043         root->tArgLists->getFirst()->count()==0
6044        )
6045      )
6046   {
6047     funcSpec.resize(0);
6048   }
6049
6050   // split scope into a namespace and a class part
6051   extractNamespaceName(scopeName,className,namespaceName,TRUE);
6052   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
6053   //       scopeName.data(),className.data(),namespaceName.data());
6054
6055   //namespaceName=removeAnonymousScopes(namespaceName);
6056   if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
6057
6058   //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
6059   // merge class and namespace scopes again
6060   scopeName.resize(0);
6061   if (!namespaceName.isEmpty())
6062   {
6063     if (className.isEmpty())
6064     {
6065       scopeName=namespaceName;
6066     }
6067     else if (!root->relates.isEmpty() || // relates command with explicit scope
6068              !getClass(className)) // class name only exists in a namespace
6069     {
6070       scopeName=namespaceName+"::"+className;
6071     }
6072     else
6073     {
6074       scopeName=className;
6075     }
6076   }
6077   else if (!className.isEmpty())
6078   {
6079     scopeName=className;
6080   }
6081   //printf("new scope=`%s'\n",scopeName.data());
6082
6083   QCString tempScopeName=scopeName;
6084   ClassDef *cd=getClass(scopeName);
6085   if (cd)
6086   {
6087     if (funcSpec.isEmpty())
6088     {
6089       int argListIndex=0;
6090       tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists,&argListIndex);
6091     }
6092     else
6093     {
6094       tempScopeName=scopeName+funcSpec;
6095     }
6096   }
6097   //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
6098   //    scopeName.data(),cd,root->tArgLists,tempScopeName.data());
6099
6100   //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6101   // rebuild the function declaration (needed to get the scope right).
6102   if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool(HIDE_SCOPE_NAMES))
6103   {
6104     if (!funcType.isEmpty())
6105     {
6106       if (isFunc) // a function -> we use argList for the arguments
6107       {
6108         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
6109       }
6110       else
6111       {
6112         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
6113       }
6114     }
6115     else
6116     {
6117       if (isFunc) // a function => we use argList for the arguments
6118       {
6119         funcDecl=tempScopeName+"::"+funcName+funcTempList;
6120       }
6121       else // variable => add `argument' list
6122       {
6123         funcDecl=tempScopeName+"::"+funcName+funcArgs;
6124       }
6125     }
6126   }
6127   else // build declaration without scope
6128   {
6129     if (!funcType.isEmpty()) // but with a type
6130     {
6131       if (isFunc) // function => omit argument list
6132       {
6133         funcDecl=funcType+" "+funcName+funcTempList;
6134       }
6135       else // variable => add `argument' list
6136       {
6137         funcDecl=funcType+" "+funcName+funcArgs;
6138       }
6139     }
6140     else // no type
6141     {
6142       if (isFunc)
6143       {
6144         funcDecl=funcName+funcTempList;
6145       }
6146       else
6147       {
6148         funcDecl=funcName+funcArgs;
6149       }
6150     }
6151   }
6152
6153   if (funcType=="template class" && !funcTempList.isEmpty())
6154     return;   // ignore explicit template instantiations
6155
6156   Debug::print(Debug::FindMembers,0,
6157            "findMember() Parse results:\n"
6158            "  namespaceName=`%s'\n"
6159            "  className=`%s`\n"
6160            "  funcType=`%s'\n"
6161            "  funcSpec=`%s'\n"
6162            "  funcName=`%s'\n"
6163            "  funcArgs=`%s'\n"
6164            "  funcTempList=`%s'\n"
6165            "  funcDecl=`%s'\n"
6166            "  related=`%s'\n"
6167            "  exceptions=`%s'\n"
6168            "  isRelated=%d\n"
6169            "  isMemberOf=%d\n"
6170            "  isFriend=%d\n"
6171            "  isFunc=%d\n\n",
6172            qPrint(namespaceName),qPrint(className),
6173            qPrint(funcType),qPrint(funcSpec),qPrint(funcName),qPrint(funcArgs),qPrint(funcTempList),
6174            qPrint(funcDecl),qPrint(root->relates),qPrint(exceptions),isRelated,isMemberOf,isFriend,
6175            isFunc
6176           );
6177
6178   MemberName *mn=0;
6179   if (!funcName.isEmpty()) // function name is valid
6180   {
6181     Debug::print(Debug::FindMembers,0,
6182                  "1. funcName=`%s'\n",funcName.data());
6183     if (funcName.left(9)=="operator ") // strip class scope from cast operator
6184     {
6185       funcName = substitute(funcName,className+"::","");
6186     }
6187     if (!funcTempList.isEmpty()) // try with member specialization
6188     {
6189       mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
6190     }
6191     if (mn==0) // try without specialization
6192     {
6193       mn=Doxygen::memberNameSDict->find(funcName);
6194     }
6195     if (!isRelated && mn) // function name already found
6196     {
6197       Debug::print(Debug::FindMembers,0,
6198                    "2. member name exists (%d members with this name)\n",mn->count());
6199       if (!className.isEmpty()) // class name is valid
6200       {
6201         if (funcSpec.isEmpty()) // not a member specialization
6202         {
6203           int count=0;
6204           int noMatchCount=0;
6205           MemberNameIterator mni(*mn);
6206           MemberDef *md;
6207           bool memFound=FALSE;
6208           for (mni.toFirst();!memFound && (md=mni.current());++mni)
6209           {
6210             ClassDef *cd=md->getClassDef();
6211             Debug::print(Debug::FindMembers,0,
6212                 "3. member definition found, "
6213                 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
6214                 qPrint(scopeName),cd ? qPrint(cd->name()) : "<none>",
6215                 qPrint(md->argsString()),
6216                 qPrint(root->fileName));
6217             //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
6218             FileDef *fd=rootNav->fileDef();
6219             NamespaceDef *nd=0;
6220             if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
6221
6222             //printf("scopeName %s->%s\n",scopeName.data(),
6223             //       stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
6224
6225             ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
6226             if (tcd==0 && cd && stripAnonymousNamespaceScope(cd->name())==scopeName)
6227             {
6228               // don't be fooled by anonymous scopes
6229               tcd=cd;
6230             }
6231             //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
6232             //    scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
6233
6234             if (cd && tcd==cd) // member's classes match
6235             {
6236               Debug::print(Debug::FindMembers,0,
6237                   "4. class definition %s found\n",cd->name().data());
6238
6239               // get the template parameter lists found at the member declaration
6240               QList<ArgumentList> declTemplArgs;
6241               cd->getTemplateParameterLists(declTemplArgs);
6242               ArgumentList *templAl = md->templateArguments();
6243               if (templAl)
6244               {
6245                 declTemplArgs.append(templAl);
6246               }
6247
6248               // get the template parameter lists found at the member definition
6249               QList<ArgumentList> *defTemplArgs = root->tArgLists;
6250               //printf("defTemplArgs=%p\n",defTemplArgs);
6251
6252               // do we replace the decl argument lists with the def argument lists?
6253               bool substDone=FALSE;
6254               ArgumentList *argList=0;
6255
6256               /* substitute the occurrences of class template names in the
6257                * argument list before matching
6258                */
6259               ArgumentList *mdAl = md->argumentList();
6260               if (declTemplArgs.count()>0 && defTemplArgs &&
6261                   declTemplArgs.count()==defTemplArgs->count() &&
6262                   mdAl
6263                  )
6264               {
6265                 /* the function definition has template arguments
6266                  * and the class definition also has template arguments, so
6267                  * we must substitute the template names of the class by that
6268                  * of the function definition before matching.
6269                  */
6270                 argList = new ArgumentList;
6271                 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
6272                     mdAl,argList);
6273
6274                 substDone=TRUE;
6275               }
6276               else /* no template arguments, compare argument lists directly */
6277               {
6278                 argList = mdAl;
6279               }
6280
6281               Debug::print(Debug::FindMembers,0,
6282                   "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
6283                   qPrint(argListToString(argList,TRUE)),qPrint(argListToString(root->argList,TRUE)),
6284                   qPrint(className),qPrint(namespaceName)
6285                   );
6286
6287               bool matching=
6288                 md->isVariable() || md->isTypedef() || // needed for function pointers
6289                 (mdAl==0 && root->argList->count()==0) ||
6290                 matchArguments2(
6291                     md->getClassDef(),md->getFileDef(),argList,
6292                     cd,fd,root->argList,
6293                     TRUE);
6294
6295               if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
6296               {
6297                 matching = FALSE; // don't match methods and attributes with the same name
6298               }
6299
6300               // for template member we also need to check the return type
6301               if (md->templateArguments()!=0 && root->tArgLists!=0)
6302               {
6303                 QCString memType = md->typeString();
6304                 memType.stripPrefix("static "); // see bug700696
6305                 funcType=substitute(stripTemplateSpecifiersFromScope(funcType,TRUE),
6306                                     className+"::",""); // see bug700693 & bug732594
6307                 memType=substitute(stripTemplateSpecifiersFromScope(memType,TRUE),
6308                                     className+"::",""); // see bug758900
6309                 Debug::print(Debug::FindMembers,0,
6310                    "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
6311                     qPrint(md->typeString()),qPrint(funcType),
6312                     md->templateArguments()->count(),root->tArgLists->getLast()->count());
6313                 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
6314                     qstrcmp(memType,funcType))
6315                 {
6316                   //printf(" ---> no matching\n");
6317                   matching = FALSE;
6318                 }
6319               }
6320               bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
6321               bool classIsTemplate = scopeIsTemplate(md->getClassDef());
6322               bool mdIsTemplate    = md->templateArguments()!=0;
6323               bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
6324               bool rootIsTemplate  = root->tArgLists!=0;
6325               //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
6326               if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
6327                   (mdIsTemplate || rootIsTemplate) && // either md or root is a template
6328                   ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
6329                  )
6330               {
6331                 // Method with template return type does not match method without return type
6332                 // even if the parameters are the same. See also bug709052
6333                 Debug::print(Debug::FindMembers,0,
6334                     "5b. Comparing return types: template v.s. non-template\n");
6335                 matching = FALSE;
6336               }
6337
6338
6339               Debug::print(Debug::FindMembers,0,
6340                   "6. match results of matchArguments2 = %d\n",matching);
6341
6342               if (substDone) // found a new argument list
6343               {
6344                 if (matching) // replace member's argument list
6345                 {
6346                   md->setDefinitionTemplateParameterLists(root->tArgLists);
6347                   md->setArgumentList(argList); // new owner of the list => no delete
6348                 }
6349                 else // no match
6350                 {
6351                   if (!funcTempList.isEmpty() &&
6352                       isSpecialization(declTemplArgs,*defTemplArgs))
6353                   {
6354                     // check if we are dealing with a partial template
6355                     // specialization. In this case we add it to the class
6356                     // even though the member arguments do not match.
6357
6358                     // TODO: copy other aspects?
6359                     root->protection=md->protection(); // copy protection level
6360                     addMethodToClass(rootNav,cd,md->name(),isFriend);
6361                     return;
6362                   }
6363                   delete argList;
6364                 }
6365               }
6366               if (matching)
6367               {
6368                 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
6369                 count++;
6370                 memFound=TRUE;
6371               }
6372             }
6373             else if (cd && cd!=tcd) // we did find a class with the same name as cd
6374                                     // but in a different namespace
6375             {
6376               noMatchCount++;
6377             }
6378           }
6379           if (count==0 && rootNav->parent() &&
6380               rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6381           {
6382             goto localObjCMethod;
6383           }
6384           if (count==0 && !(isFriend && funcType=="class"))
6385           {
6386             int candidates=0;
6387             ClassDef *ecd = 0, *ucd = 0;
6388             MemberDef *emd = 0, *umd = 0;
6389             if (mn->count()>0)
6390             {
6391               //printf("Assume template class\n");
6392               for (mni.toFirst();(md=mni.current());++mni)
6393               {
6394                 ClassDef *ccd=md->getClassDef();
6395                 MemberDef *cmd=md;
6396                 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
6397                 if (ccd!=0 && rightScopeMatch(ccd->name(),className))
6398                 {
6399                   ArgumentList *templAl = md->templateArguments();
6400                   if (root->tArgLists && templAl!=0 &&
6401                       root->tArgLists->getLast()->count()<=templAl->count())
6402                   {
6403                     addMethodToClass(rootNav,ccd,md->name(),isFriend);
6404                     return;
6405                   }
6406                   if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
6407                   { // exact argument list match -> remember
6408                     ucd = ecd = ccd;
6409                     umd = emd = cmd;
6410                     Debug::print(Debug::FindMembers,0,
6411                      "7. new candidate className=%s scope=%s args=%s exact match\n",
6412                          qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6413                   }
6414                   else // arguments do not match, but member name and scope do -> remember
6415                   {
6416                     ucd = ccd;
6417                     umd = cmd;
6418                     Debug::print(Debug::FindMembers,0,
6419                      "7. new candidate className=%s scope=%s args=%s no match\n",
6420                          qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6421                   }
6422                   candidates++;
6423                 }
6424               }
6425             }
6426             static bool strictProtoMatching = Config_getBool(STRICT_PROTO_MATCHING);
6427             if (!strictProtoMatching)
6428             {
6429               if (candidates==1 && ucd && umd)
6430               {
6431                 // we didn't find an actual match on argument lists, but there is only 1 member with this
6432                 // name in the same scope, so that has to be the one.
6433                 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
6434                 return;
6435               }
6436               else if (candidates>1 && ecd && emd)
6437               {
6438                 // we didn't find a unique match using type resolution,
6439                 // but one of the matches has the exact same signature so
6440                 // we take that one.
6441                 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
6442                 return;
6443               }
6444             }
6445
6446             QCString warnMsg = "no ";
6447             if (noMatchCount>1) warnMsg+="uniquely ";
6448             warnMsg+="matching class member found for \n";
6449
6450             if (root->tArgLists)
6451             {
6452               QListIterator<ArgumentList> alli(*root->tArgLists);
6453               ArgumentList *al;
6454               for (;(al=alli.current());++alli)
6455               {
6456                 warnMsg+="  template ";
6457                 warnMsg+=tempArgListToString(al,root->lang);
6458                 warnMsg+='\n';
6459               }
6460             }
6461             QCString fullFuncDecl=funcDecl.copy();
6462             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6463
6464             warnMsg+="  ";
6465             warnMsg+=fullFuncDecl;
6466             warnMsg+='\n';
6467
6468             if (candidates>0)
6469             {
6470               warnMsg+="Possible candidates:\n";
6471               for (mni.toFirst();(md=mni.current());++mni)
6472               {
6473                 ClassDef *cd=md->getClassDef();
6474                 if (cd!=0 && rightScopeMatch(cd->name(),className))
6475                 {
6476                   ArgumentList *templAl = md->templateArguments();
6477                   if (templAl!=0)
6478                   {
6479                     warnMsg+="  'template ";
6480                     warnMsg+=tempArgListToString(templAl,root->lang);
6481                     warnMsg+='\n';
6482                   }
6483                   warnMsg+="  ";
6484                   if (md->typeString())
6485                   {
6486                     warnMsg+=md->typeString();
6487                     warnMsg+=' ';
6488                   }
6489                   QCString qScope = cd->qualifiedNameWithTemplateParameters();
6490                   if (!qScope.isEmpty())
6491                     warnMsg+=qScope+"::"+md->name();
6492                   if (md->argsString())
6493                     warnMsg+=md->argsString();
6494                   if (noMatchCount>1)
6495                   {
6496                     warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6497                              " of file "+md->getDefFileName();
6498                   }
6499
6500                   warnMsg+='\n';
6501                 }
6502               }
6503             }
6504             warn_simple(root->fileName,root->startLine,warnMsg);
6505           }
6506         }
6507         else if (cd) // member specialization
6508         {
6509           MemberNameIterator mni(*mn);
6510           MemberDef *declMd=0;
6511           MemberDef *md=0;
6512           for (mni.toFirst();(md=mni.current());++mni)
6513           {
6514             if (md->getClassDef()==cd)
6515             {
6516               // TODO: we should probably also check for matching arguments
6517               declMd = md;
6518               break;
6519             }
6520           }
6521           MemberType mtype=MemberType_Function;
6522           ArgumentList *tArgList = new ArgumentList;
6523           //  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6524           md=new MemberDef(
6525               root->fileName,root->startLine,root->startColumn,
6526               funcType,funcName,funcArgs,exceptions,
6527               declMd ? declMd->protection() : root->protection,
6528               root->virt,root->stat,Member,
6529               mtype,tArgList,root->argList,root->metaData);
6530           //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6531           md->setTagInfo(rootNav->tagInfo());
6532           md->setLanguage(root->lang);
6533           md->setId(root->id);
6534           md->setMemberClass(cd);
6535           md->setTemplateSpecialization(TRUE);
6536           md->setTypeConstraints(root->typeConstr);
6537           md->setDefinition(funcDecl);
6538           md->enableCallGraph(root->callGraph);
6539           md->enableCallerGraph(root->callerGraph);
6540           md->enableReferencedByRelation(root->referencedByRelation);
6541           md->enableReferencesRelation(root->referencesRelation);
6542           md->setDocumentation(root->doc,root->docFile,root->docLine);
6543           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6544           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6545           md->setDocsForDefinition(!root->proto);
6546           md->setPrototype(root->proto);
6547           md->addSectionsToDefinition(root->anchors);
6548           md->setBodySegment(root->bodyLine,root->endBodyLine);
6549           FileDef *fd=rootNav->fileDef();
6550           md->setBodyDef(fd);
6551           md->setMemberSpecifiers(root->spec);
6552           md->setMemberGroupId(root->mGrpId);
6553           mn->append(md);
6554           cd->insertMember(md);
6555           md->setRefItems(root->sli);
6556           delete tArgList;
6557         }
6558         else
6559         {
6560           //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6561           //        scopeName.data(),funcName.data(),funcArgs.data());
6562         }
6563       }
6564       else if (overloaded) // check if the function belongs to only one class
6565       {
6566         // for unique overloaded member we allow the class to be
6567         // omitted, this is to be Qt compatible. Using this should
6568         // however be avoided, because it is error prone
6569         MemberNameIterator mni(*mn);
6570         MemberDef *md=mni.toFirst();
6571         ASSERT(md);
6572         ClassDef *cd=md->getClassDef();
6573         ASSERT(cd);
6574         QCString className=cd->name().copy();
6575         ++mni;
6576         bool unique=TRUE;
6577         for (;(md=mni.current());++mni)
6578         {
6579           ClassDef *cd=md->getClassDef();
6580           if (className!=cd->name()) unique=FALSE;
6581         }
6582         if (unique)
6583         {
6584           MemberType mtype;
6585           if      (root->mtype==Signal)  mtype=MemberType_Signal;
6586           else if (root->mtype==Slot)    mtype=MemberType_Slot;
6587           else if (root->mtype==DCOP)    mtype=MemberType_DCOP;
6588           else                           mtype=MemberType_Function;
6589
6590           // new overloaded member function
6591           ArgumentList *tArgList =
6592             getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6593           //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6594           MemberDef *md=new MemberDef(
6595               root->fileName,root->startLine,root->startColumn,
6596               funcType,funcName,funcArgs,exceptions,
6597               root->protection,root->virt,root->stat,Related,
6598               mtype,tArgList,root->argList,root->metaData);
6599           md->setTagInfo(rootNav->tagInfo());
6600           md->setLanguage(root->lang);
6601           md->setId(root->id);
6602           md->setTypeConstraints(root->typeConstr);
6603           md->setMemberClass(cd);
6604           md->setDefinition(funcDecl);
6605           md->enableCallGraph(root->callGraph);
6606           md->enableCallerGraph(root->callerGraph);
6607           md->enableReferencedByRelation(root->referencedByRelation);
6608           md->enableReferencesRelation(root->referencesRelation);
6609           QCString doc=getOverloadDocs();
6610           doc+="<p>";
6611           doc+=root->doc;
6612           md->setDocumentation(doc,root->docFile,root->docLine);
6613           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6614           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6615           md->setDocsForDefinition(!root->proto);
6616           md->setPrototype(root->proto);
6617           md->addSectionsToDefinition(root->anchors);
6618           md->setBodySegment(root->bodyLine,root->endBodyLine);
6619           FileDef *fd=rootNav->fileDef();
6620           md->setBodyDef(fd);
6621           md->setMemberSpecifiers(root->spec);
6622           md->setMemberGroupId(root->mGrpId);
6623           mn->append(md);
6624           cd->insertMember(md);
6625           cd->insertUsedFile(fd);
6626           md->setRefItems(root->sli);
6627         }
6628       }
6629       else // unrelated function with the same name as a member
6630       {
6631         if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6632         {
6633           QCString fullFuncDecl=funcDecl.copy();
6634           if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6635           warn(root->fileName,root->startLine,
6636                "Cannot determine class for function\n%s",
6637                fullFuncDecl.data()
6638               );
6639         }
6640       }
6641     }
6642     else if (isRelated && !root->relates.isEmpty())
6643     {
6644       Debug::print(Debug::FindMembers,0,"2. related function\n"
6645               "  scopeName=%s className=%s\n",qPrint(scopeName),qPrint(className));
6646       if (className.isEmpty()) className=root->relates;
6647       ClassDef *cd;
6648       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6649       if ((cd=getClass(scopeName)))
6650       {
6651         bool newMember=TRUE; // assume we have a new member
6652         bool newMemberName=FALSE;
6653         MemberDef *mdDefine=0;
6654         bool isDefine=FALSE;
6655         {
6656           MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6657           if (mn)
6658           {
6659             MemberNameIterator mni(*mn);
6660             mdDefine = mni.current();
6661             while (mdDefine && !isDefine)
6662             {
6663               isDefine = isDefine || mdDefine->isDefine();
6664               if (!isDefine) { ++mni; mdDefine=mni.current(); }
6665             }
6666           }
6667         }
6668
6669         FileDef *fd=rootNav->fileDef();
6670
6671         if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6672         {
6673           mn=new MemberName(funcName);
6674           newMemberName=TRUE; // we create a new member name
6675         }
6676         else
6677         {
6678           MemberNameIterator mni(*mn);
6679           MemberDef *rmd;
6680           while ((rmd=mni.current()) && newMember) // see if we got another member with matching arguments
6681           {
6682             ArgumentList *rmdAl = rmd->argumentList();
6683
6684             newMember=
6685               className!=rmd->getOuterScope()->name() ||
6686               !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6687                                cd,fd,root->argList,
6688                                TRUE);
6689             if (newMember) ++mni;
6690           }
6691           if (!newMember && rmd) // member already exists as rmd -> add docs
6692           {
6693             //printf("addMemberDocs for related member %s\n",root->name.data());
6694             //rmd->setMemberDefTemplateArguments(root->mtArgList);
6695             addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6696           }
6697         }
6698
6699         if (newMember) // need to create a new member
6700         {
6701           MemberType mtype;
6702           if (isDefine)
6703             mtype=MemberType_Define;
6704           else if (root->mtype==Signal)
6705             mtype=MemberType_Signal;
6706           else if (root->mtype==Slot)
6707             mtype=MemberType_Slot;
6708           else if (root->mtype==DCOP)
6709             mtype=MemberType_DCOP;
6710           else
6711             mtype=MemberType_Function;
6712
6713           if (isDefine && mdDefine)
6714           {
6715             mdDefine->setHidden(TRUE);
6716             funcType="#define";
6717             funcArgs=mdDefine->argsString();
6718             funcDecl=funcType + " " + funcName;
6719           }
6720
6721           //printf("New related name `%s' `%d'\n",funcName.data(),
6722           //    root->argList ? (int)root->argList->count() : -1);
6723
6724           // first note that we pass:
6725           //   (root->tArgLists ? root->tArgLists->last() : 0)
6726           // for the template arguments fo the new "member."
6727           // this accurately reflects the template arguments of
6728           // the related function, which don't have to do with
6729           // those of the related class.
6730           MemberDef *md=new MemberDef(
6731               root->fileName,root->startLine,root->startColumn,
6732               funcType,funcName,funcArgs,exceptions,
6733               root->protection,root->virt,
6734               root->stat && !isMemberOf,
6735               isMemberOf ? Foreign : Related,
6736               mtype,
6737               (root->tArgLists ? root->tArgLists->getLast() : 0),
6738               funcArgs.isEmpty() ? 0 : root->argList,root->metaData);
6739
6740           if (isDefine && mdDefine)
6741           {
6742             md->setInitializer(mdDefine->initializer());
6743           }
6744
6745           //
6746           // we still have the problem that
6747           // MemberDef::writeDocumentation() in memberdef.cpp
6748           // writes the template argument list for the class,
6749           // as if this member is a member of the class.
6750           // fortunately, MemberDef::writeDocumentation() has
6751           // a special mechanism that allows us to totally
6752           // override the set of template argument lists that
6753           // are printed.  We use that and set it to the
6754           // template argument lists of the related function.
6755           //
6756           md->setDefinitionTemplateParameterLists(root->tArgLists);
6757
6758           md->setTagInfo(rootNav->tagInfo());
6759
6760
6761
6762           //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6763           //       funcName.data(),funcDecl.data(),root->bodyLine);
6764
6765           // try to find the matching line number of the body from the
6766           // global function list
6767           bool found=FALSE;
6768           if (root->bodyLine==-1)
6769           {
6770             MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6771             if (rmn)
6772             {
6773               MemberNameIterator rmni(*rmn);
6774               MemberDef *rmd;
6775               while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
6776               {
6777                 ArgumentList *rmdAl = rmd->argumentList();
6778                 // check for matching argument lists
6779                 if (
6780                     matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6781                                     cd,fd,root->argList,
6782                                     TRUE)
6783                    )
6784                 {
6785                   found=TRUE;
6786                 }
6787                 if (!found) ++rmni;
6788               }
6789               if (rmd) // member found -> copy line number info
6790               {
6791                 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6792                 md->setBodyDef(rmd->getBodyDef());
6793                 //md->setBodyMember(rmd);
6794               }
6795             }
6796           }
6797           if (!found) // line number could not be found or is available in this
6798                       // entry
6799           {
6800             md->setBodySegment(root->bodyLine,root->endBodyLine);
6801             md->setBodyDef(fd);
6802           }
6803
6804           //if (root->mGrpId!=-1)
6805           //{
6806           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
6807           //}
6808           md->setMemberClass(cd);
6809           md->setMemberSpecifiers(root->spec);
6810           md->setDefinition(funcDecl);
6811           md->enableCallGraph(root->callGraph);
6812           md->enableCallerGraph(root->callerGraph);
6813           md->enableReferencedByRelation(root->referencedByRelation);
6814           md->enableReferencesRelation(root->referencesRelation);
6815           md->setDocumentation(root->doc,root->docFile,root->docLine);
6816           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6817           md->setDocsForDefinition(!root->proto);
6818           md->setPrototype(root->proto);
6819           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6820           md->addSectionsToDefinition(root->anchors);
6821           md->setMemberGroupId(root->mGrpId);
6822           md->setLanguage(root->lang);
6823           md->setId(root->id);
6824           //md->setMemberDefTemplateArguments(root->mtArgList);
6825           mn->append(md);
6826           cd->insertMember(md);
6827           cd->insertUsedFile(fd);
6828           md->setRefItems(root->sli);
6829           if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6830           if (!isDefine)
6831           {
6832             addMemberToGroups(root,md);
6833           }
6834           //printf("Adding member=%s\n",md->name().data());
6835           if (newMemberName)
6836           {
6837             //Doxygen::memberNameList.append(mn);
6838             //Doxygen::memberNameDict.insert(funcName,mn);
6839             Doxygen::memberNameSDict->append(funcName,mn);
6840           }
6841         }
6842         if (root->relatesType == Duplicate)
6843         {
6844           if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6845           {
6846             QCString fullFuncDecl=funcDecl.copy();
6847             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6848             warn(root->fileName,root->startLine,
6849                "Cannot determine file/namespace for relatedalso function\n%s",
6850                fullFuncDecl.data()
6851               );
6852           }
6853         }
6854       }
6855       else
6856       {
6857         warn_undoc(root->fileName,root->startLine,
6858                    "class `%s' for related function `%s' is not "
6859                    "documented.",
6860                    className.data(),funcName.data()
6861                   );
6862       }
6863     }
6864     else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6865     {
6866 localObjCMethod:
6867       ClassDef *cd;
6868       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6869       if (Config_getBool(EXTRACT_LOCAL_METHODS) && (cd=getClass(scopeName)))
6870       {
6871         Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6872               "  scopeName=%s className=%s\n",qPrint(root->name),qPrint(scopeName),qPrint(className));
6873         //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6874         MemberDef *md=new MemberDef(
6875             root->fileName,root->startLine,root->startColumn,
6876             funcType,funcName,funcArgs,exceptions,
6877             root->protection,root->virt,root->stat,Member,
6878             MemberType_Function,0,root->argList,root->metaData);
6879         md->setTagInfo(rootNav->tagInfo());
6880         md->setLanguage(root->lang);
6881         md->setId(root->id);
6882         md->makeImplementationDetail();
6883         md->setMemberClass(cd);
6884         md->setDefinition(funcDecl);
6885         md->enableCallGraph(root->callGraph);
6886         md->enableCallerGraph(root->callerGraph);
6887         md->enableReferencedByRelation(root->referencedByRelation);
6888         md->enableReferencesRelation(root->referencesRelation);
6889         md->setDocumentation(root->doc,root->docFile,root->docLine);
6890         md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6891         md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6892         md->setDocsForDefinition(!root->proto);
6893         md->setPrototype(root->proto);
6894         md->addSectionsToDefinition(root->anchors);
6895         md->setBodySegment(root->bodyLine,root->endBodyLine);
6896         FileDef *fd=rootNav->fileDef();
6897         md->setBodyDef(fd);
6898         md->setMemberSpecifiers(root->spec);
6899         md->setMemberGroupId(root->mGrpId);
6900         cd->insertMember(md);
6901         cd->insertUsedFile(fd);
6902         md->setRefItems(root->sli);
6903         if ((mn=Doxygen::memberNameSDict->find(root->name)))
6904         {
6905           mn->append(md);
6906         }
6907         else
6908         {
6909           mn = new MemberName(root->name);
6910           mn->append(md);
6911           Doxygen::memberNameSDict->append(root->name,mn);
6912         }
6913       }
6914       else
6915       {
6916         // local objective C method found for class without interface
6917       }
6918     }
6919     else // unrelated not overloaded member found
6920     {
6921       bool globMem = findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl);
6922       if (className.isEmpty() && !globMem)
6923       {
6924         warn(root->fileName,root->startLine,
6925              "class for member `%s' cannot "
6926              "be found.", funcName.data()
6927             );
6928       }
6929       else if (!className.isEmpty() && !globMem)
6930       {
6931         warn(root->fileName,root->startLine,
6932              "member `%s' of class `%s' cannot be found",
6933              funcName.data(),className.data());
6934       }
6935     }
6936   }
6937   else
6938   {
6939     // this should not be called
6940     warn(root->fileName,root->startLine,
6941          "member with no name found.");
6942   }
6943   return;
6944 }
6945
6946 //----------------------------------------------------------------------
6947 // find the members corresponding to the different documentation blocks
6948 // that are extracted from the sources.
6949
6950 static void filterMemberDocumentation(EntryNav *rootNav)
6951 {
6952   Entry *root = rootNav->entry();
6953   int i=-1,l;
6954   Debug::print(Debug::FindMembers,0,
6955       "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6956       qPrint(root->type),qPrint(root->inside),qPrint(root->name),qPrint(root->args),root->section,root->spec,root->mGrpId
6957       );
6958   //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6959   bool isFunc=TRUE;
6960
6961   if (root->relatesType == Duplicate && !root->relates.isEmpty())
6962   {
6963     QCString tmp = root->relates;
6964     root->relates.resize(0);
6965     filterMemberDocumentation(rootNav);
6966     root->relates = tmp;
6967   }
6968
6969   if ( // detect func variable/typedef to func ptr
6970       (i=findFunctionPtr(root->type,root->lang,&l))!=-1
6971      )
6972   {
6973     //printf("Fixing function pointer!\n");
6974     // fix type and argument
6975     root->args.prepend(root->type.right(root->type.length()-i-l));
6976     root->type=root->type.left(i+l);
6977     //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6978     isFunc=FALSE;
6979   }
6980   else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1))
6981     // detect function types marked as functions
6982   {
6983     isFunc=FALSE;
6984   }
6985
6986   //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6987   if (root->section==Entry::MEMBERDOC_SEC)
6988   {
6989     //printf("Documentation for inline member `%s' found args=`%s'\n",
6990     //    root->name.data(),root->args.data());
6991     //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
6992     if (root->type.isEmpty())
6993     {
6994       findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6995     }
6996     else
6997     {
6998       findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6999     }
7000   }
7001   else if (root->section==Entry::OVERLOADDOC_SEC)
7002   {
7003     //printf("Overloaded member %s found\n",root->name.data());
7004     findMember(rootNav,root->name,TRUE,isFunc);
7005   }
7006   else if
7007     ((root->section==Entry::FUNCTION_SEC      // function
7008       ||
7009       (root->section==Entry::VARIABLE_SEC &&  // variable
7010        !root->type.isEmpty() &&                // with a type
7011        g_compoundKeywordDict.find(root->type)==0 // that is not a keyword
7012        // (to skip forward declaration of class etc.)
7013       )
7014      )
7015     )
7016     {
7017       //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
7018       //    root->name.data(),root->args.data(),root->exception.data());
7019       //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
7020       //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
7021       if (root->type=="friend class" || root->type=="friend struct" ||
7022           root->type=="friend union")
7023       {
7024         findMember(rootNav,
7025             root->type+" "+
7026             root->name,
7027             FALSE,FALSE);
7028
7029       }
7030       else if (!root->type.isEmpty())
7031       {
7032         findMember(rootNav,
7033             root->type+" "+
7034             root->inside+
7035             root->name+
7036             root->args+
7037             root->exception,
7038             FALSE,isFunc);
7039       }
7040       else
7041       {
7042         findMember(rootNav,
7043             root->inside+
7044             root->name+
7045             root->args+
7046             root->exception,
7047             FALSE,isFunc);
7048       }
7049     }
7050   else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
7051   {
7052     findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
7053   }
7054   else if (root->section==Entry::VARIABLEDOC_SEC)
7055   {
7056     //printf("Documentation for variable %s found\n",root->name.data());
7057     //if (!root->relates.isEmpty()) printf("  Relates %s\n",root->relates.data());
7058     findMember(rootNav,root->name,FALSE,FALSE);
7059   }
7060   else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
7061            root->section==Entry::INCLUDED_SERVICE_SEC)
7062   {
7063     findMember(rootNav,root->type + " " + root->name,FALSE,FALSE);
7064   }
7065   else
7066   {
7067     // skip section
7068     //printf("skip section\n");
7069   }
7070 }
7071
7072 static void findMemberDocumentation(EntryNav *rootNav)
7073 {
7074   if (rootNav->section()==Entry::MEMBERDOC_SEC ||
7075       rootNav->section()==Entry::OVERLOADDOC_SEC ||
7076       rootNav->section()==Entry::FUNCTION_SEC ||
7077       rootNav->section()==Entry::VARIABLE_SEC ||
7078       rootNav->section()==Entry::VARIABLEDOC_SEC ||
7079       rootNav->section()==Entry::DEFINE_SEC ||
7080       rootNav->section()==Entry::INCLUDED_SERVICE_SEC ||
7081       rootNav->section()==Entry::EXPORTED_INTERFACE_SEC
7082      )
7083   {
7084     rootNav->loadEntry(g_storage);
7085
7086     filterMemberDocumentation(rootNav);
7087
7088     rootNav->releaseEntry();
7089   }
7090   if (rootNav->children())
7091   {
7092     EntryNavListIterator eli(*rootNav->children());
7093     EntryNav *e;
7094     for (;(e=eli.current());++eli)
7095     {
7096       if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
7097     }
7098   }
7099 }
7100
7101 //----------------------------------------------------------------------
7102
7103 static void findObjCMethodDefinitions(EntryNav *rootNav)
7104 {
7105   if (rootNav->children())
7106   {
7107     EntryNavListIterator eli(*rootNav->children());
7108     EntryNav *objCImplNav;
7109     for (;(objCImplNav=eli.current());++eli)
7110     {
7111       if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
7112       {
7113         EntryNavListIterator seli(*objCImplNav->children());
7114         EntryNav *objCMethodNav;
7115         for (;(objCMethodNav=seli.current());++seli)
7116         {
7117           if (objCMethodNav->section()==Entry::FUNCTION_SEC)
7118           {
7119             objCMethodNav->loadEntry(g_storage);
7120             Entry *objCMethod = objCMethodNav->entry();
7121
7122             //Printf("  Found ObjC method definition %s\n",objCMethod->name.data());
7123             findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
7124                        objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
7125             objCMethod->section=Entry::EMPTY_SEC;
7126
7127             objCMethodNav->releaseEntry();
7128           }
7129         }
7130       }
7131     }
7132   }
7133 }
7134
7135 //----------------------------------------------------------------------
7136 // find and add the enumeration to their classes, namespaces or files
7137
7138 static void findEnums(EntryNav *rootNav)
7139 {
7140   if (rootNav->section()==Entry::ENUM_SEC)
7141   {
7142     rootNav->loadEntry(g_storage);
7143     Entry *root = rootNav->entry();
7144
7145     MemberDef      *md=0;
7146     ClassDef       *cd=0;
7147     FileDef        *fd=0;
7148     NamespaceDef   *nd=0;
7149     MemberNameSDict *mnsd=0;
7150     bool isGlobal;
7151     bool isRelated=FALSE;
7152     bool isMemberOf=FALSE;
7153     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7154     int i;
7155
7156     QCString name;
7157     QCString scope;
7158
7159     if ((i=root->name.findRev("::"))!=-1) // scope is specified
7160     {
7161       scope=root->name.left(i); // extract scope
7162       name=root->name.right(root->name.length()-i-2); // extract name
7163       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7164     }
7165     else // no scope, check the scope in which the docs where found
7166     {
7167       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7168           && !rootNav->parent()->name().isEmpty()
7169          ) // found enum docs inside a compound
7170       {
7171         scope=rootNav->parent()->name();
7172         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7173       }
7174       name=root->name;
7175     }
7176
7177     if (!root->relates.isEmpty())
7178     {   // related member, prefix user specified scope
7179       isRelated=TRUE;
7180       isMemberOf=(root->relatesType == MemberOf);
7181       if (getClass(root->relates)==0 && !scope.isEmpty())
7182         scope=mergeScopes(scope,root->relates);
7183       else
7184         scope=root->relates.copy();
7185       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7186     }
7187
7188     if (cd && !name.isEmpty()) // found a enum inside a compound
7189     {
7190       //printf("Enum `%s'::`%s'\n",cd->name().data(),name.data());
7191       fd=0;
7192       mnsd=Doxygen::memberNameSDict;
7193       isGlobal=FALSE;
7194     }
7195     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7196     {
7197       mnsd=Doxygen::functionNameSDict;
7198       isGlobal=TRUE;
7199     }
7200     else // found a global enum
7201     {
7202       fd=rootNav->fileDef();
7203       mnsd=Doxygen::functionNameSDict;
7204       isGlobal=TRUE;
7205     }
7206
7207     if (!name.isEmpty())
7208     {
7209       // new enum type
7210       md = new MemberDef(
7211           root->fileName,root->startLine,root->startColumn,
7212           0,name,0,0,
7213           root->protection,Normal,FALSE,
7214           isMemberOf ? Foreign : isRelated ? Related : Member,
7215           MemberType_Enumeration,
7216           0,0,root->metaData);
7217       md->setTagInfo(rootNav->tagInfo());
7218       md->setLanguage(root->lang);
7219       md->setId(root->id);
7220       if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7221       md->setBodySegment(root->bodyLine,root->endBodyLine);
7222       md->setBodyDef(rootNav->fileDef());
7223       md->setMemberSpecifiers(root->spec);
7224       md->setEnumBaseType(root->args);
7225       //printf("Enum %s definition at line %d of %s: protection=%d scope=%s\n",
7226       //    root->name.data(),root->bodyLine,root->fileName.data(),root->protection,cd?cd->name().data():"<none>");
7227       md->addSectionsToDefinition(root->anchors);
7228       md->setMemberGroupId(root->mGrpId);
7229       md->enableCallGraph(root->callGraph);
7230       md->enableCallerGraph(root->callerGraph);
7231       md->enableReferencedByRelation(root->referencedByRelation);
7232       md->enableReferencesRelation(root->referencesRelation);
7233       //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
7234       md->setRefItems(root->sli);
7235       //printf("found enum %s nd=%p\n",md->name().data(),nd);
7236       bool defSet=FALSE;
7237
7238       QCString baseType = root->args;
7239       if (!baseType.isEmpty())
7240       {
7241         baseType.prepend(" : ");
7242       }
7243
7244       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7245       {
7246         if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7247         {
7248           md->setDefinition(name+baseType);
7249         }
7250         else
7251         {
7252           md->setDefinition(nd->name()+"::"+name+baseType);
7253         }
7254         //printf("definition=%s\n",md->definition());
7255         defSet=TRUE;
7256         md->setNamespace(nd);
7257         nd->insertMember(md);
7258       }
7259
7260       // even if we have already added the enum to a namespace, we still
7261       // also want to add it to other appropriate places such as file
7262       // or class.
7263       if (isGlobal)
7264       {
7265         if (!defSet) md->setDefinition(name+baseType);
7266         if (fd==0 && rootNav->parent())
7267         {
7268           fd=rootNav->parent()->fileDef();
7269         }
7270         if (fd)
7271         {
7272           md->setFileDef(fd);
7273           fd->insertMember(md);
7274         }
7275       }
7276       else if (cd)
7277       {
7278         if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7279         {
7280           md->setDefinition(name+baseType);
7281         }
7282         else
7283         {
7284           md->setDefinition(cd->name()+"::"+name+baseType);
7285         }
7286         cd->insertMember(md);
7287         cd->insertUsedFile(fd);
7288       }
7289       md->setDocumentation(root->doc,root->docFile,root->docLine);
7290       md->setDocsForDefinition(!root->proto);
7291       md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7292       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7293
7294       //printf("Adding member=%s\n",md->name().data());
7295       MemberName *mn;
7296       if ((mn=(*mnsd)[name]))
7297       {
7298         // this is used if the same enum is in multiple namespaces/classes
7299         mn->append(md);
7300       }
7301       else // new enum name
7302       {
7303         mn = new MemberName(name);
7304         mn->append(md);
7305         mnsd->append(name,mn);
7306         //printf("add %s to new memberName. Now %d members\n",
7307         //       name.data(),mn->count());
7308       }
7309       addMemberToGroups(root,md);
7310     }
7311     rootNav->releaseEntry();
7312   }
7313   else
7314   {
7315     RECURSE_ENTRYTREE(findEnums,rootNav);
7316   }
7317 }
7318
7319 //----------------------------------------------------------------------
7320
7321 static void addEnumValuesToEnums(EntryNav *rootNav)
7322 {
7323   if (rootNav->section()==Entry::ENUM_SEC)
7324     // non anonymous enumeration
7325   {
7326     rootNav->loadEntry(g_storage);
7327     Entry *root = rootNav->entry();
7328
7329     ClassDef       *cd=0;
7330     FileDef        *fd=0;
7331     NamespaceDef   *nd=0;
7332     MemberNameSDict *mnsd=0;
7333     bool isGlobal;
7334     bool isRelated=FALSE;
7335     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7336     int i;
7337
7338     QCString name;
7339     QCString scope;
7340
7341     if ((i=root->name.findRev("::"))!=-1) // scope is specified
7342     {
7343       scope=root->name.left(i); // extract scope
7344       name=root->name.right(root->name.length()-i-2); // extract name
7345       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7346     }
7347     else // no scope, check the scope in which the docs where found
7348     {
7349       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7350           && !rootNav->parent()->name().isEmpty()
7351          ) // found enum docs inside a compound
7352       {
7353         scope=rootNav->parent()->name();
7354         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7355       }
7356       name=root->name;
7357     }
7358
7359     if (!root->relates.isEmpty())
7360     {   // related member, prefix user specified scope
7361       isRelated=TRUE;
7362       if (getClass(root->relates)==0 && !scope.isEmpty())
7363         scope=mergeScopes(scope,root->relates);
7364       else
7365         scope=root->relates.copy();
7366       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7367     }
7368
7369     if (cd && !name.isEmpty()) // found a enum inside a compound
7370     {
7371       //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
7372       fd=0;
7373       mnsd=Doxygen::memberNameSDict;
7374       isGlobal=FALSE;
7375     }
7376     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7377     {
7378       //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
7379       mnsd=Doxygen::functionNameSDict;
7380       isGlobal=TRUE;
7381     }
7382     else // found a global enum
7383     {
7384       fd=rootNav->fileDef();
7385       //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
7386       mnsd=Doxygen::functionNameSDict;
7387       isGlobal=TRUE;
7388     }
7389
7390     if (!name.isEmpty())
7391     {
7392       //printf("** name=%s\n",name.data());
7393       MemberName *mn = mnsd->find(name); // for all members with this name
7394       if (mn)
7395       {
7396         MemberNameIterator mni(*mn);
7397         MemberDef *md;
7398         for (mni.toFirst(); (md=mni.current()) ; ++mni)  // for each enum in this list
7399         {
7400           if (md->isEnumerate() && rootNav->children())
7401           {
7402             //printf("   enum with %d children\n",rootNav->children()->count());
7403             EntryNavListIterator eli(*rootNav->children()); // for each enum value
7404             EntryNav *e;
7405             for (;(e=eli.current());++eli)
7406             {
7407               SrcLangExt sle;
7408               if (
7409                    (sle=rootNav->lang())==SrcLangExt_CSharp ||
7410                    sle==SrcLangExt_Java ||
7411                    sle==SrcLangExt_XML ||
7412                    (root->spec&Entry::Strong)
7413                  )
7414               {
7415                 // Unlike classic C/C++ enums, for C++11, C# & Java enum
7416                 // values are only visible inside the enum scope, so we must create
7417                 // them here and only add them to the enum
7418                 e->loadEntry(g_storage);
7419                 Entry *root = e->entry();
7420                 //printf("md->qualifiedName()=%s rootNav->name()=%s tagInfo=%p name=%s\n",
7421                 //    md->qualifiedName().data(),rootNav->name().data(),rootNav->tagInfo(),root->name.data());
7422                 QCString qualifiedName = substitute(rootNav->name(),"::",".");
7423                 if (!scope.isEmpty() && rootNav->tagInfo())
7424                 {
7425                   qualifiedName=substitute(scope,"::",".")+"."+qualifiedName;
7426                 }
7427                 if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7428                     qualifiedName       // enum value scope matches that of the enum
7429                    )
7430                 {
7431                   QCString fileName = root->fileName;
7432                   if (fileName.isEmpty() && rootNav->tagInfo())
7433                   {
7434                     fileName = rootNav->tagInfo()->tagName;
7435                   }
7436                   MemberDef *fmd=new MemberDef(
7437                       fileName,root->startLine,root->startColumn,
7438                       root->type,root->name,root->args,0,
7439                       root->protection, Normal,root->stat,Member,
7440                       MemberType_EnumValue,0,0,root->metaData);
7441                   if      (md->getClassDef())     fmd->setMemberClass(md->getClassDef());
7442                   else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
7443                   else if (md->getFileDef())      fmd->setFileDef(md->getFileDef());
7444                   fmd->setOuterScope(md->getOuterScope());
7445                   fmd->setTagInfo(e->tagInfo());
7446                   fmd->setLanguage(root->lang);
7447                   fmd->setId(root->id);
7448                   fmd->setDocumentation(root->doc,root->docFile,root->docLine);
7449                   fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7450                   fmd->addSectionsToDefinition(root->anchors);
7451                   fmd->setInitializer(root->initializer);
7452                   fmd->setMaxInitLines(root->initLines);
7453                   fmd->setMemberGroupId(root->mGrpId);
7454                   fmd->setExplicitExternal(root->explicitExternal);
7455                   fmd->setRefItems(root->sli);
7456                   fmd->setAnchor();
7457                   md->insertEnumField(fmd);
7458                   fmd->setEnumScope(md,TRUE);
7459                   MemberName *mn=mnsd->find(root->name);
7460                   if (mn)
7461                   {
7462                     mn->append(fmd);
7463                   }
7464                   else
7465                   {
7466                     mn = new MemberName(root->name);
7467                     mn->append(fmd);
7468                     mnsd->append(root->name,mn);
7469                   }
7470                 }
7471                 e->releaseEntry();
7472               }
7473               else
7474               {
7475                 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
7476                 MemberName *fmn=0;
7477                 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
7478                 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
7479                   // get list of members with the same name as the field
7480                 {
7481                   MemberNameIterator fmni(*fmn);
7482                   MemberDef *fmd;
7483                   for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
7484                   {
7485                     if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7486                     {
7487                       //printf("found enum value with same name %s in scope %s\n",
7488                       //    fmd->name().data(),fmd->getOuterScope()->name().data());
7489                       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7490                       {
7491                         NamespaceDef *fnd=fmd->getNamespaceDef();
7492                         if (fnd==nd) // enum value is inside a namespace
7493                         {
7494                           md->insertEnumField(fmd);
7495                           fmd->setEnumScope(md);
7496                         }
7497                       }
7498                       else if (isGlobal)
7499                       {
7500                         FileDef *ffd=fmd->getFileDef();
7501                         if (ffd==fd) // enum value has file scope
7502                         {
7503                           md->insertEnumField(fmd);
7504                           fmd->setEnumScope(md);
7505                         }
7506                       }
7507                       else if (isRelated && cd) // reparent enum value to
7508                                                 // match the enum's scope
7509                       {
7510                         md->insertEnumField(fmd);   // add field def to list
7511                         fmd->setEnumScope(md);      // cross ref with enum name
7512                         fmd->setEnumClassScope(cd); // cross ref with enum name
7513                         fmd->setOuterScope(cd);
7514                         fmd->makeRelated();
7515                         cd->insertMember(fmd);
7516                       }
7517                       else
7518                       {
7519                         ClassDef *fcd=fmd->getClassDef();
7520                         if (fcd==cd) // enum value is inside a class
7521                         {
7522                           //printf("Inserting enum field %s in enum scope %s\n",
7523                           //    fmd->name().data(),md->name().data());
7524                           md->insertEnumField(fmd); // add field def to list
7525                           fmd->setEnumScope(md);    // cross ref with enum name
7526                         }
7527                       }
7528                     }
7529                   }
7530                 }
7531               }
7532             }
7533           }
7534         }
7535       }
7536     }
7537
7538     rootNav->releaseEntry();
7539   }
7540   else
7541   {
7542     RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7543   }
7544 }
7545
7546
7547 //----------------------------------------------------------------------
7548 // find the documentation blocks for the enumerations
7549
7550 static void findEnumDocumentation(EntryNav *rootNav)
7551 {
7552   if (rootNav->section()==Entry::ENUMDOC_SEC
7553       && !rootNav->name().isEmpty()
7554       && rootNav->name().at(0)!='@'        // skip anonymous enums
7555      )
7556   {
7557     rootNav->loadEntry(g_storage);
7558     Entry *root = rootNav->entry();
7559
7560     //printf("Found docs for enum with name `%s' in context %s\n",
7561     //    root->name.data(),root->parent->name.data());
7562     int i;
7563     QCString name;
7564     QCString scope;
7565     if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7566     {
7567       name=root->name.right(root->name.length()-i-2); // extract name
7568       scope=root->name.left(i); // extract scope
7569       //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7570     }
7571     else // just the name
7572     {
7573       name=root->name;
7574     }
7575     if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7576         && !rootNav->parent()->name().isEmpty()
7577        ) // found enum docs inside a compound
7578     {
7579       if (!scope.isEmpty()) scope.prepend("::");
7580       scope.prepend(rootNav->parent()->name());
7581     }
7582     ClassDef *cd=getClass(scope);
7583
7584     if (!name.isEmpty())
7585     {
7586       bool found=FALSE;
7587       if (cd)
7588       {
7589         //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7590         QCString className=cd->name().copy();
7591         MemberName *mn=Doxygen::memberNameSDict->find(name);
7592         if (mn)
7593         {
7594           MemberNameIterator mni(*mn);
7595           MemberDef *md;
7596           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7597           {
7598             ClassDef *cd=md->getClassDef();
7599             if (cd && cd->name()==className && md->isEnumerate())
7600             {
7601               // documentation outside a compound overrides the documentation inside it
7602 #if 0
7603               if (!md->documentation() || rootNav->parent()->name().isEmpty())
7604 #endif
7605               {
7606                 md->setDocumentation(root->doc,root->docFile,root->docLine);
7607                 md->setDocsForDefinition(!root->proto);
7608               }
7609
7610               // brief descriptions inside a compound override the documentation
7611               // outside it
7612 #if 0
7613               if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7614 #endif
7615               {
7616                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7617               }
7618
7619               if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7620               {
7621                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7622               }
7623
7624               if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7625               {
7626                 md->setMemberGroupId(root->mGrpId);
7627               }
7628
7629               md->addSectionsToDefinition(root->anchors);
7630               md->setRefItems(root->sli);
7631
7632               GroupDef *gd=md->getGroupDef();
7633               if (gd==0 &&root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7634               {
7635                 addMemberToGroups(root,md);
7636               }
7637
7638               found=TRUE;
7639             }
7640           }
7641         }
7642         else
7643         {
7644           //printf("MemberName %s not found!\n",name.data());
7645         }
7646       }
7647       else // enum outside class
7648       {
7649         //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7650         MemberName *mn=Doxygen::functionNameSDict->find(name);
7651         if (mn)
7652         {
7653           MemberNameIterator mni(*mn);
7654           MemberDef *md;
7655           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7656           {
7657             if (md->isEnumerate())
7658             {
7659               md->setDocumentation(root->doc,root->docFile,root->docLine);
7660               md->setDocsForDefinition(!root->proto);
7661               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7662               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7663               md->addSectionsToDefinition(root->anchors);
7664               md->setMemberGroupId(root->mGrpId);
7665
7666               GroupDef *gd=md->getGroupDef();
7667               if (gd==0 && root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7668               {
7669                 addMemberToGroups(root,md);
7670               }
7671
7672               found=TRUE;
7673             }
7674           }
7675         }
7676       }
7677       if (!found)
7678       {
7679         warn(root->fileName,root->startLine,
7680              "Documentation for undefined enum `%s' found.",
7681              name.data()
7682             );
7683       }
7684     }
7685
7686     rootNav->releaseEntry();
7687   }
7688   RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7689 }
7690
7691 // search for each enum (member or function) in mnl if it has documented
7692 // enum values.
7693 static void findDEV(const MemberNameSDict &mnsd)
7694 {
7695   MemberName *mn;
7696   MemberNameSDict::Iterator mnli(mnsd);
7697   // for each member name
7698   for (mnli.toFirst();(mn=mnli.current());++mnli)
7699   {
7700     MemberDef *md;
7701     MemberNameIterator mni(*mn);
7702     // for each member definition
7703     for (mni.toFirst();(md=mni.current());++mni)
7704     {
7705       if (md->isEnumerate()) // member is an enum
7706       {
7707         MemberList *fmdl = md->enumFieldList();
7708         int documentedEnumValues=0;
7709         if (fmdl) // enum has values
7710         {
7711           MemberListIterator fmni(*fmdl);
7712           MemberDef *fmd;
7713           // for each enum value
7714           for (fmni.toFirst();(fmd=fmni.current());++fmni)
7715           {
7716             if (fmd->isLinkableInProject()) documentedEnumValues++;
7717           }
7718         }
7719         // at least one enum value is documented
7720         if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7721       }
7722     }
7723   }
7724 }
7725
7726 // search for each enum (member or function) if it has documented enum
7727 // values.
7728 static void findDocumentedEnumValues()
7729 {
7730   findDEV(*Doxygen::memberNameSDict);
7731   findDEV(*Doxygen::functionNameSDict);
7732 }
7733
7734 //----------------------------------------------------------------------
7735
7736 static void addMembersToIndex()
7737 {
7738   MemberName *mn;
7739   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7740   // for each member name
7741   for (mnli.toFirst();(mn=mnli.current());++mnli)
7742   {
7743     MemberDef *md;
7744     MemberNameIterator mni(*mn);
7745     // for each member definition
7746     for (mni.toFirst();(md=mni.current());++mni)
7747     {
7748       addClassMemberNameToIndex(md);
7749     }
7750   }
7751   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7752   // for each member name
7753   for (fnli.toFirst();(mn=fnli.current());++fnli)
7754   {
7755     MemberDef *md;
7756     MemberNameIterator mni(*mn);
7757     // for each member definition
7758     for (mni.toFirst();(md=mni.current());++mni)
7759     {
7760       if (md->getNamespaceDef())
7761       {
7762         addNamespaceMemberNameToIndex(md);
7763       }
7764       else
7765       {
7766         addFileMemberNameToIndex(md);
7767       }
7768     }
7769   }
7770 }
7771
7772 //----------------------------------------------------------------------
7773 // computes the relation between all members. For each member `m'
7774 // the members that override the implementation of `m' are searched and
7775 // the member that `m' overrides is searched.
7776
7777 static void computeMemberRelations()
7778 {
7779   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7780   MemberName *mn;
7781   for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7782   {
7783     MemberNameIterator mdi(*mn);
7784     MemberNameIterator bmdi(*mn);
7785     MemberDef *md;
7786     MemberDef *bmd;
7787     for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7788     {
7789       for ( bmdi.toFirst() ; (bmd=bmdi.current()); ++bmdi ) // for each other member with the same name
7790       {
7791         ClassDef *mcd  = md->getClassDef();
7792         if (mcd && mcd->baseClasses())
7793         {
7794           ClassDef *bmcd = bmd->getClassDef();
7795           //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7796           //      mcd->name().data(),md->name().data(),md,
7797           //       bmcd->name().data(),bmd->name().data(),bmd
7798           //      );
7799           if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
7800               (bmd->virtualness()!=Normal || bmd->getLanguage()==SrcLangExt_Python ||
7801                bmcd->compoundType()==ClassDef::Interface ||
7802                bmcd->compoundType()==ClassDef::Protocol
7803               ) &&
7804               md->isFunction() &&
7805               mcd->isLinkable() &&
7806               bmcd->isLinkable() &&
7807               mcd->isBaseClass(bmcd,TRUE))
7808           {
7809             //printf("  derived scope\n");
7810             ArgumentList *bmdAl = bmd->argumentList();
7811             ArgumentList *mdAl =  md->argumentList();
7812             //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7813             //        argListToString(bmdAl.pointer()).data(),
7814             //        argListToString(mdAl.pointer()).data()
7815             //      );
7816             if (
7817                 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl,
7818                   md->getOuterScope(), md->getFileDef(), mdAl,
7819                   TRUE
7820                   )
7821                )
7822             {
7823               MemberDef *rmd;
7824               if ((rmd=md->reimplements())==0 ||
7825                   minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7826                  )
7827               {
7828                 //printf("setting (new) reimplements member\n");
7829                 md->setReimplements(bmd);
7830               }
7831               //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7832               bmd->insertReimplementedBy(md);
7833             }
7834           }
7835         }
7836       }
7837     }
7838   }
7839 }
7840
7841
7842 //----------------------------------------------------------------------------
7843 //static void computeClassImplUsageRelations()
7844 //{
7845 //  ClassDef *cd;
7846 //  ClassSDict::Iterator cli(*Doxygen::classSDict);
7847 //  for (;(cd=cli.current());++cli)
7848 //  {
7849 //    cd->determineImplUsageRelation();
7850 //  }
7851 //}
7852
7853 //----------------------------------------------------------------------------
7854
7855 static void createTemplateInstanceMembers()
7856 {
7857   ClassSDict::Iterator cli(*Doxygen::classSDict);
7858   ClassDef *cd;
7859   // for each class
7860   for (cli.toFirst();(cd=cli.current());++cli)
7861   {
7862     // that is a template
7863     QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7864     if (templInstances)
7865     {
7866       QDictIterator<ClassDef> qdi(*templInstances);
7867       ClassDef *tcd=0;
7868       // for each instance of the template
7869       for (qdi.toFirst();(tcd=qdi.current());++qdi)
7870       {
7871         tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7872       }
7873     }
7874   }
7875 }
7876
7877 //----------------------------------------------------------------------------
7878
7879 static void mergeCategories()
7880 {
7881   ClassDef *cd;
7882   ClassSDict::Iterator cli(*Doxygen::classSDict);
7883   // merge members of categories into the class they extend
7884   for (cli.toFirst();(cd=cli.current());++cli)
7885   {
7886     int i=cd->name().find('(');
7887     if (i!=-1) // it is an Objective-C category
7888     {
7889       QCString baseName=cd->name().left(i);
7890       ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7891       if (baseClass)
7892       {
7893         //printf("*** merging members of category %s into %s\n",
7894         //    cd->name().data(),baseClass->name().data());
7895         baseClass->mergeCategory(cd);
7896       }
7897     }
7898   }
7899 }
7900
7901 // builds the list of all members for each class
7902
7903 static void buildCompleteMemberLists()
7904 {
7905   ClassDef *cd;
7906   ClassSDict::Iterator cli(*Doxygen::classSDict);
7907   // merge the member list of base classes into the inherited classes.
7908   for (cli.toFirst();(cd=cli.current());++cli)
7909   {
7910     if (// !cd->isReference() && // not an external class
7911          cd->subClasses()==0 && // is a root of the hierarchy
7912          cd->baseClasses()) // and has at least one base class
7913     {
7914       //printf("*** merging members for %s\n",cd->name().data());
7915       cd->mergeMembers();
7916     }
7917   }
7918   // now sort the member list of all classes.
7919   for (cli.toFirst();(cd=cli.current());++cli)
7920   {
7921     if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7922   }
7923 }
7924
7925 //----------------------------------------------------------------------------
7926
7927 static void generateFileSources()
7928 {
7929   if (Doxygen::inputNameList->count()>0)
7930   {
7931 #if USE_LIBCLANG
7932     static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
7933     if (clangAssistedParsing)
7934     {
7935       QDict<void> g_processedFiles(10007);
7936
7937       // create a dictionary with files to process
7938       QDict<void> g_filesToProcess(10007);
7939       FileNameListIterator fnli(*Doxygen::inputNameList);
7940       FileName *fn;
7941       for (fnli.toFirst();(fn=fnli.current());++fnli)
7942       {
7943         FileNameIterator fni(*fn);
7944         FileDef *fd;
7945         for (;(fd=fni.current());++fni)
7946         {
7947           g_filesToProcess.insert(fd->absFilePath(),(void*)0x8);
7948         }
7949       }
7950       // process source files (and their include dependencies)
7951       for (fnli.toFirst();(fn=fnli.current());++fnli)
7952       {
7953         FileNameIterator fni(*fn);
7954         FileDef *fd;
7955         for (;(fd=fni.current());++fni)
7956         {
7957           if (fd->isSource() && !fd->isReference())
7958           {
7959             QStrList filesInSameTu;
7960             fd->getAllIncludeFilesRecursively(filesInSameTu);
7961             fd->startParsing();
7962             if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7963             {
7964               msg("Generating code for file %s...\n",fd->docName().data());
7965               fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7966
7967             }
7968             else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7969               // we needed to parse the sources even if we do not show them
7970             {
7971               msg("Parsing code for file %s...\n",fd->docName().data());
7972               fd->parseSource(FALSE,filesInSameTu);
7973             }
7974
7975             char *incFile = filesInSameTu.first();
7976             while (incFile && g_filesToProcess.find(incFile))
7977             {
7978               if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile))
7979               {
7980                 QStrList moreFiles;
7981                 bool ambig;
7982                 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
7983                 if (ifd && !ifd->isReference())
7984                 {
7985                   if (ifd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7986                   {
7987                     msg(" Generating code for file %s...\n",ifd->docName().data());
7988                     ifd->writeSource(*g_outputList,TRUE,moreFiles);
7989
7990                   }
7991                   else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
7992                     // we needed to parse the sources even if we do not show them
7993                   {
7994                     msg(" Parsing code for file %s...\n",ifd->docName().data());
7995                     ifd->parseSource(TRUE,moreFiles);
7996                   }
7997                   g_processedFiles.insert(incFile,(void*)0x8);
7998                 }
7999               }
8000               incFile = filesInSameTu.next();
8001             }
8002             fd->finishParsing();
8003             g_processedFiles.insert(fd->absFilePath(),(void*)0x8);
8004           }
8005         }
8006       }
8007       // process remaining files
8008       for (fnli.toFirst();(fn=fnli.current());++fnli)
8009       {
8010         FileNameIterator fni(*fn);
8011         FileDef *fd;
8012         for (;(fd=fni.current());++fni)
8013         {
8014           if (!g_processedFiles.find(fd->absFilePath())) // not yet processed
8015           {
8016             QStrList filesInSameTu;
8017             fd->startParsing();
8018             if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
8019             {
8020               msg("Generating code for file %s...\n",fd->docName().data());
8021               fd->writeSource(*g_outputList,FALSE,filesInSameTu);
8022
8023             }
8024             else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
8025               // we needed to parse the sources even if we do not show them
8026             {
8027               msg("Parsing code for file %s...\n",fd->docName().data());
8028               fd->parseSource(FALSE,filesInSameTu);
8029             }
8030             fd->finishParsing();
8031           }
8032         }
8033       }
8034     }
8035     else
8036 #endif
8037     {
8038       FileNameListIterator fnli(*Doxygen::inputNameList);
8039       FileName *fn;
8040       for (;(fn=fnli.current());++fnli)
8041       {
8042         FileNameIterator fni(*fn);
8043         FileDef *fd;
8044         for (;(fd=fni.current());++fni)
8045         {
8046           QStrList filesInSameTu;
8047           fd->startParsing();
8048           if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
8049           {
8050             msg("Generating code for file %s...\n",fd->docName().data());
8051             fd->writeSource(*g_outputList,FALSE,filesInSameTu);
8052
8053           }
8054           else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
8055             // we needed to parse the sources even if we do not show them
8056           {
8057             msg("Parsing code for file %s...\n",fd->docName().data());
8058             fd->parseSource(FALSE,filesInSameTu);
8059           }
8060           fd->finishParsing();
8061         }
8062       }
8063     }
8064   }
8065 }
8066
8067 //----------------------------------------------------------------------------
8068
8069 static void generateFileDocs()
8070 {
8071   if (documentedHtmlFiles==0) return;
8072
8073   if (Doxygen::inputNameList->count()>0)
8074   {
8075     FileNameListIterator fnli(*Doxygen::inputNameList);
8076     FileName *fn;
8077     for (fnli.toFirst();(fn=fnli.current());++fnli)
8078     {
8079       FileNameIterator fni(*fn);
8080       FileDef *fd;
8081       for (fni.toFirst();(fd=fni.current());++fni)
8082       {
8083         bool doc = fd->isLinkableInProject();
8084         if (doc)
8085         {
8086           msg("Generating docs for file %s...\n",fd->docName().data());
8087           fd->writeDocumentation(*g_outputList);
8088         }
8089       }
8090     }
8091   }
8092 }
8093
8094 //----------------------------------------------------------------------------
8095
8096 static void addSourceReferences()
8097 {
8098   // add source references for class definitions
8099   ClassSDict::Iterator cli(*Doxygen::classSDict);
8100   ClassDef *cd=0;
8101   for (cli.toFirst();(cd=cli.current());++cli)
8102   {
8103     FileDef *fd=cd->getBodyDef();
8104     if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
8105     {
8106       fd->addSourceRef(cd->getStartBodyLine(),cd,0);
8107     }
8108   }
8109   // add source references for namespace definitions
8110   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8111   NamespaceDef *nd=0;
8112   for (nli.toFirst();(nd=nli.current());++nli)
8113   {
8114     FileDef *fd=nd->getBodyDef();
8115     if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
8116     {
8117       fd->addSourceRef(nd->getStartBodyLine(),nd,0);
8118     }
8119   }
8120
8121   // add source references for member names
8122   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8123   MemberName *mn=0;
8124   for (mnli.toFirst();(mn=mnli.current());++mnli)
8125   {
8126     MemberNameIterator mni(*mn);
8127     MemberDef *md=0;
8128     for (mni.toFirst();(md=mni.current());++mni)
8129     {
8130       //printf("class member %s: def=%s body=%d link?=%d\n",
8131       //    md->name().data(),
8132       //    md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
8133       //    md->getStartBodyLine(),md->isLinkableInProject());
8134       FileDef *fd=md->getBodyDef();
8135       if (fd &&
8136           md->getStartBodyLine()!=-1 &&
8137           md->isLinkableInProject() &&
8138           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
8139          )
8140       {
8141         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8142         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8143         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8144       }
8145     }
8146   }
8147   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8148   for (fnli.toFirst();(mn=fnli.current());++fnli)
8149   {
8150     MemberNameIterator mni(*mn);
8151     MemberDef *md=0;
8152     for (mni.toFirst();(md=mni.current());++mni)
8153     {
8154       FileDef *fd=md->getBodyDef();
8155       //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
8156       //    md->name().data(),
8157       //    md->getStartBodyLine(),md->getEndBodyLine(),fd,
8158       //    md->isLinkableInProject(),
8159       //    Doxygen::parseSourcesNeeded);
8160       if (fd &&
8161           md->getStartBodyLine()!=-1 &&
8162           md->isLinkableInProject() &&
8163           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
8164          )
8165       {
8166         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8167         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8168         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8169       }
8170     }
8171   }
8172 }
8173
8174 //----------------------------------------------------------------------------
8175
8176 static void sortMemberLists()
8177 {
8178   // sort class member lists
8179   ClassSDict::Iterator cli(*Doxygen::classSDict);
8180   ClassDef *cd=0;
8181   for (cli.toFirst();(cd=cli.current());++cli)
8182   {
8183     cd->sortMemberLists();
8184   }
8185
8186   // sort namespace member lists
8187   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8188   NamespaceDef *nd=0;
8189   for (nli.toFirst();(nd=nli.current());++nli)
8190   {
8191     nd->sortMemberLists();
8192   }
8193
8194   // sort file member lists
8195   FileNameListIterator fnli(*Doxygen::inputNameList);
8196   FileName *fn;
8197   for (;(fn=fnli.current());++fnli)
8198   {
8199     FileNameIterator fni(*fn);
8200     FileDef *fd;
8201     for (;(fd=fni.current());++fni)
8202     {
8203       fd->sortMemberLists();
8204     }
8205   }
8206
8207   // sort group member lists
8208   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8209   GroupDef *gd;
8210   for (gli.toFirst();(gd=gli.current());++gli)
8211   {
8212     gd->sortMemberLists();
8213   }
8214 }
8215
8216 //----------------------------------------------------------------------------
8217 // generate the documentation of all classes
8218
8219 static void generateClassList(ClassSDict &classSDict)
8220 {
8221   ClassSDict::Iterator cli(classSDict);
8222   for ( ; cli.current() ; ++cli )
8223   {
8224     ClassDef *cd=cli.current();
8225
8226     //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
8227     if (cd &&
8228         (cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8229          cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8230         ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8231        )
8232     {
8233       // skip external references, anonymous compounds and
8234       // template instances
8235       if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8236       {
8237         msg("Generating docs for compound %s...\n",cd->name().data());
8238
8239         cd->writeDocumentation(*g_outputList);
8240         cd->writeMemberList(*g_outputList);
8241       }
8242       // even for undocumented classes, the inner classes can be documented.
8243       cd->writeDocumentationForInnerClasses(*g_outputList);
8244     }
8245   }
8246 }
8247
8248 static void generateClassDocs()
8249 {
8250   generateClassList(*Doxygen::classSDict);
8251   generateClassList(*Doxygen::hiddenClasses);
8252 }
8253
8254 //----------------------------------------------------------------------------
8255
8256 static void inheritDocumentation()
8257 {
8258   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8259   MemberName *mn;
8260   //int count=0;
8261   for (;(mn=mnli.current());++mnli)
8262   {
8263     MemberNameIterator mni(*mn);
8264     MemberDef *md;
8265     for (;(md=mni.current());++mni)
8266     {
8267       //printf("%04d Member `%s'\n",count++,md->name().data());
8268       if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
8269       { // no documentation yet
8270         MemberDef *bmd = md->reimplements();
8271         while (bmd && bmd->documentation().isEmpty() &&
8272                       bmd->briefDescription().isEmpty()
8273               )
8274         { // search up the inheritance tree for a documentation member
8275           //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
8276           bmd = bmd->reimplements();
8277         }
8278         if (bmd) // copy the documentation from the reimplemented member
8279         {
8280           md->setInheritsDocsFrom(bmd);
8281           md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8282           md->setDocsForDefinition(bmd->isDocsForDefinition());
8283           md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8284           md->copyArgumentNames(bmd);
8285           md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
8286         }
8287       }
8288     }
8289   }
8290 }
8291
8292 //----------------------------------------------------------------------------
8293
8294 static void combineUsingRelations()
8295 {
8296   // for each file
8297   FileNameListIterator fnli(*Doxygen::inputNameList);
8298   FileName *fn;
8299   for (fnli.toFirst();(fn=fnli.current());++fnli)
8300   {
8301     FileNameIterator fni(*fn);
8302     FileDef *fd;
8303     for (fni.toFirst();(fd=fni.current());++fni)
8304     {
8305       fd->visited=FALSE;
8306     }
8307   }
8308   for (fnli.toFirst();(fn=fnli.current());++fnli)
8309   {
8310     FileNameIterator fni(*fn);
8311     FileDef *fd;
8312     for (fni.toFirst();(fd=fni.current());++fni)
8313     {
8314       fd->combineUsingRelations();
8315     }
8316   }
8317
8318   // for each namespace
8319   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8320   NamespaceDef *nd;
8321   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8322   {
8323     nd->visited=FALSE;
8324   }
8325   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8326   {
8327     nd->combineUsingRelations();
8328   }
8329 }
8330
8331 //----------------------------------------------------------------------------
8332
8333 static void addMembersToMemberGroup()
8334 {
8335   // for each class
8336   ClassSDict::Iterator cli(*Doxygen::classSDict);
8337   ClassDef *cd;
8338   for ( ; (cd=cli.current()) ; ++cli )
8339   {
8340     cd->addMembersToMemberGroup();
8341   }
8342   // for each file
8343   FileNameListIterator fnli(*Doxygen::inputNameList);
8344   FileName *fn;
8345   for (fnli.toFirst();(fn=fnli.current());++fnli)
8346   {
8347     FileNameIterator fni(*fn);
8348     FileDef *fd;
8349     for (fni.toFirst();(fd=fni.current());++fni)
8350     {
8351       fd->addMembersToMemberGroup();
8352     }
8353   }
8354   // for each namespace
8355   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8356   NamespaceDef *nd;
8357   for ( ; (nd=nli.current()) ; ++nli )
8358   {
8359     nd->addMembersToMemberGroup();
8360   }
8361   // for each group
8362   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8363   GroupDef *gd;
8364   for (gli.toFirst();(gd=gli.current());++gli)
8365   {
8366     gd->addMembersToMemberGroup();
8367   }
8368 }
8369
8370 //----------------------------------------------------------------------------
8371
8372 static void distributeMemberGroupDocumentation()
8373 {
8374   // for each class
8375   ClassSDict::Iterator cli(*Doxygen::classSDict);
8376   ClassDef *cd;
8377   for ( ; (cd=cli.current()) ; ++cli )
8378   {
8379     cd->distributeMemberGroupDocumentation();
8380   }
8381   // for each file
8382   FileNameListIterator fnli(*Doxygen::inputNameList);
8383   FileName *fn;
8384   for (fnli.toFirst();(fn=fnli.current());++fnli)
8385   {
8386     FileNameIterator fni(*fn);
8387     FileDef *fd;
8388     for (fni.toFirst();(fd=fni.current());++fni)
8389     {
8390       fd->distributeMemberGroupDocumentation();
8391     }
8392   }
8393   // for each namespace
8394   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8395   NamespaceDef *nd;
8396   for ( ; (nd=nli.current()) ; ++nli )
8397   {
8398     nd->distributeMemberGroupDocumentation();
8399   }
8400   // for each group
8401   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8402   GroupDef *gd;
8403   for (gli.toFirst();(gd=gli.current());++gli)
8404   {
8405     gd->distributeMemberGroupDocumentation();
8406   }
8407 }
8408
8409 //----------------------------------------------------------------------------
8410
8411 static void findSectionsInDocumentation()
8412 {
8413   // for each class
8414   ClassSDict::Iterator cli(*Doxygen::classSDict);
8415   ClassDef *cd;
8416   for ( ; (cd=cli.current()) ; ++cli )
8417   {
8418     cd->findSectionsInDocumentation();
8419   }
8420   // for each file
8421   FileNameListIterator fnli(*Doxygen::inputNameList);
8422   FileName *fn;
8423   for (fnli.toFirst();(fn=fnli.current());++fnli)
8424   {
8425     FileNameIterator fni(*fn);
8426     FileDef *fd;
8427     for (fni.toFirst();(fd=fni.current());++fni)
8428     {
8429       fd->findSectionsInDocumentation();
8430     }
8431   }
8432   // for each namespace
8433   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8434   NamespaceDef *nd;
8435   for ( ; (nd=nli.current()) ; ++nli )
8436   {
8437     nd->findSectionsInDocumentation();
8438   }
8439   // for each group
8440   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8441   GroupDef *gd;
8442   for (gli.toFirst();(gd=gli.current());++gli)
8443   {
8444     gd->findSectionsInDocumentation();
8445   }
8446   // for each page
8447   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8448   PageDef *pd=0;
8449   for (pdi.toFirst();(pd=pdi.current());++pdi)
8450   {
8451     pd->findSectionsInDocumentation();
8452   }
8453   if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8454 }
8455
8456 static void flushCachedTemplateRelations()
8457 {
8458   // remove all references to classes from the cache
8459   // as there can be new template instances in the inheritance path
8460   // to this class. Optimization: only remove those classes that
8461   // have inheritance instances as direct or indirect sub classes.
8462   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8463   LookupInfo *li=0;
8464   for (ci.toFirst();(li=ci.current());++ci)
8465   {
8466     if (li->classDef)
8467     {
8468       Doxygen::lookupCache->remove(ci.currentKey());
8469     }
8470   }
8471   // remove all cached typedef resolutions whose target is a
8472   // template class as this may now be a template instance
8473   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8474   MemberName *fn;
8475   for (;(fn=fnli.current());++fnli) // for each global function name
8476   {
8477     MemberNameIterator fni(*fn);
8478     MemberDef *fmd;
8479     for (;(fmd=fni.current());++fni) // for each function with that name
8480     {
8481       if (fmd->isTypedefValCached())
8482       {
8483         ClassDef *cd = fmd->getCachedTypedefVal();
8484         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8485       }
8486     }
8487   }
8488   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8489   for (;(fn=mnli.current());++mnli) // for each class method name
8490   {
8491     MemberNameIterator mni(*fn);
8492     MemberDef *fmd;
8493     for (;(fmd=mni.current());++mni) // for each function with that name
8494     {
8495       if (fmd->isTypedefValCached())
8496       {
8497         ClassDef *cd = fmd->getCachedTypedefVal();
8498         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8499       }
8500     }
8501   }
8502 }
8503
8504 //----------------------------------------------------------------------------
8505
8506 static void flushUnresolvedRelations()
8507 {
8508   // Remove all unresolved references to classes from the cache.
8509   // This is needed before resolving the inheritance relations, since
8510   // it would otherwise not find the inheritance relation
8511   // for C in the example below, as B::I was already found to be unresolvable
8512   // (which is correct if you ignore the inheritance relation between A and B).
8513   //
8514   // class A { class I {} };
8515   // class B : public A {};
8516   // class C : public B::I {};
8517   //
8518   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8519   LookupInfo *li=0;
8520   for (ci.toFirst();(li=ci.current());++ci)
8521   {
8522     if (li->classDef==0 && li->typeDef==0)
8523     {
8524       Doxygen::lookupCache->remove(ci.currentKey());
8525     }
8526   }
8527
8528   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8529   MemberName *fn;
8530   for (;(fn=fnli.current());++fnli) // for each global function name
8531   {
8532     MemberNameIterator fni(*fn);
8533     MemberDef *fmd;
8534     for (;(fmd=fni.current());++fni) // for each function with that name
8535     {
8536       fmd->invalidateCachedArgumentTypes();
8537     }
8538   }
8539   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8540   for (;(fn=mnli.current());++mnli) // for each class method name
8541   {
8542     MemberNameIterator mni(*fn);
8543     MemberDef *fmd;
8544     for (;(fmd=mni.current());++mni) // for each function with that name
8545     {
8546       fmd->invalidateCachedArgumentTypes();
8547     }
8548   }
8549
8550 }
8551
8552 //----------------------------------------------------------------------------
8553
8554 static void findDefineDocumentation(EntryNav *rootNav)
8555 {
8556   if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
8557        rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
8558      )
8559   {
8560     rootNav->loadEntry(g_storage);
8561     Entry *root = rootNav->entry();
8562
8563     //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
8564     //       root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
8565
8566     if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8567     {
8568       MemberDef *md=new MemberDef(rootNav->tagInfo()->tagName,1,1,
8569                     "#define",root->name,root->args,0,
8570                     Public,Normal,FALSE,Member,MemberType_Define,0,0,"");
8571       md->setTagInfo(rootNav->tagInfo());
8572       md->setLanguage(root->lang);
8573       //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
8574       md->setFileDef(rootNav->parent()->fileDef());
8575       //printf("Adding member=%s\n",md->name().data());
8576       MemberName *mn;
8577       if ((mn=Doxygen::functionNameSDict->find(root->name)))
8578       {
8579         mn->append(md);
8580       }
8581       else
8582       {
8583         mn = new MemberName(root->name);
8584         mn->append(md);
8585         Doxygen::functionNameSDict->append(root->name,mn);
8586       }
8587     }
8588     MemberName *mn=Doxygen::functionNameSDict->find(root->name);
8589     if (mn)
8590     {
8591       MemberNameIterator mni(*mn);
8592       MemberDef *md;
8593       int count=0;
8594       for (;(md=mni.current());++mni)
8595       {
8596         if (md->memberType()==MemberType_Define) count++;
8597       }
8598       if (count==1)
8599       {
8600         for (mni.toFirst();(md=mni.current());++mni)
8601         {
8602           if (md->memberType()==MemberType_Define)
8603           {
8604             md->setDocumentation(root->doc,root->docFile,root->docLine);
8605             md->setDocsForDefinition(!root->proto);
8606             md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8607             if (md->inbodyDocumentation().isEmpty())
8608             {
8609               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8610             }
8611             md->setBodySegment(root->bodyLine,root->endBodyLine);
8612             md->setBodyDef(rootNav->fileDef());
8613             md->addSectionsToDefinition(root->anchors);
8614             md->setMaxInitLines(root->initLines);
8615             md->setRefItems(root->sli);
8616             if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8617             addMemberToGroups(root,md);
8618           }
8619         }
8620       }
8621       else if (count>1 &&
8622                (!root->doc.isEmpty() ||
8623                 !root->brief.isEmpty() ||
8624                 root->bodyLine!=-1
8625                )
8626               )
8627         // multiple defines don't know where to add docs
8628         // but maybe they are in different files together with their documentation
8629       {
8630         for (mni.toFirst();(md=mni.current());++mni)
8631         {
8632           if (md->memberType()==MemberType_Define)
8633           {
8634             FileDef *fd=md->getFileDef();
8635             if (fd && fd->absFilePath()==root->fileName)
8636               // doc and define in the same file assume they belong together.
8637             {
8638 #if 0
8639               if (md->documentation().isEmpty())
8640 #endif
8641               {
8642                 md->setDocumentation(root->doc,root->docFile,root->docLine);
8643                 md->setDocsForDefinition(!root->proto);
8644               }
8645 #if 0
8646               if (md->briefDescription().isEmpty())
8647 #endif
8648               {
8649                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8650               }
8651               if (md->inbodyDocumentation().isEmpty())
8652               {
8653                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8654               }
8655               md->setBodySegment(root->bodyLine,root->endBodyLine);
8656               md->setBodyDef(rootNav->fileDef());
8657               md->addSectionsToDefinition(root->anchors);
8658               md->setRefItems(root->sli);
8659               md->setLanguage(root->lang);
8660               if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8661               addMemberToGroups(root,md);
8662             }
8663           }
8664         }
8665         //warn("define %s found in the following files:\n",root->name.data());
8666         //warn("Cannot determine where to add the documentation found "
8667         //     "at line %d of file %s. \n",
8668         //     root->startLine,root->fileName.data());
8669       }
8670     }
8671     else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8672     {
8673       static bool preEnabled = Config_getBool(ENABLE_PREPROCESSING);
8674       if (preEnabled)
8675       {
8676         warn(root->fileName,root->startLine,
8677              "documentation for unknown define %s found.\n",
8678              root->name.data()
8679             );
8680       }
8681       else
8682       {
8683         warn(root->fileName,root->startLine,
8684              "found documented #define but ignoring it because "
8685              "ENABLE_PREPROCESSING is NO.\n",
8686              root->name.data()
8687             );
8688       }
8689     }
8690
8691     rootNav->releaseEntry();
8692   }
8693   RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8694 }
8695
8696 //----------------------------------------------------------------------------
8697
8698 static void findDirDocumentation(EntryNav *rootNav)
8699 {
8700   if (rootNav->section() == Entry::DIRDOC_SEC)
8701   {
8702     rootNav->loadEntry(g_storage);
8703     Entry *root = rootNav->entry();
8704
8705     QCString normalizedName = root->name;
8706     normalizedName = substitute(normalizedName,"\\","/");
8707     //printf("root->docFile=%s normalizedName=%s\n",
8708     //    root->docFile.data(),normalizedName.data());
8709     if (root->docFile==normalizedName) // current dir?
8710     {
8711       int lastSlashPos=normalizedName.findRev('/');
8712       if (lastSlashPos!=-1) // strip file name
8713       {
8714         normalizedName=normalizedName.left(lastSlashPos);
8715       }
8716     }
8717     if (normalizedName.at(normalizedName.length()-1)!='/')
8718     {
8719       normalizedName+='/';
8720     }
8721     DirDef *dir,*matchingDir=0;
8722     SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8723     for (sdi.toFirst();(dir=sdi.current());++sdi)
8724     {
8725       //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8726       if (dir->name().right(normalizedName.length())==normalizedName)
8727       {
8728         if (matchingDir)
8729         {
8730            warn(root->fileName,root->startLine,
8731              "\\dir command matches multiple directories.\n"
8732              "  Applying the command for directory %s\n"
8733              "  Ignoring the command for directory %s\n",
8734              matchingDir->name().data(),dir->name().data()
8735            );
8736         }
8737         else
8738         {
8739           matchingDir=dir;
8740         }
8741       }
8742     }
8743     if (matchingDir)
8744     {
8745       //printf("Match for with dir %s\n",matchingDir->name().data());
8746       matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8747       matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8748       matchingDir->setRefItems(root->sli);
8749       addDirToGroups(root,matchingDir);
8750     }
8751     else
8752     {
8753       warn(root->fileName,root->startLine,"No matching "
8754           "directory found for command \\dir %s\n",normalizedName.data());
8755     }
8756     rootNav->releaseEntry();
8757   }
8758   RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8759 }
8760
8761
8762 //----------------------------------------------------------------------------
8763 // create a (sorted) list of separate documentation pages
8764
8765 static void buildPageList(EntryNav *rootNav)
8766 {
8767   if (rootNav->section() == Entry::PAGEDOC_SEC)
8768   {
8769     rootNav->loadEntry(g_storage);
8770     Entry *root = rootNav->entry();
8771
8772     if (!root->name.isEmpty())
8773     {
8774       addRelatedPage(rootNav);
8775     }
8776
8777     rootNav->releaseEntry();
8778   }
8779   else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8780   {
8781     rootNav->loadEntry(g_storage);
8782     Entry *root = rootNav->entry();
8783
8784     QCString title=root->args.stripWhiteSpace();
8785     if (title.isEmpty()) title=theTranslator->trMainPage();
8786     //QCString name = Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8787     QCString name = "index";
8788     addRefItem(root->sli,
8789                name,
8790                "page",
8791                name,
8792                title,
8793                0,0
8794                );
8795
8796     rootNav->releaseEntry();
8797   }
8798   RECURSE_ENTRYTREE(buildPageList,rootNav);
8799 }
8800
8801 // search for the main page defined in this project
8802 static void findMainPage(EntryNav *rootNav)
8803 {
8804   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8805   {
8806     rootNav->loadEntry(g_storage);
8807
8808     if (Doxygen::mainPage==0 && rootNav->tagInfo()==0)
8809     {
8810       Entry *root = rootNav->entry();
8811       //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8812       QCString title=root->args.stripWhiteSpace();
8813       //QCString indexName=Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8814       QCString indexName="index";
8815       Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8816                               indexName, root->brief+root->doc+root->inbodyDocs,title);
8817       //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8818       Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8819       Doxygen::mainPage->setFileName(indexName);
8820       Doxygen::mainPage->setLocalToc(root->localToc);
8821       addPageToContext(Doxygen::mainPage,rootNav);
8822
8823       SectionInfo *si = Doxygen::sectionDict->find(Doxygen::mainPage->name());
8824       if (si)
8825       {
8826         if (si->lineNr != -1)
8827         {
8828           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);
8829         }
8830         else
8831         {
8832           warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s)",Doxygen::mainPage->name().data(),si->fileName.data());
8833         }
8834       }
8835       else
8836       {
8837         // a page name is a label as well! but should no be double either
8838         si=new SectionInfo(
8839           indexName, root->startLine,
8840           Doxygen::mainPage->name(),
8841           Doxygen::mainPage->title(),
8842           SectionInfo::Page,
8843           0); // level 0
8844         Doxygen::sectionDict->append(indexName,si);
8845         Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8846       }
8847     }
8848     else if (rootNav->tagInfo()==0)
8849     {
8850       Entry *root = rootNav->entry();
8851       warn(root->fileName,root->startLine,
8852            "found more than one \\mainpage comment block! (first occurrence: %s, line %d), Skipping current block!",
8853            Doxygen::mainPage->docFile().data(),Doxygen::mainPage->docLine());
8854     }
8855
8856     rootNav->releaseEntry();
8857   }
8858   RECURSE_ENTRYTREE(findMainPage,rootNav);
8859 }
8860
8861 // search for the main page imported via tag files and add only the section labels
8862 static void findMainPageTagFiles(EntryNav *rootNav)
8863 {
8864   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8865   {
8866     rootNav->loadEntry(g_storage);
8867
8868     if (Doxygen::mainPage && rootNav->tagInfo())
8869     {
8870       Entry *root = rootNav->entry();
8871       Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8872     }
8873   }
8874   RECURSE_ENTRYTREE(findMainPageTagFiles,rootNav);
8875 }
8876
8877 static void computePageRelations(EntryNav *rootNav)
8878 {
8879   if ((rootNav->section()==Entry::PAGEDOC_SEC ||
8880        rootNav->section()==Entry::MAINPAGEDOC_SEC
8881       )
8882       && !rootNav->name().isEmpty()
8883      )
8884   {
8885     rootNav->loadEntry(g_storage);
8886     Entry *root = rootNav->entry();
8887
8888     PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8889                     Doxygen::pageSDict->find(root->name) :
8890                     Doxygen::mainPage;
8891     if (pd)
8892     {
8893       QListIterator<BaseInfo> bii(*root->extends);
8894       BaseInfo *bi;
8895       for (bii.toFirst();(bi=bii.current());++bii)
8896       {
8897         PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8898         if (subPd)
8899         {
8900           pd->addInnerCompound(subPd);
8901           //printf("*** Added subpage relation: %s->%s\n",
8902           //    pd->name().data(),subPd->name().data());
8903         }
8904       }
8905     }
8906
8907     rootNav->releaseEntry();
8908   }
8909   RECURSE_ENTRYTREE(computePageRelations,rootNav);
8910 }
8911
8912 static void checkPageRelations()
8913 {
8914   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8915   PageDef *pd=0;
8916   for (pdi.toFirst();(pd=pdi.current());++pdi)
8917   {
8918     Definition *ppd = pd->getOuterScope();
8919     while (ppd)
8920     {
8921       if (ppd==pd)
8922       {
8923         err("page defined at line %d of file %s with label %s is a subpage "
8924             "of itself! Please remove this cyclic dependency.\n",
8925             pd->docLine(),pd->docFile().data(),pd->name().data());
8926         exit(1);
8927       }
8928       ppd=ppd->getOuterScope();
8929     }
8930   }
8931 }
8932
8933 //----------------------------------------------------------------------------
8934
8935 static void resolveUserReferences()
8936 {
8937   SDict<SectionInfo>::Iterator sdi(*Doxygen::sectionDict);
8938   SectionInfo *si;
8939   for (;(si=sdi.current());++sdi)
8940   {
8941     //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8942     //        si->label.data(),si->definition?si->definition->name().data():"<none>",
8943     //        si->fileName.data());
8944     PageDef *pd=0;
8945
8946     // hack: the items of a todo/test/bug/deprecated list are all fragments from
8947     // different files, so the resulting section's all have the wrong file
8948     // name (not from the todo/test/bug/deprecated list, but from the file in
8949     // which they are defined). We correct this here by looking at the
8950     // generated section labels!
8951     QDictIterator<RefList> rli(*Doxygen::xrefLists);
8952     RefList *rl;
8953     for (rli.toFirst();(rl=rli.current());++rli)
8954     {
8955       QCString label="_"+rl->listName(); // "_todo", "_test", ...
8956       if (si->label.left(label.length())==label)
8957       {
8958         si->fileName=rl->listName();
8959         si->generated=TRUE;
8960         break;
8961       }
8962     }
8963
8964     //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8965     if (!si->generated)
8966     {
8967       // if this section is in a page and the page is in a group, then we
8968       // have to adjust the link file name to point to the group.
8969       if (!si->fileName.isEmpty() &&
8970           (pd=Doxygen::pageSDict->find(si->fileName)) &&
8971           pd->getGroupDef())
8972       {
8973         si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8974       }
8975
8976       if (si->definition)
8977       {
8978         // TODO: there should be one function in Definition that returns
8979         // the file to link to, so we can avoid the following tests.
8980         GroupDef *gd=0;
8981         if (si->definition->definitionType()==Definition::TypeMember)
8982         {
8983           gd = ((MemberDef *)si->definition)->getGroupDef();
8984         }
8985
8986         if (gd)
8987         {
8988           si->fileName=gd->getOutputFileBase().copy();
8989         }
8990         else
8991         {
8992           //si->fileName=si->definition->getOutputFileBase().copy();
8993           //printf("Setting si->fileName to %s\n",si->fileName.data());
8994         }
8995       }
8996     }
8997     //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8998   }
8999 }
9000
9001
9002
9003 //----------------------------------------------------------------------------
9004 // generate all separate documentation pages
9005
9006
9007 static void generatePageDocs()
9008 {
9009   //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
9010   if (documentedPages==0) return;
9011   PageSDict::Iterator pdi(*Doxygen::pageSDict);
9012   PageDef *pd=0;
9013   for (pdi.toFirst();(pd=pdi.current());++pdi)
9014   {
9015     if (!pd->getGroupDef() && !pd->isReference())
9016     {
9017       msg("Generating docs for page %s...\n",pd->name().data());
9018       Doxygen::insideMainPage=TRUE;
9019       pd->writeDocumentation(*g_outputList);
9020       Doxygen::insideMainPage=FALSE;
9021     }
9022   }
9023 }
9024
9025 //----------------------------------------------------------------------------
9026 // create a (sorted) list & dictionary of example pages
9027
9028 static void buildExampleList(EntryNav *rootNav)
9029 {
9030   if ((rootNav->section()==Entry::EXAMPLE_SEC || rootNav->section()==Entry::EXAMPLE_LINENO_SEC) && !rootNav->name().isEmpty())
9031   {
9032     rootNav->loadEntry(g_storage);
9033     Entry *root = rootNav->entry();
9034
9035     if (Doxygen::exampleSDict->find(root->name))
9036     {
9037       warn(root->fileName,root->startLine,
9038           "Example %s was already documented. Ignoring "
9039           "documentation found here.",
9040           root->name.data()
9041           );
9042     }
9043     else
9044     {
9045       PageDef *pd=new PageDef(root->fileName,root->startLine,
9046           root->name,root->brief+root->doc+root->inbodyDocs,root->args);
9047       pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
9048       pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
9049       pd->addSectionsToDefinition(root->anchors);
9050       pd->setLanguage(root->lang);
9051       pd->setShowLineNo(rootNav->section()==Entry::EXAMPLE_LINENO_SEC);
9052
9053       Doxygen::exampleSDict->inSort(root->name,pd);
9054       //we don't add example to groups
9055       //addExampleToGroups(root,pd);
9056     }
9057
9058     rootNav->releaseEntry();
9059   }
9060   RECURSE_ENTRYTREE(buildExampleList,rootNav);
9061 }
9062
9063 //----------------------------------------------------------------------------
9064 // prints the Entry tree (for debugging)
9065
9066 void printNavTree(EntryNav *rootNav,int indent)
9067 {
9068   QCString indentStr;
9069   indentStr.fill(' ',indent);
9070   msg("%s%s (sec=0x%x)\n",
9071       indentStr.isEmpty()?"":indentStr.data(),
9072       rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
9073       rootNav->section());
9074   if (rootNav->children())
9075   {
9076     EntryNavListIterator eli(*rootNav->children());
9077     for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
9078   }
9079 }
9080
9081
9082 //----------------------------------------------------------------------------
9083 // generate the example documentation
9084
9085 static void generateExampleDocs()
9086 {
9087   g_outputList->disable(OutputGenerator::Man);
9088   PageSDict::Iterator pdi(*Doxygen::exampleSDict);
9089   PageDef *pd=0;
9090   for (pdi.toFirst();(pd=pdi.current());++pdi)
9091   {
9092     msg("Generating docs for example %s...\n",pd->name().data());
9093     resetCCodeParserState();
9094     QCString n=pd->getOutputFileBase();
9095     startFile(*g_outputList,n,n,pd->name());
9096     startTitle(*g_outputList,n);
9097     g_outputList->docify(pd->name());
9098     endTitle(*g_outputList,n,0);
9099     g_outputList->startContents();
9100     QCString lineNoOptStr;
9101     if (pd->showLineNo())
9102     {
9103       lineNoOptStr="{lineno}";
9104     }
9105     g_outputList->generateDoc(pd->docFile(),                            // file
9106                          pd->docLine(),                            // startLine
9107                          pd,                                       // context
9108                          0,                                        // memberDef
9109                          pd->documentation()+"\n\n\\include"+lineNoOptStr+" "+pd->name(), // docs
9110                          TRUE,                                     // index words
9111                          TRUE,                                     // is example
9112                          pd->name()
9113                         );
9114     endFile(*g_outputList); // contains g_outputList->endContents()
9115   }
9116   g_outputList->enable(OutputGenerator::Man);
9117 }
9118
9119 //----------------------------------------------------------------------------
9120 // generate module pages
9121
9122 static void generateGroupDocs()
9123 {
9124   GroupSDict::Iterator gli(*Doxygen::groupSDict);
9125   GroupDef *gd;
9126   for (gli.toFirst();(gd=gli.current());++gli)
9127   {
9128     if (!gd->isReference())
9129     {
9130       gd->writeDocumentation(*g_outputList);
9131     }
9132   }
9133 }
9134
9135 //----------------------------------------------------------------------------
9136
9137 //static void generatePackageDocs()
9138 //{
9139 //  writePackageIndex(*g_outputList);
9140 //
9141 //  if (Doxygen::packageDict.count()>0)
9142 //  {
9143 //    PackageSDict::Iterator pdi(Doxygen::packageDict);
9144 //    PackageDef *pd;
9145 //    for (pdi.toFirst();(pd=pdi.current());++pdi)
9146 //    {
9147 //      pd->writeDocumentation(*g_outputList);
9148 //    }
9149 //  }
9150 //}
9151
9152 //----------------------------------------------------------------------------
9153 // generate module pages
9154
9155 static void generateNamespaceClassDocs(ClassSDict *d)
9156 {
9157   // for each class in the namespace...
9158   ClassSDict::Iterator cli(*d);
9159   ClassDef *cd;
9160   for ( ; (cd=cli.current()) ; ++cli )
9161   {
9162     if ( ( cd->isLinkableInProject() &&
9163            cd->templateMaster()==0
9164          ) // skip external references, anonymous compounds and
9165            // template instances and nested classes
9166          && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
9167        )
9168     {
9169       msg("Generating docs for compound %s...\n",cd->name().data());
9170
9171       cd->writeDocumentation(*g_outputList);
9172       cd->writeMemberList(*g_outputList);
9173     }
9174     cd->writeDocumentationForInnerClasses(*g_outputList);
9175   }
9176 }
9177
9178 static void generateNamespaceDocs()
9179 {
9180   static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE);
9181
9182   //writeNamespaceIndex(*g_outputList);
9183
9184   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
9185   NamespaceDef *nd;
9186   // for each namespace...
9187   for (;(nd=nli.current());++nli)
9188   {
9189
9190     if (nd->isLinkableInProject())
9191     {
9192       msg("Generating docs for namespace %s\n",nd->name().data());
9193       nd->writeDocumentation(*g_outputList);
9194     }
9195
9196     generateNamespaceClassDocs(nd->getClassSDict());
9197     if (sliceOpt)
9198     {
9199       generateNamespaceClassDocs(nd->getInterfaceSDict());
9200       generateNamespaceClassDocs(nd->getStructSDict());
9201       generateNamespaceClassDocs(nd->getExceptionSDict());
9202     }
9203   }
9204 }
9205
9206 #if defined(_WIN32)
9207 static QCString fixSlashes(QCString &s)
9208 {
9209   QCString result;
9210   uint i;
9211   for (i=0;i<s.length();i++)
9212   {
9213     switch(s.at(i))
9214     {
9215       case '/':
9216       case '\\':
9217         result+="\\\\";
9218         break;
9219       default:
9220         result+=s.at(i);
9221     }
9222   }
9223   return result;
9224 }
9225 #endif
9226
9227
9228 //----------------------------------------------------------------------------
9229
9230 /*! Generate a template version of the configuration file.
9231  *  If the \a shortList parameter is TRUE a configuration file without
9232  *  comments will be generated.
9233  */
9234 static void generateConfigFile(const char *configFile,bool shortList,
9235                                bool updateOnly=FALSE)
9236 {
9237   QFile f;
9238   bool fileOpened=openOutputFile(configFile,f);
9239   bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
9240   if (fileOpened)
9241   {
9242     FTextStream t(&f);
9243     Config::writeTemplate(t,shortList,updateOnly);
9244     if (!writeToStdout)
9245     {
9246       if (!updateOnly)
9247       {
9248         msg("\n\nConfiguration file `%s' created.\n\n",configFile);
9249         msg("Now edit the configuration file and enter\n\n");
9250         if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
9251           msg("  doxygen %s\n\n",configFile);
9252         else
9253           msg("  doxygen\n\n");
9254         msg("to generate the documentation for your project\n\n");
9255       }
9256       else
9257       {
9258         msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
9259       }
9260     }
9261   }
9262   else
9263   {
9264     err("Cannot open file %s for writing\n",configFile);
9265     exit(1);
9266   }
9267 }
9268 static void compareDoxyfile()
9269 {
9270   QFile f;
9271   char configFile[2];
9272   configFile[0] = '-';
9273   configFile[1] = '\0';
9274   bool fileOpened=openOutputFile(configFile,f);
9275   if (fileOpened)
9276   {
9277     FTextStream t(&f);
9278     Config::compareDoxyfile(t);
9279   }
9280   else
9281   {
9282     err("Cannot open file %s for writing\n",configFile);
9283     exit(1);
9284   }
9285 }
9286 //----------------------------------------------------------------------------
9287 // read and parse a tag file
9288
9289 //static bool readLineFromFile(QFile &f,QCString &s)
9290 //{
9291 //  char c=0;
9292 //  s.resize(0);
9293 //  while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
9294 //  return f.atEnd();
9295 //}
9296
9297 //----------------------------------------------------------------------------
9298
9299 static void readTagFile(Entry *root,const char *tl)
9300 {
9301   QCString tagLine = tl;
9302   QCString fileName;
9303   QCString destName;
9304   int eqPos = tagLine.find('=');
9305   if (eqPos!=-1) // tag command contains a destination
9306   {
9307     fileName = tagLine.left(eqPos).stripWhiteSpace();
9308     destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9309     QFileInfo fi(fileName);
9310     Doxygen::tagDestinationDict.insert(fi.absFilePath().utf8(),new QCString(destName));
9311     //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
9312   }
9313   else
9314   {
9315     fileName = tagLine;
9316   }
9317
9318   QFileInfo fi(fileName);
9319   if (!fi.exists() || !fi.isFile())
9320   {
9321     err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
9322         fileName.data());
9323     return;
9324   }
9325
9326   if (!destName.isEmpty())
9327     msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
9328   else
9329     msg("Reading tag file `%s'...\n",fileName.data());
9330
9331   parseTagFile(root,fi.absFilePath().utf8());
9332 }
9333
9334 //----------------------------------------------------------------------------
9335 static void copyLatexStyleSheet()
9336 {
9337   QStrList latexExtraStyleSheet = Config_getList(LATEX_EXTRA_STYLESHEET);
9338   for (uint i=0; i<latexExtraStyleSheet.count(); ++i)
9339   {
9340     QCString fileName(latexExtraStyleSheet.at(i));
9341     if (!fileName.isEmpty())
9342     {
9343       QFileInfo fi(fileName);
9344       if (!fi.exists())
9345       {
9346         err("Style sheet '%s' specified by LATEX_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9347       }
9348       else
9349       {
9350         QCString destFileName = Config_getString(LATEX_OUTPUT)+"/"+fi.fileName().data();
9351         if (!checkExtension(fi.fileName().data(), latexStyleExtension))
9352         {
9353           destFileName += latexStyleExtension;
9354         }
9355         copyFile(fileName, destFileName);
9356       }
9357     }
9358   }
9359 }
9360
9361 //----------------------------------------------------------------------------
9362 static void copyStyleSheet()
9363 {
9364   QCString &htmlStyleSheet = Config_getString(HTML_STYLESHEET);
9365   if (!htmlStyleSheet.isEmpty())
9366   {
9367     QFileInfo fi(htmlStyleSheet);
9368     if (!fi.exists())
9369     {
9370       err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
9371       htmlStyleSheet.resize(0); // revert to the default
9372     }
9373     else
9374     {
9375       QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9376       copyFile(htmlStyleSheet,destFileName);
9377     }
9378   }
9379   QStrList htmlExtraStyleSheet = Config_getList(HTML_EXTRA_STYLESHEET);
9380   for (uint i=0; i<htmlExtraStyleSheet.count(); ++i)
9381   {
9382     QCString fileName(htmlExtraStyleSheet.at(i));
9383     if (!fileName.isEmpty())
9384     {
9385       QFileInfo fi(fileName);
9386       if (!fi.exists())
9387       {
9388         err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9389       }
9390       else if (fi.fileName()=="doxygen.css" || fi.fileName()=="tabs.css" || fi.fileName()=="navtree.css")
9391       {
9392         err("Style sheet %s specified by HTML_EXTRA_STYLESHEET is already a built-in stylesheet. Please use a different name\n",fi.fileName().data());
9393       }
9394       else
9395       {
9396         QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9397         copyFile(fileName, destFileName);
9398       }
9399     }
9400   }
9401 }
9402
9403 static void copyLogo(const QCString &outputOption)
9404 {
9405   QCString &projectLogo = Config_getString(PROJECT_LOGO);
9406   if (!projectLogo.isEmpty())
9407   {
9408     QFileInfo fi(projectLogo);
9409     if (!fi.exists())
9410     {
9411       err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
9412       projectLogo.resize(0); // revert to the default
9413     }
9414     else
9415     {
9416       QCString destFileName = outputOption+"/"+fi.fileName().data();
9417       copyFile(projectLogo,destFileName);
9418       Doxygen::indexList->addImageFile(fi.fileName().data());
9419     }
9420   }
9421 }
9422
9423 static void copyExtraFiles(QStrList files,const QString &filesOption,const QCString &outputOption)
9424 {
9425   uint i;
9426   for (i=0; i<files.count(); ++i)
9427   {
9428     QCString fileName(files.at(i));
9429
9430     if (!fileName.isEmpty())
9431     {
9432       QFileInfo fi(fileName);
9433       if (!fi.exists())
9434       {
9435         err("Extra file '%s' specified in %s does not exist!\n", fileName.data(),filesOption.data());
9436       }
9437       else
9438       {
9439         QCString destFileName = outputOption+"/"+fi.fileName().data();
9440         Doxygen::indexList->addImageFile(fi.fileName().utf8());
9441         copyFile(fileName, destFileName);
9442       }
9443     }
9444   }
9445 }
9446
9447 //----------------------------------------------------------------------------
9448
9449 static ParserInterface *getParserForFile(const char *fn)
9450 {
9451   QCString fileName=fn;
9452   QCString extension;
9453   int sep = fileName.findRev('/');
9454   int ei = fileName.findRev('.');
9455   if (ei!=-1 && (sep==-1 || ei>sep)) // matches dir/file.ext but not dir.1/file
9456   {
9457     extension=fileName.right(fileName.length()-ei);
9458   }
9459   else
9460   {
9461     extension = ".no_extension";
9462   }
9463
9464   return Doxygen::parserManager->getParser(extension);
9465 }
9466
9467 static void parseFile(ParserInterface *parser,
9468                       Entry *root,EntryNav *rootNav,FileDef *fd,const char *fn,
9469                       bool sameTu,QStrList &filesInSameTu)
9470 {
9471 #if USE_LIBCLANG
9472   static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9473 #else
9474   static bool clangAssistedParsing = FALSE;
9475 #endif
9476   QCString fileName=fn;
9477   QCString extension;
9478   int ei = fileName.findRev('.');
9479   if (ei!=-1)
9480   {
9481     extension=fileName.right(fileName.length()-ei);
9482   }
9483   else
9484   {
9485     extension = ".no_extension";
9486   }
9487
9488   QFileInfo fi(fileName);
9489   BufStr preBuf(fi.size()+4096);
9490
9491   if (Config_getBool(ENABLE_PREPROCESSING) &&
9492       parser->needsPreprocessing(extension))
9493   {
9494     BufStr inBuf(fi.size()+4096);
9495     msg("Preprocessing %s...\n",fn);
9496     readInputFile(fileName,inBuf);
9497     preprocessFile(fileName,inBuf,preBuf);
9498   }
9499   else // no preprocessing
9500   {
9501     msg("Reading %s...\n",fn);
9502     readInputFile(fileName,preBuf);
9503   }
9504   if (preBuf.data() && preBuf.curPos()>0 && *(preBuf.data()+preBuf.curPos()-1)!='\n')
9505   {
9506     preBuf.addChar('\n'); // add extra newline to help parser
9507   }
9508
9509   BufStr convBuf(preBuf.curPos()+1024);
9510
9511   // convert multi-line C++ comments to C style comments
9512   convertCppComments(&preBuf,&convBuf,fileName);
9513
9514   convBuf.addChar('\0');
9515
9516   if (clangAssistedParsing && !sameTu)
9517   {
9518     fd->getAllIncludeFilesRecursively(filesInSameTu);
9519   }
9520
9521   // use language parse to parse the file
9522   parser->parseInput(fileName,convBuf.data(),root,sameTu,filesInSameTu);
9523
9524   // store the Entry tree in a file and create an index to
9525   // navigate/load entries
9526   //printf("root->createNavigationIndex for %s\n",fd->name().data());
9527   root->createNavigationIndex(rootNav,g_storage,fd);
9528 }
9529
9530 //! parse the list of input files
9531 static void parseFiles(Entry *root,EntryNav *rootNav)
9532 {
9533 #if USE_LIBCLANG
9534   static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9535   if (clangAssistedParsing)
9536   {
9537     QDict<void> g_processedFiles(10007);
9538
9539     // create a dictionary with files to process
9540     QDict<void> g_filesToProcess(10007);
9541     StringListIterator it(g_inputFiles);
9542     QCString *s;
9543     for (;(s=it.current());++it)
9544     {
9545       g_filesToProcess.insert(*s,(void*)0x8);
9546     }
9547
9548     // process source files (and their include dependencies)
9549     for (it.toFirst();(s=it.current());++it)
9550     {
9551       bool ambig;
9552       FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9553       ASSERT(fd!=0);
9554       if (fd->isSource() && !fd->isReference()) // this is a source file
9555       {
9556         QStrList filesInSameTu;
9557         ParserInterface * parser = getParserForFile(s->data());
9558         parser->startTranslationUnit(s->data());
9559         parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9560         //printf("  got %d extra files in tu\n",filesInSameTu.count());
9561
9562         // Now process any include files in the same translation unit
9563         // first. When libclang is used this is much more efficient.
9564         char *incFile = filesInSameTu.first();
9565         while (incFile && g_filesToProcess.find(incFile))
9566         {
9567           if (qstrcmp(incFile,s->data()) && !g_processedFiles.find(incFile))
9568           {
9569             FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
9570             if (ifd && !ifd->isReference())
9571             {
9572               QStrList moreFiles;
9573               //printf("  Processing %s in same translation unit as %s\n",incFile,s->data());
9574               parseFile(parser,root,rootNav,ifd,incFile,TRUE,moreFiles);
9575               g_processedFiles.insert(incFile,(void*)0x8);
9576             }
9577           }
9578           incFile = filesInSameTu.next();
9579         }
9580         parser->finishTranslationUnit();
9581         g_processedFiles.insert(*s,(void*)0x8);
9582       }
9583     }
9584     // process remaining files
9585     for (it.toFirst();(s=it.current());++it)
9586     {
9587       if (!g_processedFiles.find(*s)) // not yet processed
9588       {
9589         bool ambig;
9590         QStrList filesInSameTu;
9591         FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9592         ASSERT(fd!=0);
9593         ParserInterface * parser = getParserForFile(s->data());
9594         parser->startTranslationUnit(s->data());
9595         parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9596         parser->finishTranslationUnit();
9597         g_processedFiles.insert(*s,(void*)0x8);
9598       }
9599     }
9600   }
9601   else // normal pocessing
9602 #endif
9603   {
9604     StringListIterator it(g_inputFiles);
9605     QCString *s;
9606     for (;(s=it.current());++it)
9607     {
9608       bool ambig;
9609       QStrList filesInSameTu;
9610       FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9611       ASSERT(fd!=0);
9612       ParserInterface * parser = getParserForFile(s->data());
9613       parser->startTranslationUnit(s->data());
9614       parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9615     }
9616   }
9617 }
9618
9619 // resolves a path that may include symlinks, if a recursive symlink is
9620 // found an empty string is returned.
9621 static QCString resolveSymlink(QCString path)
9622 {
9623   int sepPos=0;
9624   int oldPos=0;
9625   QFileInfo fi;
9626   QDict<void> nonSymlinks;
9627   QDict<void> known;
9628   QCString result = path;
9629   QCString oldPrefix = "/";
9630   do
9631   {
9632 #ifdef WIN32
9633     // UNC path, skip server and share name
9634     if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
9635       sepPos = result.find('/',2);
9636     if (sepPos!=-1)
9637       sepPos = result.find('/',sepPos+1);
9638 #else
9639     sepPos = result.find('/',sepPos+1);
9640 #endif
9641     QCString prefix = sepPos==-1 ? result : result.left(sepPos);
9642     if (nonSymlinks.find(prefix)==0)
9643     {
9644       fi.setFile(prefix);
9645       if (fi.isSymLink())
9646       {
9647         QString target = fi.readLink();
9648         bool isRelative = QFileInfo(target).isRelative();
9649         if (isRelative)
9650         {
9651           target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
9652         }
9653         if (sepPos!=-1)
9654         {
9655           if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
9656           {
9657             target+='/';
9658           }
9659           target+=result.mid(sepPos);
9660         }
9661         result = QDir::cleanDirPath(target).data();
9662         sepPos = 0;
9663         if (known.find(result)) return QCString(); // recursive symlink!
9664         known.insert(result,(void*)0x8);
9665         if (isRelative)
9666         {
9667           sepPos = oldPos;
9668         }
9669         else // link to absolute path
9670         {
9671           sepPos = 0;
9672           oldPrefix = "/";
9673         }
9674       }
9675       else
9676       {
9677         nonSymlinks.insert(prefix,(void*)0x8);
9678         oldPrefix = prefix;
9679       }
9680       oldPos = sepPos;
9681     }
9682   }
9683   while (sepPos!=-1);
9684   return QDir::cleanDirPath(result).data();
9685 }
9686
9687 static QDict<void> g_pathsVisited(1009);
9688
9689 //----------------------------------------------------------------------------
9690 // Read all files matching at least one pattern in `patList' in the
9691 // directory represented by `fi'.
9692 // The directory is read iff the recusiveFlag is set.
9693 // The contents of all files is append to the input string
9694
9695 int readDir(QFileInfo *fi,
9696             FileNameList *fnList,
9697             FileNameDict *fnDict,
9698             StringDict  *exclDict,
9699             QStrList *patList,
9700             QStrList *exclPatList,
9701             StringList *resultList,
9702             StringDict *resultDict,
9703             bool errorIfNotExist,
9704             bool recursive,
9705             QDict<void> *killDict,
9706             QDict<void> *paths
9707            )
9708 {
9709   QCString dirName = fi->absFilePath().utf8();
9710   if (paths && paths->find(dirName)==0)
9711   {
9712     paths->insert(dirName,(void*)0x8);
9713   }
9714   if (fi->isSymLink())
9715   {
9716     dirName = resolveSymlink(dirName.data());
9717     if (dirName.isEmpty()) return 0;            // recursive symlink
9718     if (g_pathsVisited.find(dirName)) return 0; // already visited path
9719     g_pathsVisited.insert(dirName,(void*)0x8);
9720   }
9721   QDir dir(dirName);
9722   dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
9723   int totalSize=0;
9724   msg("Searching for files in directory %s\n", fi->absFilePath().data());
9725   //printf("killDict=%p count=%d\n",killDict,killDict->count());
9726
9727   const QFileInfoList *list = dir.entryInfoList();
9728   if (list)
9729   {
9730     QFileInfoListIterator it( *list );
9731     QFileInfo *cfi;
9732
9733     while ((cfi=it.current()))
9734     {
9735       if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0)
9736       { // file should not be excluded
9737         //printf("killDict->find(%s)\n",cfi->absFilePath().data());
9738         if (!cfi->exists() || !cfi->isReadable())
9739         {
9740           if (errorIfNotExist)
9741           {
9742             warn_uncond("source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
9743           }
9744         }
9745         else if (cfi->isFile() &&
9746             (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9747             (patList==0 || patternMatch(*cfi,patList)) &&
9748             !patternMatch(*cfi,exclPatList) &&
9749             (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
9750             )
9751         {
9752           totalSize+=cfi->size()+cfi->absFilePath().length()+4;
9753           QCString name=cfi->fileName().utf8();
9754           //printf("New file %s\n",name.data());
9755           if (fnDict)
9756           {
9757             FileDef  *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
9758             FileName *fn=0;
9759             if (!name.isEmpty() && (fn=(*fnDict)[name]))
9760             {
9761               fn->append(fd);
9762             }
9763             else
9764             {
9765               fn = new FileName(cfi->absFilePath().utf8(),name);
9766               fn->append(fd);
9767               if (fnList) fnList->append(fn);
9768               fnDict->insert(name,fn);
9769             }
9770           }
9771           QCString *rs=0;
9772           if (resultList || resultDict)
9773           {
9774             rs=new QCString(cfi->absFilePath().utf8());
9775           }
9776           if (resultList) resultList->append(rs);
9777           if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
9778           if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
9779         }
9780         else if (recursive &&
9781             (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9782             cfi->isDir() &&
9783             !patternMatch(*cfi,exclPatList) &&
9784             cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
9785         {
9786           cfi->setFile(cfi->absFilePath());
9787           totalSize+=readDir(cfi,fnList,fnDict,exclDict,
9788               patList,exclPatList,resultList,resultDict,errorIfNotExist,
9789               recursive,killDict,paths);
9790         }
9791       }
9792       ++it;
9793     }
9794   }
9795   return totalSize;
9796 }
9797
9798
9799 //----------------------------------------------------------------------------
9800 // read a file or all files in a directory and append their contents to the
9801 // input string. The names of the files are appended to the `fiList' list.
9802
9803 int readFileOrDirectory(const char *s,
9804                         FileNameList *fnList,
9805                         FileNameDict *fnDict,
9806                         StringDict *exclDict,
9807                         QStrList *patList,
9808                         QStrList *exclPatList,
9809                         StringList *resultList,
9810                         StringDict *resultDict,
9811                         bool recursive,
9812                         bool errorIfNotExist,
9813                         QDict<void> *killDict,
9814                         QDict<void> *paths
9815                        )
9816 {
9817   //printf("killDict=%p count=%d\n",killDict,killDict->count());
9818   // strip trailing slashes
9819   if (s==0) return 0;
9820   QCString fs = s;
9821   char lc = fs.at(fs.length()-1);
9822   if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9823
9824   QFileInfo fi(fs);
9825   //printf("readFileOrDirectory(%s)\n",s);
9826   int totalSize=0;
9827   {
9828     if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9829     {
9830       if (!fi.exists() || !fi.isReadable())
9831       {
9832         if (errorIfNotExist)
9833         {
9834           warn_uncond("source %s is not a readable file or directory... skipping.\n",s);
9835         }
9836       }
9837       else if (!Config_getBool(EXCLUDE_SYMLINKS) || !fi.isSymLink())
9838       {
9839         if (fi.isFile())
9840         {
9841           QCString dirPath = fi.dirPath(TRUE).utf8();
9842           QCString filePath = fi.absFilePath().utf8();
9843           if (paths && paths->find(dirPath))
9844           {
9845             paths->insert(dirPath,(void*)0x8);
9846           }
9847           //printf("killDict->find(%s)\n",fi.absFilePath().data());
9848           if (killDict==0 || killDict->find(filePath)==0)
9849           {
9850             totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input);
9851             //fiList->inSort(new FileInfo(fi));
9852             QCString name=fi.fileName().utf8();
9853             //printf("New file %s\n",name.data());
9854             if (fnDict)
9855             {
9856               FileDef  *fd=new FileDef(dirPath+"/",name);
9857               FileName *fn=0;
9858               if (!name.isEmpty() && (fn=(*fnDict)[name]))
9859               {
9860                 fn->append(fd);
9861               }
9862               else
9863               {
9864                 fn = new FileName(filePath,name);
9865                 fn->append(fd);
9866                 if (fnList) fnList->append(fn);
9867                 fnDict->insert(name,fn);
9868               }
9869             }
9870             QCString *rs=0;
9871             if (resultList || resultDict)
9872             {
9873               rs=new QCString(filePath);
9874               if (resultList) resultList->append(rs);
9875               if (resultDict) resultDict->insert(filePath,rs);
9876             }
9877
9878             if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9879           }
9880         }
9881         else if (fi.isDir()) // readable dir
9882         {
9883           totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9884               exclPatList,resultList,resultDict,errorIfNotExist,
9885               recursive,killDict,paths);
9886         }
9887       }
9888     }
9889   }
9890   return totalSize;
9891 }
9892
9893 //----------------------------------------------------------------------------
9894
9895 void readFormulaRepository(QCString dir, bool cmp)
9896 {
9897   static int current_repository = 0; 
9898   int new_repository = 0; 
9899   QFile f(dir+"/formula.repository");
9900   if (f.open(IO_ReadOnly)) // open repository
9901   {
9902     msg("Reading formula repository...\n");
9903     QTextStream t(&f);
9904     QCString line;
9905     Formula *f;
9906     while (!t.eof())
9907     {
9908       line=t.readLine().utf8();
9909       int se=line.find(':'); // find name and text separator.
9910       if (se==-1)
9911       {
9912         warn_uncond("formula.repository is corrupted!\n");
9913         break;
9914       }
9915       else
9916       {
9917         QCString formName = line.left(se);
9918         QCString formText = line.right(line.length()-se-1);
9919         if (cmp)
9920         {
9921           if ((f=Doxygen::formulaDict->find(formText))==0)
9922           {
9923             err("discrepancy between formula repositories! Remove "
9924                 "formula.repository and from_* files from output directories.");
9925             exit(1);
9926           }
9927           QCString formLabel;
9928           formLabel.sprintf("\\form#%d",f->getId());
9929           if (formLabel != formName)
9930           {
9931             err("discrepancy between formula repositories! Remove "
9932                 "formula.repository and from_* files from output directories.");
9933             exit(1);
9934           }
9935           new_repository++;
9936         }
9937         else
9938         {
9939           f=new Formula(formText);
9940           Doxygen::formulaList->append(f);
9941           Doxygen::formulaDict->insert(formText,f);
9942           Doxygen::formulaNameDict->insert(formName,f);
9943           current_repository++;
9944         }
9945       }
9946     }
9947   }
9948   if (cmp && (current_repository != new_repository))
9949   {
9950     err("size discrepancy between formula repositories! Remove "
9951         "formula.repository and from_* files from output directories.");
9952     exit(1);
9953   }
9954 }
9955
9956 //----------------------------------------------------------------------------
9957
9958 static void expandAliases()
9959 {
9960   QDictIterator<QCString> adi(Doxygen::aliasDict);
9961   QCString *s;
9962   for (adi.toFirst();(s=adi.current());++adi)
9963   {
9964     *s = expandAlias(adi.currentKey(),*s);
9965   }
9966 }
9967
9968 //----------------------------------------------------------------------------
9969
9970 static void escapeAliases()
9971 {
9972   QDictIterator<QCString> adi(Doxygen::aliasDict);
9973   QCString *s;
9974   for (adi.toFirst();(s=adi.current());++adi)
9975   {
9976     QCString value=*s,newValue;
9977     int in,p=0;
9978     // for each \n in the alias command value
9979     while ((in=value.find("\\n",p))!=-1)
9980     {
9981       newValue+=value.mid(p,in-p);
9982       // expand \n's except if \n is part of a built-in command.
9983       if (value.mid(in,5)!="\\note" &&
9984           value.mid(in,5)!="\\name" &&
9985           value.mid(in,10)!="\\namespace" &&
9986           value.mid(in,14)!="\\nosubgrouping"
9987          )
9988       {
9989         newValue+="\\_linebr ";
9990       }
9991       else
9992       {
9993         newValue+="\\n";
9994       }
9995       p=in+2;
9996     }
9997     newValue+=value.mid(p,value.length()-p);
9998     *s=newValue;
9999     p = 0;
10000     newValue = "";
10001     while ((in=value.find("^^",p))!=-1)
10002     {
10003       newValue+=value.mid(p,in-p);
10004       newValue+="@_linebr";
10005       p=in+2;
10006     }
10007     newValue+=value.mid(p,value.length()-p);
10008     *s=newValue;
10009     //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
10010   }
10011 }
10012
10013 //----------------------------------------------------------------------------
10014
10015 void readAliases()
10016 {
10017   // add aliases to a dictionary
10018   Doxygen::aliasDict.setAutoDelete(TRUE);
10019   QStrList &aliasList = Config_getList(ALIASES);
10020   const char *s=aliasList.first();
10021   while (s)
10022   {
10023     if (Doxygen::aliasDict[s]==0)
10024     {
10025       QCString alias=s;
10026       int i=alias.find('=');
10027       if (i>0)
10028       {
10029         QCString name=alias.left(i).stripWhiteSpace();
10030         QCString value=alias.right(alias.length()-i-1);
10031         //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
10032         if (!name.isEmpty())
10033         {
10034           QCString *dn=Doxygen::aliasDict[name];
10035           if (dn==0) // insert new alias
10036           {
10037             Doxygen::aliasDict.insert(name,new QCString(value));
10038           }
10039           else // overwrite previous alias
10040           {
10041             *dn=value;
10042           }
10043         }
10044       }
10045     }
10046     s=aliasList.next();
10047   }
10048   expandAliases();
10049   escapeAliases();
10050 }
10051
10052 //----------------------------------------------------------------------------
10053
10054 static void dumpSymbol(FTextStream &t,Definition *d)
10055 {
10056   QCString anchor;
10057   if (d->definitionType()==Definition::TypeMember)
10058   {
10059     MemberDef *md = (MemberDef *)d;
10060     anchor=":"+md->anchor();
10061   }
10062   QCString scope;
10063   if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope)
10064   {
10065     scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
10066   }
10067   t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
10068     << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
10069     << scope << "','"
10070     << d->name() << "','"
10071     << d->getDefFileName() << "','"
10072     << d->getDefLine()
10073     << "');" << endl;
10074 }
10075
10076 static void dumpSymbolMap()
10077 {
10078   QFile f("symbols.sql");
10079   if (f.open(IO_WriteOnly))
10080   {
10081     FTextStream t(&f);
10082     QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
10083     DefinitionIntf *intf;
10084     for (;(intf=di.current());++di)
10085     {
10086       if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
10087       {
10088         DefinitionListIterator dli(*(DefinitionList*)intf);
10089         Definition *d;
10090         // for each symbol
10091         for (dli.toFirst();(d=dli.current());++dli)
10092         {
10093           dumpSymbol(t,d);
10094         }
10095       }
10096       else // single symbol
10097       {
10098         Definition *d = (Definition *)intf;
10099         if (d!=Doxygen::globalScope) dumpSymbol(t,d);
10100       }
10101     }
10102   }
10103 }
10104
10105 // print developer options of doxygen
10106 static void devUsage()
10107 {
10108   msg("Developer parameters:\n");
10109   msg("  -m          dump symbol map\n");
10110   msg("  -b          output to wizard\n");
10111   msg("  -T          activates output generation via Django like template\n");
10112   msg("  -d <level>  enable a debug level, such as (multiple invocations of -d are possible):\n");
10113   Debug::printFlags();
10114 }
10115
10116
10117 //----------------------------------------------------------------------------
10118 // print the usage of doxygen
10119
10120 static void usage(const char *name)
10121 {
10122   msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2015\n\n",versionString);
10123   msg("You can use doxygen in a number of ways:\n\n");
10124   msg("1) Use doxygen to generate a template configuration file:\n");
10125   msg("    %s [-s] -g [configName]\n\n",name);
10126   msg("    If - is used for configName doxygen will write to standard output.\n\n");
10127   msg("2) Use doxygen to update an old configuration file:\n");
10128   msg("    %s [-s] -u [configName]\n\n",name);
10129   msg("3) Use doxygen to generate documentation using an existing ");
10130   msg("configuration file:\n");
10131   msg("    %s [configName]\n\n",name);
10132   msg("    If - is used for configName doxygen will read from standard input.\n\n");
10133   msg("4) Use doxygen to generate a template file controlling the layout of the\n");
10134   msg("   generated documentation:\n");
10135   msg("    %s -l [layoutFileName.xml]\n\n",name);
10136   msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
10137   msg("    RTF:        %s -w rtf styleSheetFile\n",name);
10138   msg("    HTML:       %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
10139   msg("    LaTeX:      %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
10140   msg("6) Use doxygen to generate a rtf extensions file\n");
10141   msg("    RTF:   %s -e rtf extensionsFile\n\n",name);
10142   msg("7) Use doxygen to compare the used configuration file with the template configuration file\n");
10143   msg("    %s -x [configFile]\n\n",name);
10144   msg("8) Use doxygen to show a list of build in emoji.\n");
10145   msg("    %s -f emoji outputFileName\n\n",name);
10146   msg("    If - is used for outputFileName doxygen will write to standard output.\n\n");
10147   msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
10148   msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
10149   msg("-v print version string\n");
10150 }
10151
10152 //----------------------------------------------------------------------------
10153 // read the argument of option `c' from the comment argument list and
10154 // update the option index `optind'.
10155
10156 static const char *getArg(int argc,char **argv,int &optind)
10157 {
10158   char *s=0;
10159   if (qstrlen(&argv[optind][2])>0)
10160     s=&argv[optind][2];
10161   else if (optind+1<argc && argv[optind+1][0]!='-')
10162     s=argv[++optind];
10163   return s;
10164 }
10165
10166 //----------------------------------------------------------------------------
10167
10168 void initDoxygen()
10169 {
10170   initResources();
10171   const char *lang = portable_getenv("LC_ALL");
10172   if (lang) portable_setenv("LANG",lang);
10173   setlocale(LC_ALL,"");
10174   setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
10175   setlocale(LC_NUMERIC,"C");
10176
10177   portable_correct_path();
10178
10179   Doxygen::runningTime.start();
10180   initPreprocessor();
10181
10182   Doxygen::parserManager = new ParserManager;
10183   Doxygen::parserManager->registerDefaultParser(         new FileParser);
10184   Doxygen::parserManager->registerParser("c",            new CLanguageScanner);
10185   Doxygen::parserManager->registerParser("python",       new PythonLanguageScanner);
10186   Doxygen::parserManager->registerParser("fortran",      new FortranLanguageScanner);
10187   Doxygen::parserManager->registerParser("fortranfree",  new FortranLanguageScannerFree);
10188   Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed);
10189   Doxygen::parserManager->registerParser("vhdl",         new VHDLLanguageScanner);
10190   Doxygen::parserManager->registerParser("xml",          new XMLScanner);
10191   Doxygen::parserManager->registerParser("sql",          new SQLScanner);
10192   Doxygen::parserManager->registerParser("tcl",          new TclLanguageScanner);
10193   Doxygen::parserManager->registerParser("md",           new MarkdownFileParser);
10194
10195   // register any additional parsers here...
10196
10197   initDefaultExtensionMapping();
10198   initClassMemberIndices();
10199   initNamespaceMemberIndices();
10200   initFileMemberIndices();
10201
10202   Doxygen::symbolMap     = new QDict<DefinitionIntf>(50177);
10203 #ifdef USE_LIBCLANG
10204   Doxygen::clangUsrMap   = new QDict<Definition>(50177);
10205 #endif
10206   Doxygen::inputNameList = new FileNameList;
10207   Doxygen::inputNameList->setAutoDelete(TRUE);
10208   Doxygen::memberNameSDict = new MemberNameSDict(10000);
10209   Doxygen::memberNameSDict->setAutoDelete(TRUE);
10210   Doxygen::functionNameSDict = new MemberNameSDict(10000);
10211   Doxygen::functionNameSDict->setAutoDelete(TRUE);
10212   Doxygen::groupSDict = new GroupSDict(17);
10213   Doxygen::groupSDict->setAutoDelete(TRUE);
10214   Doxygen::namespaceSDict = new NamespaceSDict(20);
10215   Doxygen::namespaceSDict->setAutoDelete(TRUE);
10216   Doxygen::classSDict = new ClassSDict(1009);
10217   Doxygen::classSDict->setAutoDelete(TRUE);
10218   Doxygen::hiddenClasses = new ClassSDict(257);
10219   Doxygen::hiddenClasses->setAutoDelete(TRUE);
10220   Doxygen::directories = new DirSDict(17);
10221   Doxygen::directories->setAutoDelete(TRUE);
10222   Doxygen::pageSDict = new PageSDict(1009);          // all doc pages
10223   Doxygen::pageSDict->setAutoDelete(TRUE);
10224   Doxygen::exampleSDict = new PageSDict(1009);       // all examples
10225   Doxygen::exampleSDict->setAutoDelete(TRUE);
10226   Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
10227   Doxygen::tagDestinationDict.setAutoDelete(TRUE);
10228   Doxygen::dirRelations.setAutoDelete(TRUE);
10229   Doxygen::citeDict = new CiteDict(257);
10230   Doxygen::genericsDict = new GenericsSDict;
10231   Doxygen::indexList = new IndexList;
10232   Doxygen::formulaList = new FormulaList;
10233   Doxygen::formulaList->setAutoDelete(TRUE);
10234   Doxygen::formulaDict = new FormulaDict(1009);
10235   Doxygen::formulaNameDict = new FormulaDict(1009);
10236   Doxygen::sectionDict = new SectionDict(257);
10237   Doxygen::sectionDict->setAutoDelete(TRUE);
10238
10239   // initialisation of these globals depends on
10240   // configuration switches so we need to postpone these
10241   Doxygen::globalScope     = 0;
10242   Doxygen::inputNameDict   = 0;
10243   Doxygen::includeNameDict = 0;
10244   Doxygen::exampleNameDict = 0;
10245   Doxygen::imageNameDict   = 0;
10246   Doxygen::dotFileNameDict = 0;
10247   Doxygen::mscFileNameDict = 0;
10248   Doxygen::diaFileNameDict = 0;
10249
10250   /**************************************************************************
10251    *            Initialize some global constants
10252    **************************************************************************/
10253
10254   g_compoundKeywordDict.insert("template class",(void *)8);
10255   g_compoundKeywordDict.insert("template struct",(void *)8);
10256   g_compoundKeywordDict.insert("class",(void *)8);
10257   g_compoundKeywordDict.insert("struct",(void *)8);
10258   g_compoundKeywordDict.insert("union",(void *)8);
10259   g_compoundKeywordDict.insert("interface",(void *)8);
10260   g_compoundKeywordDict.insert("exception",(void *)8);
10261 }
10262
10263 void cleanUpDoxygen()
10264 {
10265   delete Doxygen::sectionDict;
10266   delete Doxygen::formulaNameDict;
10267   delete Doxygen::formulaDict;
10268   delete Doxygen::formulaList;
10269   delete Doxygen::indexList;
10270   delete Doxygen::genericsDict;
10271   delete Doxygen::inputNameDict;
10272   delete Doxygen::includeNameDict;
10273   delete Doxygen::exampleNameDict;
10274   delete Doxygen::imageNameDict;
10275   delete Doxygen::dotFileNameDict;
10276   delete Doxygen::mscFileNameDict;
10277   delete Doxygen::diaFileNameDict;
10278   delete Doxygen::mainPage;
10279   delete Doxygen::pageSDict;
10280   delete Doxygen::exampleSDict;
10281   delete Doxygen::globalScope;
10282   delete Doxygen::xrefLists;
10283   delete Doxygen::parserManager;
10284   cleanUpPreprocessor();
10285   delete theTranslator;
10286   delete g_outputList;
10287   Mappers::freeMappers();
10288   codeFreeScanner();
10289
10290   if (Doxygen::symbolMap)
10291   {
10292     // iterate through Doxygen::symbolMap and delete all
10293     // DefinitionList objects, since they have no owner
10294     QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
10295     DefinitionIntf *di;
10296     for (dli.toFirst();(di=dli.current());)
10297     {
10298       if (di->definitionType()==DefinitionIntf::TypeSymbolList)
10299       {
10300         DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
10301         delete (DefinitionList *)tmp;
10302       }
10303       else
10304       {
10305         ++dli;
10306       }
10307     }
10308   }
10309
10310   delete Doxygen::inputNameList;
10311   delete Doxygen::memberNameSDict;
10312   delete Doxygen::functionNameSDict;
10313   delete Doxygen::groupSDict;
10314   delete Doxygen::classSDict;
10315   delete Doxygen::hiddenClasses;
10316   delete Doxygen::namespaceSDict;
10317   delete Doxygen::directories;
10318
10319   //delete Doxygen::symbolMap; <- we cannot do this unless all static lists
10320   //                              (such as Doxygen::namespaceSDict)
10321   //                              with objects based on Definition are made
10322   //                              dynamic first
10323 }
10324
10325 static int computeIdealCacheParam(uint v)
10326 {
10327   //printf("computeIdealCacheParam(v=%u)\n",v);
10328
10329   int r=0;
10330   while (v!=0) v>>=1,r++;
10331   // r = log2(v)
10332
10333   // convert to a valid cache size value
10334   return QMAX(0,QMIN(r-16,9));
10335 }
10336
10337 void readConfiguration(int argc, char **argv)
10338 {
10339   /**************************************************************************
10340    *             Handle arguments                                           *
10341    **************************************************************************/
10342
10343   int optind=1;
10344   const char *configName=0;
10345   const char *layoutName=0;
10346   const char *debugLabel;
10347   const char *formatName;
10348   const char *listName;
10349   bool genConfig=FALSE;
10350   bool shortList=FALSE;
10351   bool diffList=FALSE;
10352   bool updateConfig=FALSE;
10353   int retVal;
10354   while (optind<argc && argv[optind][0]=='-' &&
10355                (isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
10356                 argv[optind][1]=='-')
10357         )
10358   {
10359     switch(argv[optind][1])
10360     {
10361       case 'g':
10362         genConfig=TRUE;
10363         break;
10364       case 'l':
10365         layoutName=getArg(argc,argv,optind);
10366         if (!layoutName)
10367         { layoutName="DoxygenLayout.xml"; }
10368         writeDefaultLayoutFile(layoutName);
10369         cleanUpDoxygen();
10370         exit(0);
10371         break;
10372       case 'd':
10373         debugLabel=getArg(argc,argv,optind);
10374         if (!debugLabel)
10375         {
10376           err("option \"-d\" is missing debug specifier.\n");
10377           devUsage();
10378           cleanUpDoxygen();
10379           exit(1);
10380         }
10381         retVal = Debug::setFlag(debugLabel);
10382         if (!retVal)
10383         {
10384           err("option \"-d\" has unknown debug specifier: \"%s\".\n",debugLabel);
10385           cleanUpDoxygen();
10386           exit(1);
10387         }
10388         break;
10389       case 'x':
10390         diffList=TRUE;
10391         break;
10392       case 's':
10393         shortList=TRUE;
10394         break;
10395       case 'u':
10396         updateConfig=TRUE;
10397         break;
10398       case 'e':
10399         formatName=getArg(argc,argv,optind);
10400         if (!formatName)
10401         {
10402           err("option \"-e\" is missing format specifier rtf.\n");
10403           cleanUpDoxygen();
10404           exit(1);
10405         }
10406         if (qstricmp(formatName,"rtf")==0)
10407         {
10408           if (optind+1>=argc)
10409           {
10410             err("option \"-e rtf\" is missing an extensions file name\n");
10411             cleanUpDoxygen();
10412             exit(1);
10413           }
10414           QFile f;
10415           if (openOutputFile(argv[optind+1],f))
10416           {
10417             RTFGenerator::writeExtensionsFile(f);
10418           }
10419           cleanUpDoxygen();
10420           exit(0);
10421         }
10422         err("option \"-e\" has invalid format specifier.\n");
10423         cleanUpDoxygen();
10424         exit(1);
10425         break;
10426       case 'f':
10427         listName=getArg(argc,argv,optind);
10428         if (!listName)
10429         {
10430           err("option \"-f\" is missing list specifier.\n");
10431           cleanUpDoxygen();
10432           exit(1);
10433         }
10434         if (qstricmp(listName,"emoji")==0)
10435         {
10436           if (optind+1>=argc)
10437           {
10438             err("option \"-f emoji\" is missing an output file name\n");
10439             cleanUpDoxygen();
10440             exit(1);
10441           }
10442           QFile f;
10443           if (openOutputFile(argv[optind+1],f))
10444           {
10445             EmojiEntityMapper::instance()->writeEmojiFile(f);
10446           }
10447           cleanUpDoxygen();
10448           exit(0);
10449         }
10450         err("option \"-f\" has invalid list specifier.\n");
10451         cleanUpDoxygen();
10452         exit(1);
10453         break;
10454       case 'w':
10455         formatName=getArg(argc,argv,optind);
10456         if (!formatName)
10457         {
10458           err("option \"-w\" is missing format specifier rtf, html or latex\n");
10459           cleanUpDoxygen();
10460           exit(1);
10461         }
10462         if (qstricmp(formatName,"rtf")==0)
10463         {
10464           if (optind+1>=argc)
10465           {
10466             err("option \"-w rtf\" is missing a style sheet file name\n");
10467             cleanUpDoxygen();
10468             exit(1);
10469           }
10470           QFile f;
10471           if (openOutputFile(argv[optind+1],f))
10472           {
10473             RTFGenerator::writeStyleSheetFile(f);
10474           }
10475           cleanUpDoxygen();
10476           exit(1);
10477         }
10478         else if (qstricmp(formatName,"html")==0)
10479         {
10480           Config::init();
10481           if (optind+4<argc || QFileInfo("Doxyfile").exists())
10482              // explicit config file mentioned or default found on disk
10483           {
10484             QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10485             if (!Config::parse(df)) // parse the config file
10486             {
10487               err("error opening or reading configuration file %s!\n",argv[optind+4]);
10488               cleanUpDoxygen();
10489               exit(1);
10490             }
10491           }
10492           if (optind+3>=argc)
10493           {
10494             err("option \"-w html\" does not have enough arguments\n");
10495             cleanUpDoxygen();
10496             exit(1);
10497           }
10498           Config::postProcess(TRUE);
10499           Config::checkAndCorrect();
10500
10501           QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10502           if (!setTranslator(outputLanguage))
10503           {
10504             warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10505           }
10506
10507           QFile f;
10508           if (openOutputFile(argv[optind+1],f))
10509           {
10510             HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
10511           }
10512           f.close();
10513           if (openOutputFile(argv[optind+2],f))
10514           {
10515             HtmlGenerator::writeFooterFile(f);
10516           }
10517           f.close();
10518           if (openOutputFile(argv[optind+3],f))
10519           {
10520             HtmlGenerator::writeStyleSheetFile(f);
10521           }
10522           cleanUpDoxygen();
10523           exit(0);
10524         }
10525         else if (qstricmp(formatName,"latex")==0)
10526         {
10527           Config::init();
10528           if (optind+4<argc || QFileInfo("Doxyfile").exists())
10529           {
10530             QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10531             if (!Config::parse(df))
10532             {
10533               err("error opening or reading configuration file %s!\n",argv[optind+4]);
10534               cleanUpDoxygen();
10535               exit(1);
10536             }
10537           }
10538           if (optind+3>=argc)
10539           {
10540             err("option \"-w latex\" does not have enough arguments\n");
10541             cleanUpDoxygen();
10542             exit(1);
10543           }
10544           Config::postProcess(TRUE);
10545           Config::checkAndCorrect();
10546
10547           QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10548           if (!setTranslator(outputLanguage))
10549           {
10550             warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10551           }
10552
10553           QFile f;
10554           if (openOutputFile(argv[optind+1],f))
10555           {
10556             LatexGenerator::writeHeaderFile(f);
10557           }
10558           f.close();
10559           if (openOutputFile(argv[optind+2],f))
10560           {
10561             LatexGenerator::writeFooterFile(f);
10562           }
10563           f.close();
10564           if (openOutputFile(argv[optind+3],f))
10565           {
10566             LatexGenerator::writeStyleSheetFile(f);
10567           }
10568           cleanUpDoxygen();
10569           exit(0);
10570         }
10571         else
10572         {
10573           err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",formatName);
10574           cleanUpDoxygen();
10575           exit(1);
10576         }
10577         break;
10578       case 'm':
10579         g_dumpSymbolMap = TRUE;
10580         break;
10581       case 'v':
10582         msg("%s\n",versionString);
10583         cleanUpDoxygen();
10584         exit(0);
10585         break;
10586       case '-':
10587         if (qstrcmp(&argv[optind][2],"help")==0)
10588         {
10589           usage(argv[0]);
10590           exit(0);
10591         }
10592         else if (qstrcmp(&argv[optind][2],"version")==0)
10593         {
10594           msg("%s\n",versionString);
10595           cleanUpDoxygen();
10596           exit(0);
10597         }
10598         else
10599         {
10600           err("Unknown option \"-%s\"\n",&argv[optind][1]);
10601           usage(argv[0]);
10602           exit(1);
10603         }
10604         break;
10605       case 'b':
10606         setvbuf(stdout,NULL,_IONBF,0);
10607         Doxygen::outputToWizard=TRUE;
10608         break;
10609       case 'T':
10610         msg("Warning: this option activates output generation via Django like template files. "
10611             "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
10612             "Only use if you are a doxygen developer\n");
10613         g_useOutputTemplate=TRUE;
10614         break;
10615       case 'h':
10616       case '?':
10617         usage(argv[0]);
10618         exit(0);
10619         break;
10620       default:
10621         err("Unknown option \"-%c\"\n",argv[optind][1]);
10622         usage(argv[0]);
10623         exit(1);
10624     }
10625     optind++;
10626   }
10627
10628   /**************************************************************************
10629    *            Parse or generate the config file                           *
10630    **************************************************************************/
10631
10632   Config::init();
10633
10634   QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
10635   if (optind>=argc)
10636   {
10637     if (configFileInfo1.exists())
10638     {
10639       configName="Doxyfile";
10640     }
10641     else if (configFileInfo2.exists())
10642     {
10643       configName="doxyfile";
10644     }
10645     else if (genConfig)
10646     {
10647       configName="Doxyfile";
10648     }
10649     else
10650     {
10651       err("Doxyfile not found and no input file specified!\n");
10652       usage(argv[0]);
10653       exit(1);
10654     }
10655   }
10656   else
10657   {
10658     QFileInfo fi(argv[optind]);
10659     if (fi.exists() || qstrcmp(argv[optind],"-")==0 || genConfig)
10660     {
10661       configName=argv[optind];
10662     }
10663     else
10664     {
10665       err("configuration file %s not found!\n",argv[optind]);
10666       usage(argv[0]);
10667       exit(1);
10668     }
10669   }
10670
10671   if (genConfig && g_useOutputTemplate)
10672   {
10673     generateTemplateFiles("templates");
10674     cleanUpDoxygen();
10675     exit(0);
10676   }
10677
10678   if (genConfig)
10679   {
10680     generateConfigFile(configName,shortList);
10681     cleanUpDoxygen();
10682     exit(0);
10683   }
10684
10685   if (!Config::parse(configName,updateConfig))
10686   {
10687     err("could not open or read configuration file %s!\n",configName);
10688     cleanUpDoxygen();
10689     exit(1);
10690   }
10691
10692   if (diffList)
10693   {
10694     compareDoxyfile();
10695     cleanUpDoxygen();
10696     exit(0);
10697   }
10698
10699   if (updateConfig)
10700   {
10701     generateConfigFile(configName,shortList,TRUE);
10702     cleanUpDoxygen();
10703     exit(0);
10704   }
10705
10706   /* Perlmod wants to know the path to the config file.*/
10707   QFileInfo configFileInfo(configName);
10708   setPerlModDoxyfile(configFileInfo.absFilePath().data());
10709
10710 }
10711
10712 /** check and resolve config options */
10713 void checkConfiguration()
10714 {
10715
10716   Config::postProcess(FALSE);
10717   Config::checkAndCorrect();
10718   initWarningFormat();
10719 }
10720
10721 /** adjust globals that depend on configuration settings. */
10722 void adjustConfiguration()
10723 {
10724   Doxygen::globalScope = new NamespaceDef("<globalScope>",1,1,"<globalScope>");
10725   Doxygen::inputNameDict = new FileNameDict(10007);
10726   Doxygen::includeNameDict = new FileNameDict(10007);
10727   Doxygen::exampleNameDict = new FileNameDict(1009);
10728   Doxygen::exampleNameDict->setAutoDelete(TRUE);
10729   Doxygen::imageNameDict = new FileNameDict(257);
10730   Doxygen::imageNameDict->setAutoDelete(TRUE);
10731   Doxygen::dotFileNameDict = new FileNameDict(257);
10732   Doxygen::dotFileNameDict->setAutoDelete(TRUE);
10733   Doxygen::mscFileNameDict = new FileNameDict(257);
10734   Doxygen::mscFileNameDict->setAutoDelete(TRUE);
10735   Doxygen::diaFileNameDict = new FileNameDict(257);
10736   Doxygen::diaFileNameDict->setAutoDelete(TRUE);
10737
10738   QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10739   if (!setTranslator(outputLanguage))
10740   {
10741     warn_uncond("Output language %s not supported! Using English instead.\n",
10742        outputLanguage.data());
10743   }
10744   QStrList &includePath = Config_getList(INCLUDE_PATH);
10745   char *s=includePath.first();
10746   while (s)
10747   {
10748     QFileInfo fi(s);
10749     addSearchDir(fi.absFilePath().utf8());
10750     s=includePath.next();
10751   }
10752
10753   /* Set the global html file extension. */
10754   Doxygen::htmlFileExtension = Config_getString(HTML_FILE_EXTENSION);
10755
10756
10757   Doxygen::xrefLists->setAutoDelete(TRUE);
10758
10759   Doxygen::parseSourcesNeeded = Config_getBool(CALL_GRAPH) ||
10760                                 Config_getBool(CALLER_GRAPH) ||
10761                                 Config_getBool(REFERENCES_RELATION) ||
10762                                 Config_getBool(REFERENCED_BY_RELATION);
10763
10764   Doxygen::markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
10765
10766   /**************************************************************************
10767    *            Add custom extension mappings
10768    **************************************************************************/
10769
10770   QStrList &extMaps = Config_getList(EXTENSION_MAPPING);
10771   char *mapping = extMaps.first();
10772   while (mapping)
10773   {
10774     QCString mapStr = mapping;
10775     int i;
10776     if ((i=mapStr.find('='))!=-1)
10777     {
10778       QCString ext=mapStr.left(i).stripWhiteSpace().lower();
10779       QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
10780       if (!updateLanguageMapping(ext,language))
10781       {
10782         err("Failed to map file extension '%s' to unsupported language '%s'.\n"
10783             "Check the EXTENSION_MAPPING setting in the config file.\n",
10784             ext.data(),language.data());
10785       }
10786       else
10787       {
10788         msg("Adding custom extension mapping: .%s will be treated as language %s\n",
10789             ext.data(),language.data());
10790       }
10791     }
10792     mapping = extMaps.next();
10793   }
10794
10795
10796   // add predefined macro name to a dictionary
10797   QStrList &expandAsDefinedList =Config_getList(EXPAND_AS_DEFINED);
10798   s=expandAsDefinedList.first();
10799   while (s)
10800   {
10801     if (Doxygen::expandAsDefinedDict[s]==0)
10802     {
10803       Doxygen::expandAsDefinedDict.insert(s,(void *)666);
10804     }
10805     s=expandAsDefinedList.next();
10806   }
10807
10808   // read aliases and store them in a dictionary
10809   readAliases();
10810
10811   // store number of spaces in a tab into Doxygen::spaces
10812   int &tabSize = Config_getInt(TAB_SIZE);
10813   Doxygen::spaces.resize(tabSize+1);
10814   int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
10815   Doxygen::spaces.at(tabSize)='\0';
10816 }
10817
10818 #ifdef HAS_SIGNALS
10819 static void stopDoxygen(int)
10820 {
10821   QDir thisDir;
10822   msg("Cleaning up...\n");
10823   if (!Doxygen::entryDBFileName.isEmpty())
10824   {
10825     thisDir.remove(Doxygen::entryDBFileName);
10826   }
10827   if (!Doxygen::objDBFileName.isEmpty())
10828   {
10829     thisDir.remove(Doxygen::objDBFileName);
10830   }
10831   if (!Doxygen::filterDBFileName.isEmpty())
10832   {
10833     thisDir.remove(Doxygen::filterDBFileName);
10834   }
10835   killpg(0,SIGINT);
10836   exit(1);
10837 }
10838 #endif
10839
10840 static void writeTagFile()
10841 {
10842   QCString &generateTagFile = Config_getString(GENERATE_TAGFILE);
10843   if (generateTagFile.isEmpty()) return;
10844
10845   QFile tag(generateTagFile);
10846   if (!tag.open(IO_WriteOnly))
10847   {
10848     err("cannot open tag file %s for writing\n",
10849         generateTagFile.data()
10850        );
10851     return;
10852   }
10853   FTextStream tagFile(&tag);
10854   tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
10855   tagFile << "<tagfile>" << endl;
10856
10857   // for each file
10858   FileNameListIterator fnli(*Doxygen::inputNameList);
10859   FileName *fn;
10860   for (fnli.toFirst();(fn=fnli.current());++fnli)
10861   {
10862     FileNameIterator fni(*fn);
10863     FileDef *fd;
10864     for (fni.toFirst();(fd=fni.current());++fni)
10865     {
10866       if (fd->isLinkableInProject()) fd->writeTagFile(tagFile);
10867     }
10868   }
10869   // for each class
10870   ClassSDict::Iterator cli(*Doxygen::classSDict);
10871   ClassDef *cd;
10872   for ( ; (cd=cli.current()) ; ++cli )
10873   {
10874     if (cd->isLinkableInProject()) cd->writeTagFile(tagFile);
10875   }
10876   // for each namespace
10877   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
10878   NamespaceDef *nd;
10879   for ( ; (nd=nli.current()) ; ++nli )
10880   {
10881     if (nd->isLinkableInProject()) nd->writeTagFile(tagFile);
10882   }
10883   // for each group
10884   GroupSDict::Iterator gli(*Doxygen::groupSDict);
10885   GroupDef *gd;
10886   for (gli.toFirst();(gd=gli.current());++gli)
10887   {
10888     if (gd->isLinkableInProject()) gd->writeTagFile(tagFile);
10889   }
10890   // for each page
10891   PageSDict::Iterator pdi(*Doxygen::pageSDict);
10892   PageDef *pd=0;
10893   for (pdi.toFirst();(pd=pdi.current());++pdi)
10894   {
10895     if (pd->isLinkableInProject()) pd->writeTagFile(tagFile);
10896   }
10897   if (Doxygen::mainPage) Doxygen::mainPage->writeTagFile(tagFile);
10898
10899   /*
10900   if (Doxygen::mainPage && !Config_getString(GENERATE_TAGFILE).isEmpty())
10901   {
10902     tagFile << "  <compound kind=\"page\">" << endl
10903                      << "    <name>"
10904                      << convertToXML(Doxygen::mainPage->name())
10905                      << "</name>" << endl
10906                      << "    <title>"
10907                      << convertToXML(Doxygen::mainPage->title())
10908                      << "</title>" << endl
10909                      << "    <filename>"
10910                      << convertToXML(Doxygen::mainPage->getOutputFileBase())
10911                      << "</filename>" << endl;
10912
10913     mainPage->writeDocAnchorsToTagFile();
10914     tagFile << "  </compound>" << endl;
10915   }
10916   */
10917
10918   tagFile << "</tagfile>" << endl;
10919 }
10920
10921 static void exitDoxygen()
10922 {
10923   if (!g_successfulRun)  // premature exit
10924   {
10925     QDir thisDir;
10926     msg("Exiting...\n");
10927     if (!Doxygen::entryDBFileName.isEmpty())
10928     {
10929       thisDir.remove(Doxygen::entryDBFileName);
10930     }
10931     if (!Doxygen::objDBFileName.isEmpty())
10932     {
10933       thisDir.remove(Doxygen::objDBFileName);
10934     }
10935     if (!Doxygen::filterDBFileName.isEmpty())
10936     {
10937       thisDir.remove(Doxygen::filterDBFileName);
10938     }
10939   }
10940 }
10941
10942 static QCString createOutputDirectory(const QCString &baseDirName,
10943                                   QCString &formatDirName,
10944                                   const char *defaultDirName)
10945 {
10946   // Note the & on the next line, we modify the formatDirOption!
10947   if (formatDirName.isEmpty())
10948   {
10949     formatDirName = baseDirName + defaultDirName;
10950   }
10951   else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
10952   {
10953     formatDirName.prepend(baseDirName+'/');
10954   }
10955   QDir formatDir(formatDirName);
10956   if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
10957   {
10958     err("Could not create output directory %s\n", formatDirName.data());
10959     cleanUpDoxygen();
10960     exit(1);
10961   }
10962   return formatDirName;
10963 }
10964
10965 static QCString getQchFileName()
10966 {
10967   QCString const & qchFile = Config_getString(QCH_FILE);
10968   if (!qchFile.isEmpty())
10969   {
10970     return qchFile;
10971   }
10972
10973   QCString const & projectName = Config_getString(PROJECT_NAME);
10974   QCString const & versionText = Config_getString(PROJECT_NUMBER);
10975
10976   return QCString("../qch/")
10977       + (projectName.isEmpty() ? QCString("index") : projectName)
10978       + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
10979       + QCString(".qch");
10980 }
10981
10982 void searchInputFiles()
10983 {
10984   QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
10985   bool alwaysRecursive = Config_getBool(RECURSIVE);
10986   StringDict excludeNameDict(1009);
10987   excludeNameDict.setAutoDelete(TRUE);
10988
10989   // gather names of all files in the include path
10990   g_s.begin("Searching for include files...\n");
10991   QStrList &includePathList = Config_getList(INCLUDE_PATH);
10992   char *s=includePathList.first();
10993   while (s)
10994   {
10995     QStrList &pl = Config_getList(INCLUDE_FILE_PATTERNS);
10996     if (pl.count()==0)
10997     {
10998       pl = Config_getList(FILE_PATTERNS);
10999     }
11000     readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
11001                         &exclPatterns,0,0,
11002                         alwaysRecursive);
11003     s=includePathList.next();
11004   }
11005   g_s.end();
11006
11007   g_s.begin("Searching for example files...\n");
11008   QStrList &examplePathList = Config_getList(EXAMPLE_PATH);
11009   s=examplePathList.first();
11010   while (s)
11011   {
11012     readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
11013                         &Config_getList(EXAMPLE_PATTERNS),
11014                         0,0,0,
11015                         (alwaysRecursive || Config_getBool(EXAMPLE_RECURSIVE)));
11016     s=examplePathList.next();
11017   }
11018   g_s.end();
11019
11020   g_s.begin("Searching for images...\n");
11021   QStrList &imagePathList=Config_getList(IMAGE_PATH);
11022   s=imagePathList.first();
11023   while (s)
11024   {
11025     readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
11026                         0,0,0,
11027                         alwaysRecursive);
11028     s=imagePathList.next();
11029   }
11030   g_s.end();
11031
11032   g_s.begin("Searching for dot files...\n");
11033   QStrList &dotFileList=Config_getList(DOTFILE_DIRS);
11034   s=dotFileList.first();
11035   while (s)
11036   {
11037     readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
11038                         0,0,0,
11039                         alwaysRecursive);
11040     s=dotFileList.next();
11041   }
11042   g_s.end();
11043
11044   g_s.begin("Searching for msc files...\n");
11045   QStrList &mscFileList=Config_getList(MSCFILE_DIRS);
11046   s=mscFileList.first();
11047   while (s)
11048   {
11049     readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
11050                         0,0,0,
11051                         alwaysRecursive);
11052     s=mscFileList.next();
11053   }
11054   g_s.end();
11055
11056   g_s.begin("Searching for dia files...\n");
11057   QStrList &diaFileList=Config_getList(DIAFILE_DIRS);
11058   s=diaFileList.first();
11059   while (s)
11060   {
11061     readFileOrDirectory(s,0,Doxygen::diaFileNameDict,0,0,
11062                         0,0,0,
11063                         alwaysRecursive);
11064     s=diaFileList.next();
11065   }
11066   g_s.end();
11067
11068   g_s.begin("Searching for files to exclude\n");
11069   QStrList &excludeList = Config_getList(EXCLUDE);
11070   s=excludeList.first();
11071   while (s)
11072   {
11073     readFileOrDirectory(s,0,0,0,&Config_getList(FILE_PATTERNS),
11074                         0,0,&excludeNameDict,
11075                         alwaysRecursive,
11076                         FALSE);
11077     s=excludeList.next();
11078   }
11079   g_s.end();
11080
11081   /**************************************************************************
11082    *             Determine Input Files                                      *
11083    **************************************************************************/
11084
11085   g_s.begin("Searching INPUT for files to process...\n");
11086   QDict<void> *killDict = new QDict<void>(10007);
11087   QStrList &inputList=Config_getList(INPUT);
11088   g_inputFiles.setAutoDelete(TRUE);
11089   s=inputList.first();
11090   while (s)
11091   {
11092     QCString path=s;
11093     uint l = path.length();
11094     if (l>0)
11095     {
11096       // strip trailing slashes
11097       if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
11098
11099       readFileOrDirectory(
11100           path,
11101           Doxygen::inputNameList,
11102           Doxygen::inputNameDict,
11103           &excludeNameDict,
11104           &Config_getList(FILE_PATTERNS),
11105           &exclPatterns,
11106           &g_inputFiles,0,
11107           alwaysRecursive,
11108           TRUE,
11109           killDict,
11110           &Doxygen::inputPaths);
11111     }
11112     s=inputList.next();
11113   }
11114   Doxygen::inputNameList->sort();
11115   delete killDict;
11116   g_s.end();
11117 }
11118
11119
11120 void parseInput()
11121 {
11122   atexit(exitDoxygen);
11123
11124
11125   /**************************************************************************
11126    *            Make sure the output directory exists
11127    **************************************************************************/
11128   QCString &outputDirectory = Config_getString(OUTPUT_DIRECTORY);
11129   if (outputDirectory.isEmpty())
11130   {
11131     outputDirectory=QDir::currentDirPath().utf8();
11132   }
11133   else
11134   {
11135     QDir dir(outputDirectory);
11136     if (!dir.exists())
11137     {
11138       dir.setPath(QDir::currentDirPath());
11139       if (!dir.mkdir(outputDirectory))
11140       {
11141         err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
11142             "exist and cannot be created\n",outputDirectory.data());
11143         cleanUpDoxygen();
11144         exit(1);
11145       }
11146       else
11147       {
11148         msg("Notice: Output directory `%s' does not exist. "
11149             "I have created it for you.\n", outputDirectory.data());
11150       }
11151       dir.cd(outputDirectory);
11152     }
11153     outputDirectory=dir.absPath().utf8();
11154   }
11155
11156   /**************************************************************************
11157    *            Initialize global lists and dictionaries
11158    **************************************************************************/
11159
11160   Doxygen::symbolStorage = new Store;
11161
11162   // also scale lookup cache with SYMBOL_CACHE_SIZE
11163   int cacheSize = Config_getInt(LOOKUP_CACHE_SIZE);
11164   if (cacheSize<0) cacheSize=0;
11165   if (cacheSize>9) cacheSize=9;
11166   uint lookupSize = 65536 << cacheSize;
11167   Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
11168   Doxygen::lookupCache->setAutoDelete(TRUE);
11169
11170 #ifdef HAS_SIGNALS
11171   signal(SIGINT, stopDoxygen);
11172 #endif
11173
11174   uint pid = portable_pid();
11175   Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
11176   Doxygen::objDBFileName.prepend(outputDirectory+"/");
11177   Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
11178   Doxygen::entryDBFileName.prepend(outputDirectory+"/");
11179   Doxygen::filterDBFileName.sprintf("doxygen_filterdb_%d.tmp",pid);
11180   Doxygen::filterDBFileName.prepend(outputDirectory+"/");
11181
11182   if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
11183   {
11184     err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
11185     exit(1);
11186   }
11187
11188
11189
11190   /**************************************************************************
11191    *            Check/create output directories                             *
11192    **************************************************************************/
11193
11194   QCString htmlOutput;
11195   bool &generateHtml = Config_getBool(GENERATE_HTML);
11196   if (generateHtml || g_useOutputTemplate /* TODO: temp hack */)
11197     htmlOutput = createOutputDirectory(outputDirectory,Config_getString(HTML_OUTPUT),"/html");
11198
11199   QCString docbookOutput;
11200   bool &generateDocbook = Config_getBool(GENERATE_DOCBOOK);
11201   if (generateDocbook)
11202     docbookOutput = createOutputDirectory(outputDirectory,Config_getString(DOCBOOK_OUTPUT),"/docbook");
11203
11204   QCString xmlOutput;
11205   bool &generateXml = Config_getBool(GENERATE_XML);
11206   if (generateXml)
11207     xmlOutput = createOutputDirectory(outputDirectory,Config_getString(XML_OUTPUT),"/xml");
11208
11209   QCString latexOutput;
11210   bool &generateLatex = Config_getBool(GENERATE_LATEX);
11211   if (generateLatex)
11212     latexOutput = createOutputDirectory(outputDirectory,Config_getString(LATEX_OUTPUT),"/latex");
11213
11214   QCString rtfOutput;
11215   bool &generateRtf = Config_getBool(GENERATE_RTF);
11216   if (generateRtf)
11217     rtfOutput = createOutputDirectory(outputDirectory,Config_getString(RTF_OUTPUT),"/rtf");
11218
11219   QCString manOutput;
11220   bool &generateMan = Config_getBool(GENERATE_MAN);
11221   if (generateMan)
11222     manOutput = createOutputDirectory(outputDirectory,Config_getString(MAN_OUTPUT),"/man");
11223
11224   //QCString sqlOutput;
11225   //bool &generateSql = Config_getBool(GENERATE_SQLITE3);
11226   //if (generateSql)
11227   //  sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3");
11228
11229   if (Config_getBool(HAVE_DOT))
11230   {
11231     QCString curFontPath = Config_getString(DOT_FONTPATH);
11232     if (curFontPath.isEmpty())
11233     {
11234       portable_getenv("DOTFONTPATH");
11235       QCString newFontPath = ".";
11236       if (!curFontPath.isEmpty())
11237       {
11238         newFontPath+=portable_pathListSeparator();
11239         newFontPath+=curFontPath;
11240       }
11241       portable_setenv("DOTFONTPATH",newFontPath);
11242     }
11243     else
11244     {
11245       portable_setenv("DOTFONTPATH",curFontPath);
11246     }
11247   }
11248
11249
11250
11251   /**************************************************************************
11252    *             Handle layout file                                         *
11253    **************************************************************************/
11254
11255   LayoutDocManager::instance().init();
11256   QCString &layoutFileName = Config_getString(LAYOUT_FILE);
11257   bool defaultLayoutUsed = FALSE;
11258   if (layoutFileName.isEmpty())
11259   {
11260     layoutFileName = "DoxygenLayout.xml";
11261     defaultLayoutUsed = TRUE;
11262   }
11263
11264   QFile layoutFile(layoutFileName);
11265   if (layoutFile.open(IO_ReadOnly))
11266   {
11267     msg("Parsing layout file %s...\n",layoutFileName.data());
11268     QTextStream t(&layoutFile);
11269     t.setEncoding(QTextStream::Latin1);
11270     LayoutDocManager::instance().parse(t,layoutFileName);
11271   }
11272   else if (!defaultLayoutUsed)
11273   {
11274     warn_uncond("failed to open layout file '%s' for reading!\n",layoutFileName.data());
11275   }
11276
11277   /**************************************************************************
11278    *             Read and preprocess input                                  *
11279    **************************************************************************/
11280
11281   // prevent search in the output directories
11282   QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
11283   if (generateHtml)    exclPatterns.append(htmlOutput);
11284   if (generateDocbook) exclPatterns.append(docbookOutput);
11285   if (generateXml)     exclPatterns.append(xmlOutput);
11286   if (generateLatex)   exclPatterns.append(latexOutput);
11287   if (generateRtf)     exclPatterns.append(rtfOutput);
11288   if (generateMan)     exclPatterns.append(manOutput);
11289
11290   searchInputFiles();
11291
11292   // Notice: the order of the function calls below is very important!
11293
11294   if (Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX))
11295   {
11296     readFormulaRepository(Config_getString(HTML_OUTPUT));
11297   }
11298   if (Config_getBool(GENERATE_RTF))
11299   {
11300     // in case GENERRATE_HTML is set we just have to compare, both repositories should be identical
11301     readFormulaRepository(Config_getString(RTF_OUTPUT),Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX));
11302   }
11303   if (Config_getBool(GENERATE_DOCBOOK))
11304   {
11305     // in case GENERRATE_HTML is set we just have to compare, both repositories should be identical
11306     readFormulaRepository(Config_getString(DOCBOOK_OUTPUT),
11307                          (Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX)) || Config_getBool(GENERATE_RTF));
11308   }
11309
11310   /**************************************************************************
11311    *             Handle Tag Files                                           *
11312    **************************************************************************/
11313
11314   g_storage = new FileStorage;
11315   g_storage->setName(Doxygen::entryDBFileName);
11316   if (!g_storage->open(IO_WriteOnly))
11317   {
11318     err("Failed to create temporary storage file %s\n",
11319         Doxygen::entryDBFileName.data());
11320     exit(1);
11321   }
11322   Entry *root=new Entry;
11323   EntryNav *rootNav = new EntryNav(0,root);
11324   rootNav->setEntry(root);
11325   msg("Reading and parsing tag files\n");
11326
11327   QStrList &tagFileList = Config_getList(TAGFILES);
11328   char *s=tagFileList.first();
11329   while (s)
11330   {
11331     readTagFile(root,s);
11332     root->createNavigationIndex(rootNav,g_storage,0);
11333     s=tagFileList.next();
11334   }
11335
11336   /**************************************************************************
11337    *             Parse source files                                         *
11338    **************************************************************************/
11339
11340   if (Config_getBool(BUILTIN_STL_SUPPORT))
11341   {
11342     addSTLClasses(rootNav);
11343   }
11344
11345   g_s.begin("Parsing files\n");
11346   parseFiles(root,rootNav);
11347   g_storage->close();
11348   g_s.end();
11349
11350   // we are done with input scanning now, so free up the buffers used by flex
11351   // (can be around 4MB)
11352   preFreeScanner();
11353   scanFreeScanner();
11354   pyscanFreeScanner();
11355
11356   if (!g_storage->open(IO_ReadOnly))
11357   {
11358     err("Failed to open temporary storage file %s for reading",
11359         Doxygen::entryDBFileName.data());
11360     exit(1);
11361   }
11362
11363   /**************************************************************************
11364    *             Gather information                                         *
11365    **************************************************************************/
11366
11367   g_s.begin("Building group list...\n");
11368   buildGroupList(rootNav);
11369   organizeSubGroups(rootNav);
11370   g_s.end();
11371
11372   g_s.begin("Building directory list...\n");
11373   buildDirectories();
11374   findDirDocumentation(rootNav);
11375   g_s.end();
11376
11377   g_s.begin("Building namespace list...\n");
11378   buildNamespaceList(rootNav);
11379   findUsingDirectives(rootNav);
11380   g_s.end();
11381
11382   g_s.begin("Building file list...\n");
11383   buildFileList(rootNav);
11384   g_s.end();
11385   //generateFileTree();
11386
11387   g_s.begin("Building class list...\n");
11388   buildClassList(rootNav);
11389   g_s.end();
11390
11391   g_s.begin("Associating documentation with classes...\n");
11392   buildClassDocList(rootNav);
11393
11394   // build list of using declarations here (global list)
11395   buildListOfUsingDecls(rootNav);
11396   g_s.end();
11397
11398   g_s.begin("Computing nesting relations for classes...\n");
11399   resolveClassNestingRelations();
11400   g_s.end();
11401   // 1.8.2-20121111: no longer add nested classes to the group as well
11402   //distributeClassGroupRelations();
11403
11404   // calling buildClassList may result in cached relations that
11405   // become invalid after resolveClassNestingRelations(), that's why
11406   // we need to clear the cache here
11407   Doxygen::lookupCache->clear();
11408   // we don't need the list of using declaration anymore
11409   g_usingDeclarations.clear();
11410
11411   g_s.begin("Building example list...\n");
11412   buildExampleList(rootNav);
11413   g_s.end();
11414
11415   g_s.begin("Searching for enumerations...\n");
11416   findEnums(rootNav);
11417   g_s.end();
11418
11419   // Since buildVarList calls isVarWithConstructor
11420   // and this calls getResolvedClass we need to process
11421   // typedefs first so the relations between classes via typedefs
11422   // are properly resolved. See bug 536385 for an example.
11423   g_s.begin("Searching for documented typedefs...\n");
11424   buildTypedefList(rootNav);
11425   g_s.end();
11426
11427   if (Config_getBool(OPTIMIZE_OUTPUT_SLICE))
11428   {
11429     g_s.begin("Searching for documented sequences...\n");
11430     buildSequenceList(rootNav);
11431     g_s.end();
11432
11433     g_s.begin("Searching for documented dictionaries...\n");
11434     buildDictionaryList(rootNav);
11435     g_s.end();
11436   }
11437
11438   g_s.begin("Searching for members imported via using declarations...\n");
11439   // this should be after buildTypedefList in order to properly import
11440   // used typedefs
11441   findUsingDeclarations(rootNav);
11442   g_s.end();
11443
11444   g_s.begin("Searching for included using directives...\n");
11445   findIncludedUsingDirectives();
11446   g_s.end();
11447
11448   g_s.begin("Searching for documented variables...\n");
11449   buildVarList(rootNav);
11450   g_s.end();
11451
11452   g_s.begin("Building interface member list...\n");
11453   buildInterfaceAndServiceList(rootNav); // UNO IDL
11454
11455   g_s.begin("Building member list...\n"); // using class info only !
11456   buildFunctionList(rootNav);
11457   g_s.end();
11458
11459   g_s.begin("Searching for friends...\n");
11460   findFriends();
11461   g_s.end();
11462
11463   g_s.begin("Searching for documented defines...\n");
11464   findDefineDocumentation(rootNav);
11465   g_s.end();
11466
11467   g_s.begin("Computing class inheritance relations...\n");
11468   findClassEntries(rootNav);
11469   findInheritedTemplateInstances();
11470   g_s.end();
11471
11472   g_s.begin("Computing class usage relations...\n");
11473   findUsedTemplateInstances();
11474   g_s.end();
11475
11476   if (Config_getBool(INLINE_SIMPLE_STRUCTS))
11477   {
11478     g_s.begin("Searching for tag less structs...\n");
11479     findTagLessClasses();
11480     g_s.end();
11481   }
11482
11483   g_s.begin("Flushing cached template relations that have become invalid...\n");
11484   flushCachedTemplateRelations();
11485   g_s.end();
11486
11487   g_s.begin("Computing class relations...\n");
11488   computeTemplateClassRelations();
11489   flushUnresolvedRelations();
11490   if (Config_getBool(OPTIMIZE_OUTPUT_VHDL))
11491   {
11492     VhdlDocGen::computeVhdlComponentRelations();
11493   }
11494   computeClassRelations();
11495   g_classEntries.clear();
11496   g_s.end();
11497
11498   g_s.begin("Add enum values to enums...\n");
11499   addEnumValuesToEnums(rootNav);
11500   findEnumDocumentation(rootNav);
11501   g_s.end();
11502
11503   g_s.begin("Searching for member function documentation...\n");
11504   findObjCMethodDefinitions(rootNav);
11505   findMemberDocumentation(rootNav); // may introduce new members !
11506   findUsingDeclImports(rootNav); // may introduce new members !
11507
11508   transferRelatedFunctionDocumentation();
11509   transferFunctionDocumentation();
11510   g_s.end();
11511
11512   // moved to after finding and copying documentation,
11513   // as this introduces new members see bug 722654
11514   g_s.begin("Creating members for template instances...\n");
11515   createTemplateInstanceMembers();
11516   g_s.end();
11517
11518   g_s.begin("Building page list...\n");
11519   buildPageList(rootNav);
11520   g_s.end();
11521
11522   g_s.begin("Search for main page...\n");
11523   findMainPage(rootNav);
11524   findMainPageTagFiles(rootNav);
11525   g_s.end();
11526
11527   g_s.begin("Computing page relations...\n");
11528   computePageRelations(rootNav);
11529   checkPageRelations();
11530   g_s.end();
11531
11532   g_s.begin("Determining the scope of groups...\n");
11533   findGroupScope(rootNav);
11534   g_s.end();
11535
11536   g_s.begin("Sorting lists...\n");
11537   Doxygen::memberNameSDict->sort();
11538   Doxygen::functionNameSDict->sort();
11539   Doxygen::hiddenClasses->sort();
11540   Doxygen::classSDict->sort();
11541   g_s.end();
11542
11543   msg("Freeing entry tree\n");
11544   delete rootNav;
11545   g_storage->close();
11546   delete g_storage;
11547   g_storage=0;
11548
11549   QDir thisDir;
11550   thisDir.remove(Doxygen::entryDBFileName);
11551
11552   g_s.begin("Determining which enums are documented\n");
11553   findDocumentedEnumValues();
11554   g_s.end();
11555
11556   g_s.begin("Computing member relations...\n");
11557   mergeCategories();
11558   computeMemberRelations();
11559   g_s.end();
11560
11561   g_s.begin("Building full member lists recursively...\n");
11562   buildCompleteMemberLists();
11563   g_s.end();
11564
11565   g_s.begin("Adding members to member groups.\n");
11566   addMembersToMemberGroup();
11567   g_s.end();
11568
11569   if (Config_getBool(DISTRIBUTE_GROUP_DOC))
11570   {
11571     g_s.begin("Distributing member group documentation.\n");
11572     distributeMemberGroupDocumentation();
11573     g_s.end();
11574   }
11575
11576   g_s.begin("Computing member references...\n");
11577   computeMemberReferences();
11578   g_s.end();
11579
11580   if (Config_getBool(INHERIT_DOCS))
11581   {
11582     g_s.begin("Inheriting documentation...\n");
11583     inheritDocumentation();
11584     g_s.end();
11585   }
11586
11587   // compute the shortest possible names of all files
11588   // without losing the uniqueness of the file names.
11589   g_s.begin("Generating disk names...\n");
11590   Doxygen::inputNameList->generateDiskNames();
11591   g_s.end();
11592
11593   g_s.begin("Adding source references...\n");
11594   addSourceReferences();
11595   g_s.end();
11596
11597   g_s.begin("Adding xrefitems...\n");
11598   addListReferences();
11599   generateXRefPages();
11600   g_s.end();
11601
11602   g_s.begin("Sorting member lists...\n");
11603   sortMemberLists();
11604   g_s.end();
11605
11606   if (Config_getBool(DIRECTORY_GRAPH))
11607   {
11608     g_s.begin("Computing dependencies between directories...\n");
11609     computeDirDependencies();
11610     g_s.end();
11611   }
11612
11613   //g_s.begin("Resolving citations...\n");
11614   //Doxygen::citeDict->resolve();
11615
11616   g_s.begin("Generating citations page...\n");
11617   Doxygen::citeDict->generatePage();
11618   g_s.end();
11619
11620   g_s.begin("Counting data structures...\n");
11621   countDataStructures();
11622   g_s.end();
11623
11624   g_s.begin("Resolving user defined references...\n");
11625   resolveUserReferences();
11626   g_s.end();
11627
11628   g_s.begin("Finding anchors and sections in the documentation...\n");
11629   findSectionsInDocumentation();
11630   g_s.end();
11631
11632   g_s.begin("Transferring function references...\n");
11633   transferFunctionReferences();
11634   g_s.end();
11635
11636   g_s.begin("Combining using relations...\n");
11637   combineUsingRelations();
11638   g_s.end();
11639
11640   g_s.begin("Adding members to index pages...\n");
11641   addMembersToIndex();
11642   g_s.end();
11643 }
11644
11645 void generateOutput()
11646 {
11647   /**************************************************************************
11648    *            Initialize output generators                                *
11649    **************************************************************************/
11650
11651   /// add extra languages for which we can only produce syntax highlighted code
11652   addCodeOnlyMappings();
11653
11654   //// dump all symbols
11655   if (g_dumpSymbolMap)
11656   {
11657     dumpSymbolMap();
11658     exit(0);
11659   }
11660
11661   initSearchIndexer();
11662
11663   bool generateHtml  = Config_getBool(GENERATE_HTML);
11664   bool generateLatex = Config_getBool(GENERATE_LATEX);
11665   bool generateMan   = Config_getBool(GENERATE_MAN);
11666   bool generateRtf   = Config_getBool(GENERATE_RTF);
11667   bool generateDocbook = Config_getBool(GENERATE_DOCBOOK);
11668
11669
11670   g_outputList = new OutputList(TRUE);
11671   if (generateHtml)
11672   {
11673     g_outputList->add(new HtmlGenerator);
11674     HtmlGenerator::init();
11675
11676     // add HTML indexers that are enabled
11677     bool generateHtmlHelp    = Config_getBool(GENERATE_HTMLHELP);
11678     bool generateEclipseHelp = Config_getBool(GENERATE_ECLIPSEHELP);
11679     bool generateQhp         = Config_getBool(GENERATE_QHP);
11680     bool generateTreeView    = Config_getBool(GENERATE_TREEVIEW);
11681     bool generateDocSet      = Config_getBool(GENERATE_DOCSET);
11682     if (generateEclipseHelp) Doxygen::indexList->addIndex(new EclipseHelp);
11683     if (generateHtmlHelp)    Doxygen::indexList->addIndex(new HtmlHelp);
11684     if (generateQhp)         Doxygen::indexList->addIndex(new Qhp);
11685     if (generateTreeView)    Doxygen::indexList->addIndex(new FTVHelp(TRUE));
11686     if (generateDocSet)      Doxygen::indexList->addIndex(new DocSets);
11687     Doxygen::indexList->initialize();
11688     HtmlGenerator::writeTabData();
11689   }
11690   if (generateLatex)
11691   {
11692     g_outputList->add(new LatexGenerator);
11693     LatexGenerator::init();
11694   }
11695   if (generateDocbook)
11696   {
11697     g_outputList->add(new DocbookGenerator);
11698     DocbookGenerator::init();
11699   }
11700   if (generateMan)
11701   {
11702     g_outputList->add(new ManGenerator);
11703     ManGenerator::init();
11704   }
11705   if (generateRtf)
11706   {
11707     g_outputList->add(new RTFGenerator);
11708     RTFGenerator::init();
11709   }
11710   if (Config_getBool(USE_HTAGS))
11711   {
11712     Htags::useHtags = TRUE;
11713     QCString htmldir = Config_getString(HTML_OUTPUT);
11714     if (!Htags::execute(htmldir))
11715        err("USE_HTAGS is YES but htags(1) failed. \n");
11716     if (!Htags::loadFilemap(htmldir))
11717        err("htags(1) ended normally but failed to load the filemap. \n");
11718   }
11719
11720   /**************************************************************************
11721    *                        Generate documentation                          *
11722    **************************************************************************/
11723
11724   if (generateHtml)  writeDoxFont(Config_getString(HTML_OUTPUT));
11725   if (generateLatex) writeDoxFont(Config_getString(LATEX_OUTPUT));
11726   if (generateDocbook) writeDoxFont(Config_getString(DOCBOOK_OUTPUT));
11727   if (generateRtf)   writeDoxFont(Config_getString(RTF_OUTPUT));
11728
11729   g_s.begin("Generating style sheet...\n");
11730   //printf("writing style info\n");
11731   g_outputList->writeStyleInfo(0); // write first part
11732   g_s.end();
11733
11734   static bool searchEngine      = Config_getBool(SEARCHENGINE);
11735   static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
11736
11737   g_s.begin("Generating search indices...\n");
11738   if (searchEngine && !serverBasedSearch && (generateHtml || g_useOutputTemplate))
11739   {
11740     createJavascriptSearchIndex();
11741   }
11742
11743   // generate search indices (need to do this before writing other HTML
11744   // pages as these contain a drop down menu with options depending on
11745   // what categories we find in this function.
11746   if (generateHtml && searchEngine)
11747   {
11748     QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search";
11749     QDir searchDir(searchDirName);
11750     if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
11751     {
11752       err("Could not create search results directory '%s' $PWD='%s'\n",
11753           searchDirName.data(),QDir::currentDirPath().data());
11754       exit(1);
11755     }
11756     HtmlGenerator::writeSearchData(searchDirName);
11757     if (!serverBasedSearch) // client side search index
11758     {
11759       writeJavascriptSearchIndex();
11760     }
11761   }
11762   g_s.end();
11763
11764   g_s.begin("Generating example documentation...\n");
11765   generateExampleDocs();
11766   g_s.end();
11767
11768   if (!Htags::useHtags)
11769   {
11770     g_s.begin("Generating file sources...\n");
11771     generateFileSources();
11772     g_s.end();
11773   }
11774
11775   g_s.begin("Generating file documentation...\n");
11776   generateFileDocs();
11777   g_s.end();
11778
11779   g_s.begin("Generating page documentation...\n");
11780   generatePageDocs();
11781   g_s.end();
11782
11783   g_s.begin("Generating group documentation...\n");
11784   generateGroupDocs();
11785   g_s.end();
11786
11787   g_s.begin("Generating class documentation...\n");
11788   generateClassDocs();
11789   g_s.end();
11790
11791   g_s.begin("Generating namespace index...\n");
11792   generateNamespaceDocs();
11793   g_s.end();
11794
11795   if (Config_getBool(GENERATE_LEGEND))
11796   {
11797     g_s.begin("Generating graph info page...\n");
11798     writeGraphInfo(*g_outputList);
11799     g_s.end();
11800   }
11801
11802   g_s.begin("Generating directory documentation...\n");
11803   generateDirDocs(*g_outputList);
11804   g_s.end();
11805
11806   if (Doxygen::formulaList->count()>0 && generateHtml
11807       && !Config_getBool(USE_MATHJAX))
11808   {
11809     g_s.begin("Generating bitmaps for formulas in HTML...\n");
11810     Doxygen::formulaList->generateBitmaps(Config_getString(HTML_OUTPUT));
11811     g_s.end();
11812   }
11813   if (Doxygen::formulaList->count()>0 && generateRtf)
11814   {
11815     g_s.begin("Generating bitmaps for formulas in RTF...\n");
11816     Doxygen::formulaList->generateBitmaps(Config_getString(RTF_OUTPUT));
11817     g_s.end();
11818   }
11819
11820   if (Doxygen::formulaList->count()>0 && generateDocbook)
11821   {
11822     g_s.begin("Generating bitmaps for formulas in Docbook...\n");
11823     Doxygen::formulaList->generateBitmaps(Config_getString(DOCBOOK_OUTPUT));
11824     g_s.end();
11825   }
11826
11827   if (Config_getBool(SORT_GROUP_NAMES))
11828   {
11829     Doxygen::groupSDict->sort();
11830     GroupSDict::Iterator gli(*Doxygen::groupSDict);
11831     GroupDef *gd;
11832     for (gli.toFirst();(gd=gli.current());++gli)
11833     {
11834       gd->sortSubGroups();
11835     }
11836   }
11837
11838   if (g_outputList->count()>0)
11839   {
11840     writeIndexHierarchy(*g_outputList);
11841   }
11842
11843   g_s.begin("finalizing index lists...\n");
11844   Doxygen::indexList->finalize();
11845   g_s.end();
11846
11847   g_s.begin("writing tag file...\n");
11848   writeTagFile();
11849   g_s.end();
11850
11851   if (Config_getBool(DOT_CLEANUP))
11852   {
11853     if (generateHtml)
11854       removeDoxFont(Config_getString(HTML_OUTPUT));
11855     if (generateRtf)
11856       removeDoxFont(Config_getString(RTF_OUTPUT));
11857     if (generateLatex)
11858       removeDoxFont(Config_getString(LATEX_OUTPUT));
11859     if (generateDocbook)
11860       removeDoxFont(Config_getString(DOCBOOK_OUTPUT));
11861   }
11862
11863   if (Config_getBool(GENERATE_XML))
11864   {
11865     g_s.begin("Generating XML output...\n");
11866     Doxygen::generatingXmlOutput=TRUE;
11867     generateXML();
11868     Doxygen::generatingXmlOutput=FALSE;
11869     g_s.end();
11870   }
11871   if (USE_SQLITE3)
11872   {
11873     g_s.begin("Generating SQLITE3 output...\n");
11874     generateSqlite3();
11875     g_s.end();
11876   }
11877
11878   if (Config_getBool(GENERATE_AUTOGEN_DEF))
11879   {
11880     g_s.begin("Generating AutoGen DEF output...\n");
11881     generateDEF();
11882     g_s.end();
11883   }
11884   if (Config_getBool(GENERATE_PERLMOD))
11885   {
11886     g_s.begin("Generating Perl module output...\n");
11887     generatePerlMod();
11888     g_s.end();
11889   }
11890   if (generateHtml && searchEngine && serverBasedSearch)
11891   {
11892     g_s.begin("Generating search index\n");
11893     if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
11894     {
11895       HtmlGenerator::writeSearchPage();
11896       Doxygen::searchIndex->write(Config_getString(HTML_OUTPUT)+"/search/search.idx");
11897     }
11898     else // write data for external search index
11899     {
11900       HtmlGenerator::writeExternalSearchPage();
11901       QCString searchDataFile = Config_getString(SEARCHDATA_FILE);
11902       if (searchDataFile.isEmpty())
11903       {
11904         searchDataFile="searchdata.xml";
11905       }
11906       if (!portable_isAbsolutePath(searchDataFile))
11907       {
11908         searchDataFile.prepend(Config_getString(OUTPUT_DIRECTORY)+"/");
11909       }
11910       Doxygen::searchIndex->write(searchDataFile);
11911     }
11912     g_s.end();
11913   }
11914
11915   if (g_useOutputTemplate) generateOutputViaTemplate();
11916
11917   if (generateRtf)
11918   {
11919     g_s.begin("Combining RTF output...\n");
11920     if (!RTFGenerator::preProcessFileInplace(Config_getString(RTF_OUTPUT),"refman.rtf"))
11921     {
11922       err("An error occurred during post-processing the RTF files!\n");
11923     }
11924     g_s.end();
11925   }
11926
11927   if (Config_getBool(HAVE_DOT))
11928   {
11929     g_s.begin("Running dot...\n");
11930     DotManager::instance()->run();
11931     g_s.end();
11932   }
11933
11934   // copy static stuff
11935   if (generateHtml)
11936   {
11937     FTVHelp::generateTreeViewImages();
11938     copyStyleSheet();
11939     copyLogo(Config_getString(HTML_OUTPUT));
11940     copyExtraFiles(Config_getList(HTML_EXTRA_FILES),"HTML_EXTRA_FILES",Config_getString(HTML_OUTPUT));
11941   }
11942   if (generateLatex)
11943   {
11944     copyLatexStyleSheet();
11945     copyLogo(Config_getString(LATEX_OUTPUT));
11946     copyExtraFiles(Config_getList(LATEX_EXTRA_FILES),"LATEX_EXTRA_FILES",Config_getString(LATEX_OUTPUT));
11947   }
11948   if (generateDocbook)
11949   {
11950     copyLogo(Config_getString(DOCBOOK_OUTPUT));
11951   }
11952   if (generateRtf)
11953   {
11954     copyLogo(Config_getString(RTF_OUTPUT));
11955   }
11956
11957   if (generateHtml &&
11958       Config_getBool(GENERATE_HTMLHELP) &&
11959       !Config_getString(HHC_LOCATION).isEmpty())
11960   {
11961     g_s.begin("Running html help compiler...\n");
11962     QString oldDir = QDir::currentDirPath();
11963     QDir::setCurrent(Config_getString(HTML_OUTPUT));
11964     portable_sysTimerStart();
11965     if (portable_system(Config_getString(HHC_LOCATION), "index.hhp", Debug::isFlagSet(Debug::ExtCmd))!=1)
11966     {
11967       err("failed to run html help compiler on index.hhp\n");
11968     }
11969     portable_sysTimerStop();
11970     QDir::setCurrent(oldDir);
11971     g_s.end();
11972   }
11973   if ( generateHtml &&
11974        Config_getBool(GENERATE_QHP) &&
11975       !Config_getString(QHG_LOCATION).isEmpty())
11976   {
11977     g_s.begin("Running qhelpgenerator...\n");
11978     QCString const qhpFileName = Qhp::getQhpFileName();
11979     QCString const qchFileName = getQchFileName();
11980
11981     QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
11982     QString const oldDir = QDir::currentDirPath();
11983     QDir::setCurrent(Config_getString(HTML_OUTPUT));
11984     portable_sysTimerStart();
11985     if (portable_system(Config_getString(QHG_LOCATION), args.data(), FALSE))
11986     {
11987       err("failed to run qhelpgenerator on index.qhp\n");
11988     }
11989     portable_sysTimerStop();
11990     QDir::setCurrent(oldDir);
11991     g_s.end();
11992   }
11993
11994   int cacheParam;
11995   msg("lookup cache used %d/%d hits=%d misses=%d\n",
11996       Doxygen::lookupCache->count(),
11997       Doxygen::lookupCache->size(),
11998       Doxygen::lookupCache->hits(),
11999       Doxygen::lookupCache->misses());
12000   cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
12001   if (cacheParam>Config_getInt(LOOKUP_CACHE_SIZE))
12002   {
12003     msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
12004   }
12005
12006   if (Debug::isFlagSet(Debug::Time))
12007   {
12008     msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
12009          ((double)Doxygen::runningTime.elapsed())/1000.0,
12010          portable_getSysElapsedTime()
12011         );
12012     g_s.print();
12013   }
12014   else
12015   {
12016     msg("finished...\n");
12017   }
12018
12019
12020   /**************************************************************************
12021    *                        Start cleaning up                               *
12022    **************************************************************************/
12023
12024   cleanUpDoxygen();
12025
12026   finializeSearchIndexer();
12027   Doxygen::symbolStorage->close();
12028   QDir thisDir;
12029   thisDir.remove(Doxygen::objDBFileName);
12030   thisDir.remove(Doxygen::filterDBFileName);
12031   Config::deinit();
12032   QTextCodec::deleteAllCodecs();
12033   delete Doxygen::symbolMap;
12034   delete Doxygen::clangUsrMap;
12035   delete Doxygen::symbolStorage;
12036   g_successfulRun=TRUE;
12037 }
12038