00826d62cc24f6cad160b19758748f26e0b3781a
[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 #include <locale.h>
17
18 #include <qfileinfo.h>
19 #include <qfile.h>
20 #include <qdir.h>
21 #include <qdict.h>
22 #include <qregexp.h>
23 #include <qstrlist.h>
24 #include <stdio.h>
25 #include <stdlib.h>
26 #include <sys/stat.h>
27 #include <qtextcodec.h>
28 #include <errno.h>
29 #include <qptrdict.h>
30 #include <qtextstream.h>
31
32 #include "version.h"
33 #include "doxygen.h"
34 #include "scanner.h"
35 #include "entry.h"
36 #include "index.h"
37 #include "logos.h"
38 #include "message.h"
39 #include "config.h"
40 #include "util.h"
41 #include "pre.h"
42 #include "tagreader.h"
43 #include "dot.h"
44 #include "msc.h"
45 #include "docparser.h"
46 #include "dirdef.h"
47 #include "outputlist.h"
48 #include "declinfo.h"
49 #include "htmlgen.h"
50 #include "latexgen.h"
51 #include "mangen.h"
52 #include "language.h"
53 #include "debug.h"
54 #include "htmlhelp.h"
55 #include "qhp.h"
56 #include "ftvhelp.h"
57 #include "defargs.h"
58 #include "rtfgen.h"
59 #include "sqlite3gen.h"
60 #include "xmlgen.h"
61 #include "docbookgen.h"
62 #include "defgen.h"
63 #include "perlmodgen.h"
64 #include "reflist.h"
65 #include "pagedef.h"
66 #include "bufstr.h"
67 #include "commentcnv.h"
68 #include "cmdmapper.h"
69 #include "searchindex.h"
70 #include "parserintf.h"
71 #include "htags.h"
72 #include "pyscanner.h"
73 #include "fortranscanner.h"
74 #include "xmlscanner.h"
75 #include "sqlscanner.h"
76 #include "tclscanner.h"
77 #include "code.h"
78 #include "objcache.h"
79 #include "store.h"
80 #include "marshal.h"
81 #include "portable.h"
82 #include "vhdljjparser.h"
83 #include "vhdldocgen.h"
84 #include "eclipsehelp.h"
85 #include "cite.h"
86 #include "filestorage.h"
87 #include "markdown.h"
88 #include "arguments.h"
89 #include "memberlist.h"
90 #include "layout.h"
91 #include "groupdef.h"
92 #include "classlist.h"
93 #include "namespacedef.h"
94 #include "filename.h"
95 #include "membername.h"
96 #include "membergroup.h"
97 #include "docsets.h"
98 #include "formula.h"
99 #include "settings.h"
100 #include "context.h"
101 #include "fileparser.h"
102
103 // provided by the generated file resources.cpp
104 extern void initResources();
105
106 #define RECURSE_ENTRYTREE(func,var) \
107   do { if (var->children()) { \
108     EntryNavListIterator eli(*var->children()); \
109     for (;eli.current();++eli) func(eli.current()); \
110   } } while(0)
111
112
113 #if !defined(_WIN32) || defined(__CYGWIN__)
114 #include <signal.h>
115 #define HAS_SIGNALS
116 #endif
117
118 // globally accessible variables
119 ClassSDict      *Doxygen::classSDict = 0;
120 ClassSDict      *Doxygen::hiddenClasses = 0;
121 NamespaceSDict  *Doxygen::namespaceSDict = 0;
122 MemberNameSDict *Doxygen::memberNameSDict = 0;
123 MemberNameSDict *Doxygen::functionNameSDict = 0;
124 FileNameList    *Doxygen::inputNameList = 0;       // all input files
125 FileNameDict    *Doxygen::inputNameDict = 0;
126 GroupSDict      *Doxygen::groupSDict = 0;
127 FormulaList     *Doxygen::formulaList = 0;       // all formulas
128 FormulaDict     *Doxygen::formulaDict = 0;       // all formulas
129 FormulaDict     *Doxygen::formulaNameDict = 0;   // the label name of all formulas
130 PageSDict       *Doxygen::pageSDict = 0;
131 PageSDict       *Doxygen::exampleSDict = 0;
132 SectionDict     *Doxygen::sectionDict = 0;        // all page sections
133 CiteDict        *Doxygen::citeDict=0;              // database of bibliographic references
134 StringDict       Doxygen::aliasDict(257);          // aliases
135 QDict<void>      Doxygen::inputPaths(1009);
136 FileNameDict    *Doxygen::includeNameDict = 0;     // include names
137 FileNameDict    *Doxygen::exampleNameDict = 0;     // examples
138 FileNameDict    *Doxygen::imageNameDict = 0;       // images
139 FileNameDict    *Doxygen::dotFileNameDict = 0;     // dot files
140 FileNameDict    *Doxygen::mscFileNameDict = 0;     // msc files
141 FileNameDict    *Doxygen::diaFileNameDict = 0;     // dia files
142 StringDict       Doxygen::namespaceAliasDict(257); // all namespace aliases
143 StringDict       Doxygen::tagDestinationDict(257); // all tag locations
144 QDict<void>      Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
145 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
146 PageDef         *Doxygen::mainPage = 0;
147 bool             Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
148 NamespaceDef    *Doxygen::globalScope = 0;
149 QDict<RefList>  *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
150 bool             Doxygen::parseSourcesNeeded = FALSE;
151 QTime            Doxygen::runningTime;
152 SearchIndexIntf *Doxygen::searchIndex=0;
153 QDict<DefinitionIntf> *Doxygen::symbolMap = 0;
154 QDict<Definition> *Doxygen::clangUsrMap = 0;
155 bool             Doxygen::outputToWizard=FALSE;
156 QDict<int> *     Doxygen::htmlDirMap = 0;
157 QCache<LookupInfo> *Doxygen::lookupCache;
158 DirSDict        *Doxygen::directories;
159 SDict<DirRelation> Doxygen::dirRelations(257);
160 ParserManager   *Doxygen::parserManager = 0;
161 QCString Doxygen::htmlFileExtension;
162 bool             Doxygen::suppressDocWarnings = FALSE;
163 Store           *Doxygen::symbolStorage;
164 QCString         Doxygen::objDBFileName;
165 QCString         Doxygen::entryDBFileName;
166 bool             Doxygen::gatherDefines = TRUE;
167 IndexList       *Doxygen::indexList;
168 int              Doxygen::subpageNestingLevel = 0;
169 bool             Doxygen::userComments = FALSE;
170 QCString         Doxygen::spaces;
171 bool             Doxygen::generatingXmlOutput = FALSE;
172 bool             Doxygen::markdownSupport = TRUE;
173 GenericsSDict   *Doxygen::genericsDict;
174
175 // locally accessible globals
176 static QDict<EntryNav>  g_classEntries(1009);
177 static StringList       g_inputFiles;
178 static QDict<void>      g_compoundKeywordDict(7);  // keywords recognised as compounds
179 static OutputList      *g_outputList = 0;          // list of output generating objects
180 static QDict<FileDef>   g_usingDeclarations(1009); // used classes
181 static FileStorage     *g_storage = 0;
182 static bool             g_successfulRun = FALSE;
183 static bool             g_dumpSymbolMap = FALSE;
184 static bool             g_useOutputTemplate = FALSE;
185
186 void clearAll()
187 {
188   g_inputFiles.clear();
189   //g_excludeNameDict.clear();
190   //delete g_outputList; g_outputList=0;
191
192   Doxygen::classSDict->clear();
193   Doxygen::namespaceSDict->clear();
194   Doxygen::pageSDict->clear();
195   Doxygen::exampleSDict->clear();
196   Doxygen::inputNameList->clear();
197   Doxygen::formulaList->clear();
198   Doxygen::sectionDict->clear();
199   Doxygen::inputNameDict->clear();
200   Doxygen::includeNameDict->clear();
201   Doxygen::exampleNameDict->clear();
202   Doxygen::imageNameDict->clear();
203   Doxygen::dotFileNameDict->clear();
204   Doxygen::mscFileNameDict->clear();
205   Doxygen::diaFileNameDict->clear();
206   Doxygen::formulaDict->clear();
207   Doxygen::formulaNameDict->clear();
208   Doxygen::tagDestinationDict.clear();
209   delete Doxygen::citeDict;
210   delete Doxygen::mainPage; Doxygen::mainPage=0;
211 }
212
213 class Statistics
214 {
215   public:
216     Statistics() { stats.setAutoDelete(TRUE); }
217     void begin(const char *name)
218     {
219       msg(name);
220       stat *entry= new stat(name,0);
221       stats.append(entry);
222       time.restart();
223     }
224     void end()
225     {
226       stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
227     }
228     void print()
229     {
230       bool restore=FALSE;
231       if (Debug::isFlagSet(Debug::Time))
232       {
233         Debug::clearFlag("time");
234         restore=TRUE;
235       }
236       msg("----------------------\n");
237       QListIterator<stat> sli(stats);
238       stat *s;
239       for ( sli.toFirst(); (s=sli.current()); ++sli )
240       {
241         msg("Spent %.3f seconds in %s",s->elapsed,s->name);
242       }
243       if (restore) Debug::setFlag("time");
244     }
245   private:
246     struct stat
247     {
248       const char *name;
249       double elapsed;
250       stat() : name(NULL),elapsed(0) {}
251       stat(const char *n, double el) : name(n),elapsed(el) {}
252     };
253     QList<stat> stats;
254     QTime       time;
255 } g_s;
256
257
258 void statistics()
259 {
260   fprintf(stderr,"--- inputNameDict stats ----\n");
261   Doxygen::inputNameDict->statistics();
262   fprintf(stderr,"--- includeNameDict stats ----\n");
263   Doxygen::includeNameDict->statistics();
264   fprintf(stderr,"--- exampleNameDict stats ----\n");
265   Doxygen::exampleNameDict->statistics();
266   fprintf(stderr,"--- imageNameDict stats ----\n");
267   Doxygen::imageNameDict->statistics();
268   fprintf(stderr,"--- dotFileNameDict stats ----\n");
269   Doxygen::dotFileNameDict->statistics();
270   fprintf(stderr,"--- mscFileNameDict stats ----\n");
271   Doxygen::mscFileNameDict->statistics();
272   fprintf(stderr,"--- diaFileNameDict stats ----\n");
273   Doxygen::diaFileNameDict->statistics();
274   //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
275   //g_excludeNameDict.statistics();
276   fprintf(stderr,"--- aliasDict stats ----\n");
277   Doxygen::aliasDict.statistics();
278   fprintf(stderr,"--- typedefDict stats ----\n");
279   fprintf(stderr,"--- namespaceAliasDict stats ----\n");
280   Doxygen::namespaceAliasDict.statistics();
281   fprintf(stderr,"--- formulaDict stats ----\n");
282   Doxygen::formulaDict->statistics();
283   fprintf(stderr,"--- formulaNameDict stats ----\n");
284   Doxygen::formulaNameDict->statistics();
285   fprintf(stderr,"--- tagDestinationDict stats ----\n");
286   Doxygen::tagDestinationDict.statistics();
287   fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
288   g_compoundKeywordDict.statistics();
289   fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
290   Doxygen::expandAsDefinedDict.statistics();
291   fprintf(stderr,"--- memGrpInfoDict stats ----\n");
292   Doxygen::memGrpInfoDict.statistics();
293 }
294
295
296
297 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
298                    ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
299 static void findMember(EntryNav *rootNav,
300                        QCString funcDecl,
301                        bool overloaded,
302                        bool isFunc
303                       );
304
305 enum FindBaseClassRelation_Mode
306 {
307   TemplateInstances,
308   DocumentedOnly,
309   Undocumented
310 };
311
312 static bool findClassRelation(
313                            EntryNav *rootNav,
314                            Definition *context,
315                            ClassDef *cd,
316                            BaseInfo *bi,
317                            QDict<int> *templateNames,
318                            /*bool insertUndocumented*/
319                            FindBaseClassRelation_Mode mode,
320                            bool isArtificial
321                           );
322
323 /** A struct contained the data for an STL class */
324 struct STLInfo
325 {
326   const char *className;
327   const char *baseClass1;
328   const char *baseClass2;
329   const char *templType1;
330   const char *templName1;
331   const char *templType2;
332   const char *templName2;
333   bool virtualInheritance;
334   bool iterators;
335 };
336
337 static STLInfo g_stlinfo[] =
338 {
339   // className              baseClass1                      baseClass2             templType1     templName1     templType2    templName2     virtInheritance  // iterators
340   { "allocator",            0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
341   { "array",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE }, // C++11
342   { "auto_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // deprecated
343   { "smart_ptr",            0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
344   { "unique_ptr",           0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
345   { "weak_ptr",             0,                              0,                     "T",           "ptr",         0,            0,             FALSE,              FALSE }, // C++11
346   { "ios_base",             0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
347   { "error_code",           0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
348   { "error_category",       0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
349   { "system_error",         0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
350   { "error_condition",      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
351   { "thread",               0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }, // C++11
352   { "basic_ios",            "ios_base",                     0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
353   { "basic_istream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
354   { "basic_ostream",        "basic_ios<Char>",              0,                     "Char",        0,             0,            0,             TRUE,               FALSE },
355   { "basic_iostream",       "basic_istream<Char>",          "basic_ostream<Char>", "Char",        0,             0,            0,             FALSE,              FALSE },
356   { "basic_ifstream",       "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
357   { "basic_ofstream",       "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
358   { "basic_fstream",        "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
359   { "basic_istringstream",  "basic_istream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
360   { "basic_ostringstream",  "basic_ostream<Char>",          0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
361   { "basic_stringstream",   "basic_iostream<Char>",         0,                     "Char",        0,             0,            0,             FALSE,              FALSE },
362   { "ios",                  "basic_ios<char>",              0,                     0,             0,             0,            0,             FALSE,              FALSE },
363   { "wios",                 "basic_ios<wchar_t>",           0,                     0,             0,             0,            0,             FALSE,              FALSE },
364   { "istream",              "basic_istream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
365   { "wistream",             "basic_istream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
366   { "ostream",              "basic_ostream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
367   { "wostream",             "basic_ostream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
368   { "ifstream",             "basic_ifstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
369   { "wifstream",            "basic_ifstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
370   { "ofstream",             "basic_ofstream<char>",         0,                     0,             0,             0,            0,             FALSE,              FALSE },
371   { "wofstream",            "basic_ofstream<wchar_t>",      0,                     0,             0,             0,            0,             FALSE,              FALSE },
372   { "fstream",              "basic_fstream<char>",          0,                     0,             0,             0,            0,             FALSE,              FALSE },
373   { "wfstream",             "basic_fstream<wchar_t>",       0,                     0,             0,             0,            0,             FALSE,              FALSE },
374   { "istringstream",        "basic_istringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
375   { "wistringstream",       "basic_istringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
376   { "ostringstream",        "basic_ostringstream<char>",    0,                     0,             0,             0,            0,             FALSE,              FALSE },
377   { "wostringstream",       "basic_ostringstream<wchar_t>", 0,                     0,             0,             0,            0,             FALSE,              FALSE },
378   { "stringstream",         "basic_stringstream<char>",     0,                     0,             0,             0,            0,             FALSE,              FALSE },
379   { "wstringstream",        "basic_stringstream<wchar_t>",  0,                     0,             0,             0,            0,             FALSE,              FALSE },
380   { "basic_string",         0,                              0,                     "Char",        0,             0,            0,             FALSE,              TRUE  },
381   { "string",               "basic_string<char>",           0,                     0,             0,             0,            0,             FALSE,              TRUE  },
382   { "wstring",              "basic_string<wchar_t>",        0,                     0,             0,             0,            0,             FALSE,              TRUE  },
383   { "complex",              0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
384   { "bitset",               0,                              0,                     "Bits",        0,             0,            0,             FALSE,              FALSE },
385   { "deque",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
386   { "list",                 0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
387   { "forward_list",         0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  }, // C++11
388   { "map",                  0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
389   { "unordered_map",        0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
390   { "multimap",             0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  },
391   { "unordered_multimap",   0,                              0,                     "K",           "keys",        "T",          "elements",    FALSE,              TRUE  }, // C++11
392   { "set",                  0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
393   { "unordered_set",        0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
394   { "multiset",             0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  },
395   { "unordered_multiset",   0,                              0,                     "K",           "keys",        0,            0,             FALSE,              TRUE  }, // C++11
396   { "vector",               0,                              0,                     "T",           "elements",    0,            0,             FALSE,              TRUE  },
397   { "queue",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
398   { "priority_queue",       0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
399   { "stack",                0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
400   { "valarray",             0,                              0,                     "T",           "elements",    0,            0,             FALSE,              FALSE },
401   { "exception",            0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE },
402   { "bad_alloc",            "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
403   { "bad_cast",             "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
404   { "bad_typeid",           "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
405   { "logic_error",          "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
406   { "ios_base::failure",    "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
407   { "runtime_error",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
408   { "bad_exception",        "exception",                    0,                     0,             0,             0,            0,             FALSE,              FALSE },
409   { "domain_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
410   { "invalid_argument",     "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
411   { "length_error",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
412   { "out_of_range",         "logic_error",                  0,                     0,             0,             0,            0,             FALSE,              FALSE },
413   { "range_error",          "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
414   { "overflow_error",       "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
415   { "underflow_error",      "runtime_error",                0,                     0,             0,             0,            0,             FALSE,              FALSE },
416   { 0,                      0,                              0,                     0,             0,             0,            0,             FALSE,              FALSE }
417 };
418
419 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
420 {
421   Entry *memEntry = new Entry;
422   memEntry->name       = name;
423   memEntry->type       = type;
424   memEntry->protection = Public;
425   memEntry->section    = Entry::VARIABLE_SEC;
426   memEntry->brief      = "STL member";
427   memEntry->hidden     = FALSE;
428   memEntry->artificial = TRUE;
429   //memEntry->parent     = root;
430   //root->addSubEntry(memEntry);
431   EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
432   memEntryNav->setEntry(memEntry);
433   rootNav->addChild(memEntryNav);
434 }
435
436 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
437 {
438   Entry *iteratorClassEntry = new Entry;
439   iteratorClassEntry->fileName  = "[STL]";
440   iteratorClassEntry->startLine = 1;
441   iteratorClassEntry->name      = name;
442   iteratorClassEntry->section   = Entry::CLASS_SEC;
443   iteratorClassEntry->brief     = "STL iterator class";
444   iteratorClassEntry->hidden    = FALSE;
445   iteratorClassEntry->artificial= TRUE;
446   EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
447   iteratorClassEntryNav->setEntry(iteratorClassEntry);
448   classEntryNav->addChild(iteratorClassEntryNav);
449 }
450
451
452 static void addSTLClasses(EntryNav *rootNav)
453 {
454   Entry *namespaceEntry = new Entry;
455   namespaceEntry->fileName  = "[STL]";
456   namespaceEntry->startLine = 1;
457   //namespaceEntry->parent    = rootNav->entry();
458   namespaceEntry->name      = "std";
459   namespaceEntry->section   = Entry::NAMESPACE_SEC;
460   namespaceEntry->brief     = "STL namespace";
461   namespaceEntry->hidden    = FALSE;
462   namespaceEntry->artificial= TRUE;
463   //root->addSubEntry(namespaceEntry);
464   EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
465   namespaceEntryNav->setEntry(namespaceEntry);
466   rootNav->addChild(namespaceEntryNav);
467
468   STLInfo *info = g_stlinfo;
469   while (info->className)
470   {
471     //printf("Adding STL class %s\n",info->className);
472     QCString fullName = info->className;
473     fullName.prepend("std::");
474
475     // add fake Entry for the class
476     Entry *classEntry = new Entry;
477     classEntry->fileName  = "[STL]";
478     classEntry->startLine = 1;
479     classEntry->name      = fullName;
480     //classEntry->parent    = namespaceEntry;
481     classEntry->section   = Entry::CLASS_SEC;
482     classEntry->brief     = "STL class";
483     classEntry->hidden    = FALSE;
484     classEntry->artificial= TRUE;
485     //namespaceEntry->addSubEntry(classEntry);
486     EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
487     classEntryNav->setEntry(classEntry);
488     namespaceEntryNav->addChild(classEntryNav);
489
490     // add template arguments to class
491     if (info->templType1)
492     {
493       ArgumentList *al = new ArgumentList;
494       Argument *a=new Argument;
495       a->type="typename";
496       a->name=info->templType1;
497       al->append(a);
498       if (info->templType2) // another template argument
499       {
500         a=new Argument;
501         a->type="typename";
502         a->name=info->templType2;
503         al->append(a);
504       }
505       classEntry->tArgLists = new QList<ArgumentList>;
506       classEntry->tArgLists->setAutoDelete(TRUE);
507       classEntry->tArgLists->append(al);
508     }
509     // add member variables
510     if (info->templName1)
511     {
512       addSTLMember(classEntryNav,info->templType1,info->templName1);
513     }
514     if (info->templName2)
515     {
516       addSTLMember(classEntryNav,info->templType2,info->templName2);
517     }
518     if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
519         fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
520     {
521       Entry *memEntry = new Entry;
522       memEntry->name       = "operator->";
523       memEntry->args       = "()";
524       memEntry->type       = "T*";
525       memEntry->protection = Public;
526       memEntry->section    = Entry::FUNCTION_SEC;
527       memEntry->brief      = "STL member";
528       memEntry->hidden     = FALSE;
529       memEntry->artificial = FALSE;
530       EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
531       memEntryNav->setEntry(memEntry);
532       classEntryNav->addChild(memEntryNav);
533     }
534     if (info->baseClass1)
535     {
536       classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
537     }
538     if (info->baseClass2)
539     {
540       classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
541     }
542     if (info->iterators)
543     {
544       // add iterator class
545       addSTLIterator(classEntryNav,fullName+"::iterator");
546       addSTLIterator(classEntryNav,fullName+"::const_iterator");
547       addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
548       addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
549     }
550     info++;
551   }
552 }
553
554 //----------------------------------------------------------------------------
555
556 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
557                                               FileDef *fileScope,TagInfo *tagInfo);
558
559 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
560 {
561   if (rootNav->parent()) // add the page to it's scope
562   {
563     QCString scope = rootNav->parent()->name();
564     if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
565     {
566       scope=substitute(scope,".","::");
567     }
568     scope = stripAnonymousNamespaceScope(scope);
569     scope+="::"+pd->name();
570     Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
571     if (d)
572     {
573       pd->setPageScope(d);
574     }
575   }
576 }
577
578 static void addRelatedPage(EntryNav *rootNav)
579 {
580   Entry *root = rootNav->entry();
581   GroupDef *gd=0;
582   QListIterator<Grouping> gli(*root->groups);
583   Grouping *g;
584   for (;(g=gli.current());++gli)
585   {
586     if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
587   }
588   //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
589   QCString doc;
590   if (root->brief.isEmpty())
591   {
592     doc=root->doc+root->inbodyDocs;
593   }
594   else
595   {
596     doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
597   }
598   PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
599       root->docFile,root->docLine,
600       root->sli,
601       gd,rootNav->tagInfo(),
602       root->lang
603      );
604   if (pd)
605   {
606     pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
607     pd->addSectionsToDefinition(root->anchors);
608     pd->setShowToc(root->stat);
609     addPageToContext(pd,rootNav);
610   }
611 }
612
613 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
614 {
615   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
616         ((!includeExternal && rootNav->tagInfo()==0) ||
617          ( includeExternal && rootNav->tagInfo()!=0))
618      )
619   {
620     rootNav->loadEntry(g_storage);
621     Entry *root = rootNav->entry();
622
623     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
624         (root->groupDocType!=Entry::GROUPDOC_NORMAL &&  additional))
625     {
626       GroupDef *gd = Doxygen::groupSDict->find(root->name);
627       //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
628       //    root->type.data(),root->name.data(),additional,includeExternal,gd);
629
630       if (gd)
631       {
632         if ( !gd->hasGroupTitle() )
633         {
634           gd->setGroupTitle( root->type );
635         }
636         else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
637         {
638           warn( root->fileName,root->startLine,
639               "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
640               qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
641         }
642         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
643         gd->setDocumentation( root->doc, root->docFile, root->docLine );
644         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
645         gd->addSectionsToDefinition(root->anchors);
646         gd->setRefItems(root->sli);
647         gd->setLanguage(root->lang);
648       }
649       else
650       {
651         if (rootNav->tagInfo())
652         {
653           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
654           gd->setReference(rootNav->tagInfo()->tagName);
655         }
656         else
657         {
658           gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
659         }
660         gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
661         // allow empty docs for group
662         gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
663         gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
664         gd->addSectionsToDefinition(root->anchors);
665         Doxygen::groupSDict->append(root->name,gd);
666         gd->setRefItems(root->sli);
667         gd->setLanguage(root->lang);
668       }
669     }
670
671     rootNav->releaseEntry();
672   }
673   if (rootNav->children())
674   {
675     EntryNavListIterator eli(*rootNav->children());
676     EntryNav *e;
677     for (;(e=eli.current());++eli)
678     {
679       buildGroupListFiltered(e,additional,includeExternal);
680     }
681   }
682 }
683
684 static void buildGroupList(EntryNav *rootNav)
685 {
686   // --- first process only local groups
687   // first process the @defgroups blocks
688   buildGroupListFiltered(rootNav,FALSE,FALSE);
689   // then process the @addtogroup, @weakgroup blocks
690   buildGroupListFiltered(rootNav,TRUE,FALSE);
691
692   // --- then also process external groups
693   // first process the @defgroups blocks
694   buildGroupListFiltered(rootNav,FALSE,TRUE);
695   // then process the @addtogroup, @weakgroup blocks
696   buildGroupListFiltered(rootNav,TRUE,TRUE);
697 }
698
699 static void findGroupScope(EntryNav *rootNav)
700 {
701   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
702       rootNav->parent() && !rootNav->parent()->name().isEmpty())
703   {
704     GroupDef *gd;
705     if ((gd=Doxygen::groupSDict->find(rootNav->name())))
706     {
707       QCString scope = rootNav->parent()->name();
708       if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
709       {
710         scope=substitute(scope,".","::");
711       }
712       scope = stripAnonymousNamespaceScope(scope);
713       scope+="::"+gd->name();
714       Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
715       if (d)
716       {
717         gd->setGroupScope(d);
718       }
719     }
720   }
721   RECURSE_ENTRYTREE(findGroupScope,rootNav);
722 }
723
724 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
725 {
726   if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
727   {
728     rootNav->loadEntry(g_storage);
729     Entry *root = rootNav->entry();
730
731     if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
732         (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
733     {
734       GroupDef *gd;
735       if ((gd=Doxygen::groupSDict->find(root->name)))
736       {
737         //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
738         addGroupToGroups(root,gd);
739       }
740     }
741
742     rootNav->releaseEntry();
743   }
744   if (rootNav->children())
745   {
746     EntryNavListIterator eli(*rootNav->children());
747     EntryNav *e;
748     for (;(e=eli.current());++eli)
749     {
750       organizeSubGroupsFiltered(e,additional);
751     }
752   }
753 }
754
755 static void organizeSubGroups(EntryNav *rootNav)
756 {
757   //printf("Defining groups\n");
758   // first process the @defgroups blocks
759   organizeSubGroupsFiltered(rootNav,FALSE);
760   //printf("Additional groups\n");
761   // then process the @addtogroup, @weakgroup blocks
762   organizeSubGroupsFiltered(rootNav,TRUE);
763 }
764
765 //----------------------------------------------------------------------
766
767 static void buildFileList(EntryNav *rootNav)
768 {
769   if (((rootNav->section()==Entry::FILEDOC_SEC) ||
770         ((rootNav->section() & Entry::FILE_MASK) && Config_getBool(EXTRACT_ALL))) &&
771       !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
772      )
773   {
774     rootNav->loadEntry(g_storage);
775     Entry *root = rootNav->entry();
776
777     bool ambig;
778     FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
779     //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
780     if (fd && !ambig)
781     {
782 #if 0
783       if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
784           (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
785       {
786         warn(
787             root->fileName,root->startLine,
788             "file %s already documented. "
789             "Skipping documentation.",
790             root->name.data()
791             );
792       }
793       else
794 #endif
795       {
796         //printf("Adding documentation!\n");
797         // using FALSE in setDocumentation is small hack to make sure a file
798         // is documented even if a \file command is used without further
799         // documentation
800         fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
801         fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
802         fd->addSectionsToDefinition(root->anchors);
803         fd->setRefItems(root->sli);
804         QListIterator<Grouping> gli(*root->groups);
805         Grouping *g;
806         for (;(g=gli.current());++gli)
807         {
808           GroupDef *gd=0;
809           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
810           {
811             gd->addFile(fd);
812             fd->makePartOfGroup(gd);
813             //printf("File %s: in group %s\n",fd->name().data(),s->data());
814           }
815         }
816       }
817     }
818     else
819     {
820       const char *fn = root->fileName.data();
821       QCString text(4096);
822       text.sprintf("the name `%s' supplied as "
823           "the second argument in the \\file statement ",
824           qPrint(root->name));
825       if (ambig) // name is ambiguous
826       {
827         text+="matches the following input files:\n";
828         text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
829         text+="Please use a more specific name by "
830           "including a (larger) part of the path!";
831       }
832       else // name is not an input file
833       {
834         text+="is not an input file";
835       }
836       warn(fn,root->startLine,text);
837     }
838
839     rootNav->releaseEntry();
840   }
841   RECURSE_ENTRYTREE(buildFileList,rootNav);
842 }
843
844 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
845 {
846   if (
847       (!root->doc.stripWhiteSpace().isEmpty() ||
848        !root->brief.stripWhiteSpace().isEmpty() ||
849        Config_getBool(EXTRACT_ALL)
850       ) && root->protection!=Private
851      )
852   {
853     //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
854
855     bool local=Config_getBool(FORCE_LOCAL_INCLUDES);
856     QCString includeFile = root->includeFile;
857     if (!includeFile.isEmpty() && includeFile.at(0)=='"')
858     {
859       local = TRUE;
860       includeFile=includeFile.mid(1,includeFile.length()-2);
861     }
862     else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
863     {
864       local = FALSE;
865       includeFile=includeFile.mid(1,includeFile.length()-2);
866     }
867
868     bool ambig;
869     FileDef *fd=0;
870     // see if we need to include a verbatim copy of the header file
871     //printf("root->includeFile=%s\n",root->includeFile.data());
872     if (!includeFile.isEmpty() &&
873         (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
874        )
875     { // explicit request
876       QCString text;
877       text.sprintf("the name `%s' supplied as "
878                   "the argument of the \\class, \\struct, \\union, or \\include command ",
879                   qPrint(includeFile)
880                  );
881       if (ambig) // name is ambiguous
882       {
883         text+="matches the following input files:\n";
884         text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
885         text+="Please use a more specific name by "
886             "including a (larger) part of the path!";
887       }
888       else // name is not an input file
889       {
890         text+="is not an input file";
891       }
892       warn(root->fileName,root->startLine,text);
893     }
894     else if (includeFile.isEmpty() && ifd &&
895         // see if the file extension makes sense
896         guessSection(ifd->name())==Entry::HEADER_SEC)
897     { // implicit assumption
898       fd=ifd;
899     }
900
901     // if a file is found, we mark it as a source file.
902     if (fd)
903     {
904       QCString iName = !root->includeName.isEmpty() ?
905                        root->includeName : includeFile;
906       if (!iName.isEmpty()) // user specified include file
907       {
908         if (iName.at(0)=='<') local=FALSE; // explicit override
909         else if (iName.at(0)=='"') local=TRUE;
910         if (iName.at(0)=='"' || iName.at(0)=='<')
911         {
912           iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
913         }
914         if (iName.isEmpty())
915         {
916           iName=fd->name();
917         }
918       }
919       else if (!Config_getList(STRIP_FROM_INC_PATH).isEmpty())
920       {
921         iName=stripFromIncludePath(fd->absFilePath());
922       }
923       else // use name of the file containing the class definition
924       {
925         iName=fd->name();
926       }
927       if (fd->generateSourceFile()) // generate code for header
928       {
929         cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
930       }
931       else // put #include in the class documentation without link
932       {
933         cd->setIncludeFile(0,iName,local,TRUE);
934       }
935     }
936   }
937 }
938
939 #if 0
940 static bool addNamespace(Entry *root,ClassDef *cd)
941 {
942   // see if this class is defined inside a namespace
943   if (root->section & Entry::COMPOUND_MASK)
944   {
945     Entry *e = root->parent;
946     while (e)
947     {
948       if (e->section==Entry::NAMESPACE_SEC)
949       {
950         NamespaceDef *nd=0;
951         QCString nsName = stripAnonymousNamespaceScope(e->name);
952         //printf("addNameSpace() trying: %s\n",nsName.data());
953         if (!nsName.isEmpty() && nsName.at(0)!='@' &&
954             (nd=getResolvedNamespace(nsName))
955            )
956         {
957           cd->setNamespace(nd);
958           cd->setOuterScope(nd);
959           nd->insertClass(cd);
960           return TRUE;
961         }
962       }
963       e=e->parent;
964     }
965   }
966   return FALSE;
967 }
968 #endif
969
970 #if 0
971 static Definition *findScope(Entry *root,int level=0)
972 {
973   if (root==0) return 0;
974   //printf("start findScope name=%s\n",root->name.data());
975   Definition *result=0;
976   if (root->section&Entry::SCOPE_MASK)
977   {
978     result = findScope(root->parent,level+1); // traverse to the root of the tree
979     if (result)
980     {
981       //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
982       // TODO: look at template arguments
983       result = result->findInnerCompound(root->name);
984     }
985     else // reached the global scope
986     {
987       // TODO: look at template arguments
988       result = Doxygen::globalScope->findInnerCompound(root->name);
989       //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
990     }
991   }
992   //printf("end findScope(%s,%d)=%s\n",root->name.data(),
993   //       level,result==0 ? "<none>" : result->name().data());
994   return result;
995 }
996 #endif
997
998 /*! returns the Definition object belonging to the first \a level levels of
999  *  full qualified name \a name. Creates an artificial scope if the scope is
1000  *  not found and set the parent/child scope relation if the scope is found.
1001  */
1002 static Definition *buildScopeFromQualifiedName(const QCString name,
1003                                                int level,SrcLangExt lang,TagInfo *tagInfo)
1004 {
1005   //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
1006   int i=0;
1007   int p=0,l;
1008   Definition *prevScope=Doxygen::globalScope;
1009   QCString fullScope;
1010   while (i<level)
1011   {
1012     int idx=getScopeFragment(name,p,&l);
1013     if (idx==-1) return prevScope;
1014     QCString nsName = name.mid(idx,l);
1015     if (nsName.isEmpty()) return prevScope;
1016     if (!fullScope.isEmpty()) fullScope+="::";
1017     fullScope+=nsName;
1018     NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
1019     Definition *innerScope = nd;
1020     ClassDef *cd=0;
1021     if (nd==0) cd = getClass(fullScope);
1022     if (nd==0 && cd) // scope is a class
1023     {
1024       innerScope = cd;
1025     }
1026     else if (nd==0 && cd==0 && fullScope.find('<')==-1) // scope is not known and could be a namespace!
1027     {
1028       // introduce bogus namespace
1029       //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
1030       nd=new NamespaceDef(
1031         "[generated]",1,1,fullScope,
1032         tagInfo?tagInfo->tagName:QCString(),
1033         tagInfo?tagInfo->fileName:QCString());
1034       nd->setLanguage(lang);
1035
1036       // add namespace to the list
1037       Doxygen::namespaceSDict->inSort(fullScope,nd);
1038       innerScope = nd;
1039     }
1040     else // scope is a namespace
1041     {
1042     }
1043     if (innerScope)
1044     {
1045       // make the parent/child scope relation
1046       prevScope->addInnerCompound(innerScope);
1047       innerScope->setOuterScope(prevScope);
1048     }
1049     else // current scope is a class, so return only the namespace part...
1050     {
1051       return prevScope;
1052     }
1053     // proceed to the next scope fragment
1054     p=idx+l+2;
1055     prevScope=innerScope;
1056     i++;
1057   }
1058   return prevScope;
1059 }
1060
1061 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
1062                                               FileDef *fileScope,TagInfo *tagInfo)
1063 {
1064   //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
1065   Definition *resultScope=startScope;
1066   if (resultScope==0) resultScope=Doxygen::globalScope;
1067   QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
1068   int l1=0,i1;
1069   i1=getScopeFragment(scope,0,&l1);
1070   if (i1==-1)
1071   {
1072     //printf(">no fragments!\n");
1073     return resultScope;
1074   }
1075   int p=i1+l1,l2=0,i2;
1076   while ((i2=getScopeFragment(scope,p,&l2))!=-1)
1077   {
1078     QCString nestedNameSpecifier = scope.mid(i1,l1);
1079     Definition *orgScope = resultScope;
1080     //printf("  nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
1081     resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
1082     //printf("  resultScope=%p\n",resultScope);
1083     if (resultScope==0)
1084     {
1085       NamespaceSDict *usedNamespaces;
1086       if (orgScope==Doxygen::globalScope && fileScope &&
1087           (usedNamespaces = fileScope->getUsedNamespaces()))
1088         // also search for used namespaces
1089       {
1090         NamespaceSDict::Iterator ni(*usedNamespaces);
1091         NamespaceDef *nd;
1092         for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
1093         {
1094           // restart search within the used namespace
1095           resultScope = findScopeFromQualifiedName(nd,n,fileScope,tagInfo);
1096         }
1097         if (resultScope)
1098         {
1099           // for a nested class A::I in used namespace N, we get
1100           // N::A::I while looking for A, so we should compare
1101           // resultScope->name() against scope.left(i2+l2)
1102           //printf("  -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1103           if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1104           {
1105             break;
1106           }
1107           goto nextFragment;
1108         }
1109       }
1110
1111       // also search for used classes. Complication: we haven't been able
1112       // to put them in the right scope yet, because we are still resolving
1113       // the scope relations!
1114       // Therefore loop through all used classes and see if there is a right
1115       // scope match between the used class and nestedNameSpecifier.
1116       QDictIterator<FileDef> ui(g_usingDeclarations);
1117       FileDef *usedFd;
1118       for (ui.toFirst();(usedFd=ui.current());++ui)
1119       {
1120         //printf("Checking using class %s\n",ui.currentKey());
1121         if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1122         {
1123           // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1124           // so use this instead.
1125           QCString fqn = QCString(ui.currentKey())+
1126                          scope.right(scope.length()-p);
1127           resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),
1128                                                     startScope->getLanguage(),0);
1129           //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1130           if (resultScope)
1131           {
1132             //printf("> Match! resultScope=%s\n",resultScope->name().data());
1133             return resultScope;
1134           }
1135         }
1136       }
1137
1138       //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1139       return 0;
1140     }
1141  nextFragment:
1142     i1=i2;
1143     l1=l2;
1144     p=i2+l2;
1145   }
1146   //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1147   return resultScope;
1148 }
1149
1150 ArgumentList *getTemplateArgumentsFromName(
1151                   const QCString &name,
1152                   const QList<ArgumentList> *tArgLists)
1153 {
1154   if (tArgLists==0) return 0;
1155
1156   QListIterator<ArgumentList> ali(*tArgLists);
1157   // for each scope fragment, check if it is a template and advance through
1158   // the list if so.
1159   int i,p=0;
1160   while ((i=name.find("::",p))!=-1)
1161   {
1162     NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1163     if (nd==0)
1164     {
1165       ClassDef *cd = getClass(name.left(i));
1166       if (cd)
1167       {
1168         if (cd->templateArguments())
1169         {
1170           ++ali;
1171         }
1172       }
1173     }
1174     p=i+2;
1175   }
1176   return ali.current();
1177 }
1178
1179 static
1180 ClassDef::CompoundType convertToCompoundType(int section,uint64 specifier)
1181 {
1182   ClassDef::CompoundType sec=ClassDef::Class;
1183   if (specifier&Entry::Struct)
1184     sec=ClassDef::Struct;
1185   else if (specifier&Entry::Union)
1186     sec=ClassDef::Union;
1187   else if (specifier&Entry::Category)
1188     sec=ClassDef::Category;
1189   else if (specifier&Entry::Interface)
1190     sec=ClassDef::Interface;
1191   else if (specifier&Entry::Protocol)
1192     sec=ClassDef::Protocol;
1193   else if (specifier&Entry::Exception)
1194     sec=ClassDef::Exception;
1195   else if (specifier&Entry::Service)
1196     sec=ClassDef::Service;
1197   else if (specifier&Entry::Singleton)
1198     sec=ClassDef::Singleton;
1199
1200   switch(section)
1201   {
1202     //case Entry::UNION_SEC:
1203     case Entry::UNIONDOC_SEC:
1204       sec=ClassDef::Union;
1205       break;
1206       //case Entry::STRUCT_SEC:
1207     case Entry::STRUCTDOC_SEC:
1208       sec=ClassDef::Struct;
1209       break;
1210       //case Entry::INTERFACE_SEC:
1211     case Entry::INTERFACEDOC_SEC:
1212       sec=ClassDef::Interface;
1213       break;
1214       //case Entry::PROTOCOL_SEC:
1215     case Entry::PROTOCOLDOC_SEC:
1216       sec=ClassDef::Protocol;
1217       break;
1218       //case Entry::CATEGORY_SEC:
1219     case Entry::CATEGORYDOC_SEC:
1220       sec=ClassDef::Category;
1221       break;
1222       //case Entry::EXCEPTION_SEC:
1223     case Entry::EXCEPTIONDOC_SEC:
1224       sec=ClassDef::Exception;
1225       break;
1226     case Entry::SERVICEDOC_SEC:
1227       sec=ClassDef::Service;
1228       break;
1229     case Entry::SINGLETONDOC_SEC:
1230       sec=ClassDef::Singleton;
1231       break;
1232   }
1233   return sec;
1234 }
1235
1236
1237 static void addClassToContext(EntryNav *rootNav)
1238 {
1239   //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1240   rootNav->loadEntry(g_storage);
1241   Entry *root = rootNav->entry();
1242
1243   //NamespaceDef *nd = 0;
1244   FileDef *fd = rootNav->fileDef();
1245
1246   QCString scName;
1247   if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1248   {
1249      scName=rootNav->parent()->name();
1250   }
1251   // name without parent's scope
1252   QCString fullName = root->name;
1253
1254   // strip off any template parameters (but not those for specializations)
1255   fullName=stripTemplateSpecifiersFromScope(fullName);
1256
1257   // name with scope (if not present already)
1258   QCString qualifiedName = fullName;
1259   if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1260   {
1261     qualifiedName.prepend(scName+"::");
1262   }
1263
1264   // see if we already found the class before
1265   ClassDef *cd = getClass(qualifiedName);
1266
1267   Debug::print(Debug::Classes,0, "  Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1268       cd ? qPrint(cd->name()) : qPrint(root->name), qPrint(qualifiedName),cd);
1269
1270   if (cd)
1271   {
1272     fullName=cd->name();
1273     Debug::print(Debug::Classes,0,"  Existing class %s!\n",qPrint(cd->name()));
1274     //if (cd->templateArguments()==0)
1275     //{
1276     //  //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1277     //  cd->setTemplateArguments(tArgList);
1278     //}
1279
1280     cd->setDocumentation(root->doc,root->docFile,root->docLine);
1281     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1282
1283     if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1284     {
1285       cd->setBodySegment(root->bodyLine,root->endBodyLine);
1286       cd->setBodyDef(fd);
1287     }
1288     //cd->setName(fullName); // change name to match docs
1289
1290     if (cd->templateArguments()==0 || (cd->isForwardDeclared() && (root->spec&Entry::ForwardDecl)==0))
1291     {
1292       // this happens if a template class declared with @class is found
1293       // before the actual definition or if a forward declaration has different template
1294       // parameter names.
1295       ArgumentList *tArgList =
1296         getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1297       cd->setTemplateArguments(tArgList);
1298     }
1299
1300     cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1301   }
1302   else // new class
1303   {
1304     ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1305
1306     QCString className;
1307     QCString namespaceName;
1308     extractNamespaceName(fullName,className,namespaceName);
1309
1310     //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1311     //    fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1312
1313     QCString tagName;
1314     QCString refFileName;
1315     TagInfo *tagInfo = rootNav->tagInfo();
1316     int i;
1317     if (tagInfo)
1318     {
1319       tagName     = tagInfo->tagName;
1320       refFileName = tagInfo->fileName;
1321       if (fullName.find("::")!=-1)
1322         // symbols imported via tag files may come without the parent scope,
1323         // so we artificially create it here
1324       {
1325         buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1326       }
1327     }
1328     ArgumentList *tArgList = 0;
1329     if ((root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java) && (i=fullName.find('<'))!=-1)
1330     {
1331       // a Java/C# generic class looks like a C++ specialization, so we need to split the
1332       // name and template arguments here
1333       tArgList = new ArgumentList;
1334       stringToArgumentList(fullName.mid(i),tArgList);
1335       fullName=fullName.left(i);
1336     }
1337     else
1338     {
1339       tArgList = getTemplateArgumentsFromName(fullName,root->tArgLists);
1340     }
1341     cd=new ClassDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn,
1342         fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1343     Debug::print(Debug::Classes,0,"  New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1344         qPrint(fullName),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
1345     cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1346     cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1347     cd->setLanguage(root->lang);
1348     cd->setId(root->id);
1349     cd->setHidden(root->hidden);
1350     cd->setArtificial(root->artificial);
1351     cd->setClassSpecifier(root->spec);
1352     cd->setTypeConstraints(root->typeConstr);
1353     //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1354
1355     //printf("class %s template args=%s\n",fullName.data(),
1356     //    tArgList ? tempArgListToString(tArgList,root->lang).data() : "<none>");
1357     cd->setTemplateArguments(tArgList);
1358     cd->setProtection(root->protection);
1359     cd->setIsStatic(root->stat);
1360
1361     // file definition containing the class cd
1362     cd->setBodySegment(root->bodyLine,root->endBodyLine);
1363     cd->setBodyDef(fd);
1364
1365     // see if the class is found inside a namespace
1366     //bool found=addNamespace(root,cd);
1367
1368     cd->insertUsedFile(fd);
1369
1370     // add class to the list
1371     //printf("ClassDict.insert(%s)\n",fullName.data());
1372     Doxygen::classSDict->append(fullName,cd);
1373
1374     if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1375     {
1376       //printf("inserting generic '%s' cd=%p\n",fullName.data(),cd);
1377       Doxygen::genericsDict->insert(fullName,cd);
1378     }
1379   }
1380
1381   cd->addSectionsToDefinition(root->anchors);
1382   if (!root->subGrouping) cd->setSubGrouping(FALSE);
1383   if (cd->hasDocumentation())
1384   {
1385     addIncludeFile(cd,fd,root);
1386   }
1387   if (fd && (root->section & Entry::COMPOUND_MASK))
1388   {
1389     //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1390     //    cd->name().data(),
1391     //    fd->name().data(),
1392     //    root->fileName.data()
1393     //   );
1394     cd->setFileDef(fd);
1395     fd->insertClass(cd);
1396   }
1397   addClassToGroups(root,cd);
1398   cd->setRefItems(root->sli);
1399
1400   rootNav->releaseEntry();
1401 }
1402
1403 //----------------------------------------------------------------------
1404 // build a list of all classes mentioned in the documentation
1405 // and all classes that have a documentation block before their definition.
1406 static void buildClassList(EntryNav *rootNav)
1407 {
1408   if (
1409         ((rootNav->section() & Entry::COMPOUND_MASK) ||
1410          rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1411      )
1412   {
1413     addClassToContext(rootNav);
1414   }
1415   RECURSE_ENTRYTREE(buildClassList,rootNav);
1416 }
1417
1418 static void buildClassDocList(EntryNav *rootNav)
1419 {
1420   if (
1421        (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1422      )
1423   {
1424     addClassToContext(rootNav);
1425   }
1426   RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1427 }
1428
1429 static void resolveClassNestingRelations()
1430 {
1431   ClassSDict::Iterator cli(*Doxygen::classSDict);
1432   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1433
1434   bool done=FALSE;
1435   int iteration=0;
1436   while (!done)
1437   {
1438     done=TRUE;
1439     ++iteration;
1440     ClassDef *cd=0;
1441     for (cli.toFirst();(cd=cli.current());++cli)
1442     {
1443       if (!cd->visited)
1444       {
1445         QCString name = stripAnonymousNamespaceScope(cd->name());
1446         //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1447         // also add class to the correct structural context
1448         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1449                                                  name,cd->getFileDef(),0);
1450         if (d)
1451         {
1452           //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1453           d->addInnerCompound(cd);
1454           cd->setOuterScope(d);
1455           cd->visited=TRUE;
1456           done=FALSE;
1457         }
1458         //else
1459         //{
1460         //  printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1461         //}
1462       }
1463     }
1464   }
1465
1466   //give warnings for unresolved compounds
1467   ClassDef *cd=0;
1468   for (cli.toFirst();(cd=cli.current());++cli)
1469   {
1470     if (!cd->visited)
1471     {
1472       QCString name = stripAnonymousNamespaceScope(cd->name());
1473       //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1474       /// create the scope artificially
1475       // anyway, so we can at least relate scopes properly.
1476       Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1477       if (d!=cd && !cd->getDefFileName().isEmpty())
1478                  // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1479                  // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1480                  // also avoid warning for stuff imported via a tagfile.
1481       {
1482         d->addInnerCompound(cd);
1483         cd->setOuterScope(d);
1484         warn(cd->getDefFileName(),cd->getDefLine(),
1485             "Internal inconsistency: scope for class %s not "
1486             "found!",name.data()
1487             );
1488       }
1489     }
1490   }
1491 }
1492
1493 void distributeClassGroupRelations()
1494 {
1495   //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
1496   //if (!inlineGroupedClasses) return;
1497   //printf("** distributeClassGroupRelations()\n");
1498
1499   ClassSDict::Iterator cli(*Doxygen::classSDict);
1500   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1501
1502   ClassDef *cd;
1503   for (cli.toFirst();(cd=cli.current());++cli)
1504   {
1505     //printf("Checking %s\n",cd->name().data());
1506     // distribute the group to nested classes as well
1507     if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1508     {
1509       //printf("  Candidate for merging\n");
1510       ClassSDict::Iterator ncli(*cd->getClassSDict());
1511       ClassDef *ncd;
1512       GroupDef *gd = cd->partOfGroups()->at(0);
1513       for (ncli.toFirst();(ncd=ncli.current());++ncli)
1514       {
1515         if (ncd->partOfGroups()==0)
1516         {
1517           //printf("  Adding %s to group '%s'\n",ncd->name().data(),
1518           //    gd->groupTitle());
1519           ncd->makePartOfGroup(gd);
1520           gd->addClass(ncd);
1521         }
1522       }
1523       cd->visited=TRUE; // only visit every class once
1524     }
1525   }
1526 }
1527
1528 //----------------------------
1529
1530 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1531 {
1532   QCString fullName = removeAnonymousScopes(templ->name());
1533   if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1534   fullName+="."+fieldName;
1535   ClassDef *cd = new ClassDef(templ->getDefFileName(),
1536                               templ->getDefLine(),
1537                               templ->getDefColumn(),
1538                               fullName,
1539                               templ->compoundType());
1540   cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1541   cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1542   cd->setLanguage(templ->getLanguage());
1543   cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1544   cd->setBodyDef(templ->getBodyDef());
1545
1546   cd->setOuterScope(rootCd->getOuterScope());
1547   if (rootCd->getOuterScope()!=Doxygen::globalScope)
1548   {
1549     rootCd->getOuterScope()->addInnerCompound(cd);
1550   }
1551
1552   FileDef *fd = templ->getFileDef();
1553   if (fd)
1554   {
1555     cd->setFileDef(fd);
1556     fd->insertClass(cd);
1557   }
1558   GroupList *groups = rootCd->partOfGroups();
1559   if ( groups!=0 )
1560   {
1561     GroupListIterator gli(*groups);
1562     GroupDef *gd;
1563     for (gli.toFirst();(gd=gli.current());++gli)
1564     {
1565       cd->makePartOfGroup(gd);
1566       gd->addClass(cd);
1567     }
1568   }
1569   //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1570   Doxygen::classSDict->append(fullName,cd);
1571
1572   MemberList *ml = templ->getMemberList(MemberListType_pubAttribs);
1573   if (ml)
1574   {
1575     MemberListIterator li(*ml);
1576     MemberDef *md;
1577     for (li.toFirst();(md=li.current());++li)
1578     {
1579       //printf("    Member %s type=%s\n",md->name().data(),md->typeString());
1580       MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1581                                      md->typeString(),md->name(),md->argsString(),md->excpString(),
1582                                      md->protection(),md->virtualness(),md->isStatic(),Member,
1583                                      md->memberType(),
1584                                      0,0);
1585       imd->setMemberClass(cd);
1586       imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1587       imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1588       imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1589       imd->setMemberSpecifiers(md->getMemberSpecifiers());
1590       imd->setMemberGroupId(md->getMemberGroupId());
1591       imd->setInitializer(md->initializer());
1592       imd->setMaxInitLines(md->initializerLines());
1593       imd->setBitfields(md->bitfieldString());
1594       imd->setLanguage(md->getLanguage());
1595       cd->insertMember(imd);
1596     }
1597   }
1598   return cd;
1599 }
1600
1601 /** Look through the members of class \a cd and its public members.
1602  *  If there is a member m of a tag less struct/union,
1603  *  then we create a duplicate of the struct/union with the name of the
1604  *  member to identify it.
1605  *  So if cd has name S, then the tag less struct/union will get name S.m
1606  *  Since tag less structs can be nested we need to call this function
1607  *  recursively. Later on we need to patch the member types so we keep
1608  *  track of the hierarchy of classes we create.
1609  */
1610 static void processTagLessClasses(ClassDef *rootCd,
1611                                   ClassDef *cd,
1612                                   ClassDef *tagParentCd,
1613                                   const QCString &prefix,int count)
1614 {
1615   //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1616   //printf("checking members for %s\n",cd->name().data());
1617   if (cd->getClassSDict())
1618   {
1619     MemberList *ml = cd->getMemberList(MemberListType_pubAttribs);
1620     if (ml)
1621     {
1622       MemberListIterator li(*ml);
1623       MemberDef *md;
1624       for (li.toFirst();(md=li.current());++li)
1625       {
1626         QCString type = md->typeString();
1627         if (type.find("::@")!=-1) // member of tag less struct/union
1628         {
1629           ClassSDict::Iterator it(*cd->getClassSDict());
1630           ClassDef *icd;
1631           for (it.toFirst();(icd=it.current());++it)
1632           {
1633             //printf("  member %s: type='%s'\n",md->name().data(),type.data());
1634             //printf("  comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1635             if (type.find(icd->name())!=-1) // matching tag less struct/union
1636             {
1637               QCString name = md->name();
1638               if (name.at(0)=='@') name = "__unnamed__";
1639               if (!prefix.isEmpty()) name.prepend(prefix+".");
1640               //printf("    found %s for class %s\n",name.data(),cd->name().data());
1641               ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1642               processTagLessClasses(rootCd,icd,ncd,name,count+1);
1643               //printf("    addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1644               tagParentCd->addTaggedInnerClass(ncd);
1645               ncd->setTagLessReference(icd);
1646
1647               // replace tag-less type for generated/original member
1648               // by newly created class name.
1649               // note the difference between changing cd and tagParentCd.
1650               // for the initial call this is the same pointer, but for
1651               // recursive calls cd is the original tag-less struct (of which
1652               // there is only one instance) and tagParentCd is the newly
1653               // generated tagged struct of which there can be multiple instances!
1654               MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1655               if (pml)
1656               {
1657                 MemberListIterator pli(*pml);
1658                 MemberDef *pmd;
1659                 for (pli.toFirst();(pmd=pli.current());++pli)
1660                 {
1661                   if (pmd->name()==md->name())
1662                   {
1663                     pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1664                     //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1665                   }
1666                 }
1667               }
1668             }
1669           }
1670         }
1671       }
1672     }
1673   }
1674 }
1675
1676 static void findTagLessClasses(ClassDef *cd)
1677 {
1678   if (cd->getClassSDict())
1679   {
1680     ClassSDict::Iterator it(*cd->getClassSDict());
1681     ClassDef *icd;
1682     for (it.toFirst();(icd=it.current());++it)
1683     {
1684       if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1685       {
1686         findTagLessClasses(icd);
1687       }
1688     }
1689   }
1690
1691   processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1692 }
1693
1694 static void findTagLessClasses()
1695 {
1696   ClassSDict::Iterator cli(*Doxygen::classSDict);
1697   ClassDef *cd;
1698   for (cli.toFirst();(cd=cli.current());++cli) // for each class
1699   {
1700     Definition *scope = cd->getOuterScope();
1701     if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1702     {
1703       findTagLessClasses(cd);
1704     }
1705   }
1706 }
1707
1708
1709 //----------------------------------------------------------------------
1710 // build a list of all namespaces mentioned in the documentation
1711 // and all namespaces that have a documentation block before their definition.
1712 static void buildNamespaceList(EntryNav *rootNav)
1713 {
1714   if (
1715        (rootNav->section()==Entry::NAMESPACE_SEC ||
1716         rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1717         rootNav->section()==Entry::PACKAGEDOC_SEC
1718        ) &&
1719        !rootNav->name().isEmpty()
1720      )
1721   {
1722     rootNav->loadEntry(g_storage);
1723     Entry *root = rootNav->entry();
1724
1725     //printf("** buildNamespaceList(%s)\n",root->name.data());
1726
1727     QCString fName = root->name;
1728     if (root->section==Entry::PACKAGEDOC_SEC)
1729     {
1730       fName=substitute(fName,".","::");
1731     }
1732
1733     QCString fullName = stripAnonymousNamespaceScope(fName);
1734     if (!fullName.isEmpty())
1735     {
1736       //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1737       //        root->fileName.data(), root->startLine);
1738       NamespaceDef *nd;
1739       if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1740       {
1741         nd->setDocumentation(root->doc,root->docFile,root->docLine);
1742         nd->setName(fullName); // change name to match docs
1743         nd->addSectionsToDefinition(root->anchors);
1744         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1745         if (nd->getLanguage()==SrcLangExt_Unknown)
1746         {
1747           nd->setLanguage(root->lang);
1748         }
1749         if (rootNav->tagInfo()==0) // if we found the namespace in a tag file
1750                                    // and also in a project file, then remove
1751                                    // the tag file reference
1752         {
1753           nd->setReference("");
1754           nd->setFileName(fullName);
1755         }
1756
1757         // file definition containing the namespace nd
1758         FileDef *fd=rootNav->fileDef();
1759         // insert the namespace in the file definition
1760         if (fd) fd->insertNamespace(nd);
1761         addNamespaceToGroups(root,nd);
1762         nd->setRefItems(root->sli);
1763       }
1764       else // fresh namespace
1765       {
1766         QCString tagName;
1767         QCString tagFileName;
1768         TagInfo *tagInfo = rootNav->tagInfo();
1769         if (tagInfo)
1770         {
1771           tagName     = tagInfo->tagName;
1772           tagFileName = tagInfo->fileName;
1773         }
1774         //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1775         NamespaceDef *nd=new NamespaceDef(tagInfo?tagName:root->fileName,root->startLine,
1776                              root->startColumn,fullName,tagName,tagFileName,
1777                              root->type,root->spec&Entry::Published);
1778         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1779         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1780         nd->addSectionsToDefinition(root->anchors);
1781         nd->setHidden(root->hidden);
1782         nd->setArtificial(root->artificial);
1783         nd->setLanguage(root->lang);
1784         nd->setId(root->id);
1785
1786         //printf("Adding namespace to group\n");
1787         addNamespaceToGroups(root,nd);
1788         nd->setRefItems(root->sli);
1789
1790         // file definition containing the namespace nd
1791         FileDef *fd=rootNav->fileDef();
1792         // insert the namespace in the file definition
1793         if (fd) fd->insertNamespace(nd);
1794
1795         // the empty string test is needed for extract all case
1796         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1797         nd->insertUsedFile(fd);
1798         nd->setBodySegment(root->bodyLine,root->endBodyLine);
1799         nd->setBodyDef(fd);
1800         // add class to the list
1801         Doxygen::namespaceSDict->inSort(fullName,nd);
1802
1803         // also add namespace to the correct structural context
1804         Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName,0,tagInfo);
1805         //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1806         if (d==0) // we didn't find anything, create the scope artificially
1807                   // anyway, so we can at least relate scopes properly.
1808         {
1809           Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1810           d->addInnerCompound(nd);
1811           nd->setOuterScope(d);
1812           // TODO: Due to the order in which the tag file is written
1813           // a nested class can be found before its parent!
1814         }
1815         else
1816         {
1817           d->addInnerCompound(nd);
1818           nd->setOuterScope(d);
1819         }
1820       }
1821     }
1822
1823     rootNav->releaseEntry();
1824   }
1825   RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1826 }
1827
1828 //----------------------------------------------------------------------
1829
1830 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1831                               const QCString &name)
1832 {
1833   NamespaceDef *usingNd =0;
1834   if (unl)
1835   {
1836     //printf("Found namespace dict %d\n",unl->count());
1837     NamespaceSDict::Iterator unli(*unl);
1838     NamespaceDef *und;
1839     for (unli.toFirst();(und=unli.current());++unli)
1840     {
1841       QCString uScope=und->name()+"::";
1842       usingNd = getResolvedNamespace(uScope+name);
1843       //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1844     }
1845   }
1846   return usingNd;
1847 }
1848
1849 static void findUsingDirectives(EntryNav *rootNav)
1850 {
1851   if (rootNav->section()==Entry::USINGDIR_SEC)
1852   {
1853     rootNav->loadEntry(g_storage);
1854     Entry *root = rootNav->entry();
1855
1856     //printf("Found using directive %s at line %d of %s\n",
1857     //    root->name.data(),root->startLine,root->fileName.data());
1858     QCString name=substitute(root->name,".","::");
1859     if (name.right(2)=="::")
1860     {
1861       name=name.left(name.length()-2);
1862     }
1863     if (!name.isEmpty())
1864     {
1865       NamespaceDef *usingNd = 0;
1866       NamespaceDef *nd = 0;
1867       FileDef      *fd = rootNav->fileDef();
1868       QCString nsName;
1869
1870       // see if the using statement was found inside a namespace or inside
1871       // the global file scope.
1872       if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1873           (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1874          )
1875       {
1876         nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1877         if (!nsName.isEmpty())
1878         {
1879           nd = getResolvedNamespace(nsName);
1880         }
1881       }
1882
1883       // find the scope in which the `using' namespace is defined by prepending
1884       // the possible scopes in which the using statement was found, starting
1885       // with the most inner scope and going to the most outer scope (i.e.
1886       // file scope).
1887       int scopeOffset = nsName.length();
1888       do
1889       {
1890         QCString scope=scopeOffset>0 ?
1891                       nsName.left(scopeOffset)+"::" : QCString();
1892         usingNd = getResolvedNamespace(scope+name);
1893         //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1894         if (scopeOffset==0)
1895         {
1896           scopeOffset=-1;
1897         }
1898         else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1899         {
1900           scopeOffset=0;
1901         }
1902       } while (scopeOffset>=0 && usingNd==0);
1903
1904       if (usingNd==0 && nd) // not found, try used namespaces in this scope
1905                             // or in one of the parent namespace scopes
1906       {
1907         NamespaceDef *pnd = nd;
1908         while (pnd && usingNd==0)
1909         {
1910           // also try with one of the used namespaces found earlier
1911           usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1912
1913           // goto the parent
1914           Definition *s = pnd->getOuterScope();
1915           if (s && s->definitionType()==Definition::TypeNamespace)
1916           {
1917             pnd = (NamespaceDef*)s;
1918           }
1919           else
1920           {
1921             pnd = 0;
1922           }
1923         }
1924       }
1925       if (usingNd==0 && fd) // still nothing, also try used namespace in the
1926                             // global scope
1927       {
1928         usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1929       }
1930
1931       //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1932
1933       // add the namespace the correct scope
1934       if (usingNd)
1935       {
1936         //printf("using fd=%p nd=%p\n",fd,nd);
1937         if (nd)
1938         {
1939           //printf("Inside namespace %s\n",nd->name().data());
1940           nd->addUsingDirective(usingNd);
1941         }
1942         else if (fd)
1943         {
1944           //printf("Inside file %s\n",fd->name().data());
1945           fd->addUsingDirective(usingNd);
1946         }
1947       }
1948       else // unknown namespace, but add it anyway.
1949       {
1950         //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1951         NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1952         nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1953         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1954         nd->addSectionsToDefinition(root->anchors);
1955         //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1956         nd->setHidden(root->hidden);
1957         nd->setArtificial(TRUE);
1958         nd->setLanguage(root->lang);
1959         nd->setId(root->id);
1960
1961         QListIterator<Grouping> gli(*root->groups);
1962         Grouping *g;
1963         for (;(g=gli.current());++gli)
1964         {
1965           GroupDef *gd=0;
1966           if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1967             gd->addNamespace(nd);
1968         }
1969
1970         // insert the namespace in the file definition
1971         if (fd)
1972         {
1973           fd->insertNamespace(nd);
1974           fd->addUsingDirective(nd);
1975         }
1976
1977         // the empty string test is needed for extract all case
1978         nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1979         nd->insertUsedFile(fd);
1980         // add class to the list
1981         Doxygen::namespaceSDict->inSort(name,nd);
1982         nd->setRefItems(root->sli);
1983       }
1984     }
1985
1986     rootNav->releaseEntry();
1987   }
1988   RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
1989 }
1990
1991 //----------------------------------------------------------------------
1992
1993 static void buildListOfUsingDecls(EntryNav *rootNav)
1994 {
1995   if (rootNav->section()==Entry::USINGDECL_SEC &&
1996       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1997      )
1998   {
1999     rootNav->loadEntry(g_storage);
2000     Entry *root = rootNav->entry();
2001
2002     QCString name = substitute(root->name,".","::");
2003
2004     if (g_usingDeclarations.find(name)==0)
2005     {
2006       FileDef *fd = rootNav->fileDef();
2007       if (fd)
2008       {
2009         g_usingDeclarations.insert(name,fd);
2010       }
2011     }
2012
2013     rootNav->releaseEntry();
2014   }
2015   RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
2016 }
2017
2018
2019 static void findUsingDeclarations(EntryNav *rootNav)
2020 {
2021   if (rootNav->section()==Entry::USINGDECL_SEC &&
2022       !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2023      )
2024   {
2025     rootNav->loadEntry(g_storage);
2026     Entry *root = rootNav->entry();
2027
2028     //printf("Found using declaration %s at line %d of %s inside section %x\n",
2029     //   root->name.data(),root->startLine,root->fileName.data(),
2030     //   rootNav->parent()->section());
2031     if (!root->name.isEmpty())
2032     {
2033       ClassDef *usingCd = 0;
2034       NamespaceDef *nd = 0;
2035       FileDef      *fd = rootNav->fileDef();
2036       QCString scName;
2037
2038       // see if the using statement was found inside a namespace or inside
2039       // the global file scope.
2040       if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
2041       {
2042         scName=rootNav->parent()->name();
2043         if (!scName.isEmpty())
2044         {
2045           nd = getResolvedNamespace(scName);
2046         }
2047       }
2048
2049       // Assume the using statement was used to import a class.
2050       // Find the scope in which the `using' namespace is defined by prepending
2051       // the possible scopes in which the using statement was found, starting
2052       // with the most inner scope and going to the most outer scope (i.e.
2053       // file scope).
2054
2055       QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2056       usingCd = getClass(name); // try direct lookup first, this is needed to get
2057                                 // builtin STL classes to properly resolve, e.g.
2058                                 // vector -> std::vector
2059       if (usingCd==0)
2060       {
2061         usingCd = getResolvedClass(nd,fd,name); // try via resolving (see also bug757509)
2062       }
2063       if (usingCd==0)
2064       {
2065         usingCd = Doxygen::hiddenClasses->find(name); // check if it is already hidden
2066       }
2067
2068       //printf("%s -> %p\n",root->name.data(),usingCd);
2069       if (usingCd==0) // definition not in the input => add an artificial class
2070       {
2071         Debug::print(Debug::Classes,0,"  New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
2072              qPrint(name),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
2073         usingCd = new ClassDef(
2074                      "<using>",1,1,
2075                      name,
2076                      ClassDef::Class);
2077         Doxygen::hiddenClasses->append(root->name,usingCd);
2078         usingCd->setArtificial(TRUE);
2079         usingCd->setLanguage(root->lang);
2080       }
2081       else
2082       {
2083         Debug::print(Debug::Classes,0,"  Found used class %s in scope=%s\n",
2084             qPrint(usingCd->name()),
2085                         nd?qPrint(nd->name()):
2086                         fd?qPrint(fd->name()):
2087                         "<unknown>");
2088       }
2089
2090       if (nd)
2091       {
2092         //printf("Inside namespace %s\n",nd->name().data());
2093         nd->addUsingDeclaration(usingCd);
2094       }
2095       else if (fd)
2096       {
2097         //printf("Inside file %s\n",fd->name().data());
2098         fd->addUsingDeclaration(usingCd);
2099       }
2100     }
2101
2102     rootNav->releaseEntry();
2103   }
2104   RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
2105 }
2106
2107 //----------------------------------------------------------------------
2108
2109 static void findUsingDeclImports(EntryNav *rootNav)
2110 {
2111   if (rootNav->section()==Entry::USINGDECL_SEC &&
2112       (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
2113      )
2114   {
2115     //printf("Found using declaration %s inside section %x\n",
2116     //    rootNav->name().data(), rootNav->parent()->section());
2117     QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
2118     fullName=stripAnonymousNamespaceScope(fullName);
2119     fullName=stripTemplateSpecifiersFromScope(fullName);
2120     ClassDef *cd = getClass(fullName);
2121     if (cd)
2122     {
2123       //printf("found class %s\n",cd->name().data());
2124       int i=rootNav->name().find("::");
2125       if (i!=-1)
2126       {
2127         QCString scope=rootNav->name().left(i);
2128         QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
2129         ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2130         if (bcd)
2131         {
2132           //printf("found class %s memName=%s\n",bcd->name().data(),memName.data());
2133           MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2134           if (mndict)
2135           {
2136             MemberNameInfo *mni = mndict->find(memName);
2137             if (mni)
2138             {
2139               MemberNameInfoIterator mnii(*mni);
2140               MemberInfo *mi;
2141               for ( ; (mi=mnii.current()) ; ++mnii )
2142               {
2143                 MemberDef *md = mi->memberDef;
2144                 if (md && md->protection()!=Private)
2145                 {
2146
2147                   rootNav->loadEntry(g_storage);
2148                   Entry *root = rootNav->entry();
2149
2150                   //printf("found member %s\n",mni->memberName());
2151                   MemberDef *newMd = 0;
2152                   {
2153                     QCString fileName = root->fileName;
2154                     if (fileName.isEmpty() && rootNav->tagInfo())
2155                     {
2156                       fileName = rootNav->tagInfo()->tagName;
2157                     }
2158                     ArgumentList *templAl = md->templateArguments();
2159                     ArgumentList *al = md->templateArguments();
2160                     newMd = new MemberDef(
2161                       fileName,root->startLine,root->startColumn,
2162                       md->typeString(),memName,md->argsString(),
2163                       md->excpString(),root->protection,root->virt,
2164                       md->isStatic(),Member,md->memberType(),
2165                       templAl,al
2166                       );
2167                   }
2168                   newMd->setMemberClass(cd);
2169                   cd->insertMember(newMd);
2170                   if (!root->doc.isEmpty() || !root->brief.isEmpty())
2171                   {
2172                     newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2173                     newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2174                     newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2175                   }
2176                   else
2177                   {
2178                     newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2179                     newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2180                     newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2181                   }
2182                   newMd->setDefinition(md->definition());
2183                   newMd->enableCallGraph(root->callGraph);
2184                   newMd->enableCallerGraph(root->callerGraph);
2185                   newMd->setBitfields(md->bitfieldString());
2186                   newMd->addSectionsToDefinition(root->anchors);
2187                   newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2188                   newMd->setBodyDef(md->getBodyDef());
2189                   newMd->setInitializer(md->initializer());
2190                   newMd->setMaxInitLines(md->initializerLines());
2191                   newMd->setMemberGroupId(root->mGrpId);
2192                   newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2193                   newMd->setLanguage(root->lang);
2194                   newMd->setId(root->id);
2195
2196                   rootNav->releaseEntry();
2197                 }
2198               }
2199             }
2200           }
2201         }
2202       }
2203     }
2204
2205   }
2206   RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2207 }
2208
2209 //----------------------------------------------------------------------
2210
2211 static void findIncludedUsingDirectives()
2212 {
2213   // first mark all files as not visited
2214   FileNameListIterator fnli(*Doxygen::inputNameList);
2215   FileName *fn;
2216   for (fnli.toFirst();(fn=fnli.current());++fnli)
2217   {
2218     FileNameIterator fni(*fn);
2219     FileDef *fd;
2220     for (;(fd=fni.current());++fni)
2221     {
2222       fd->visited=FALSE;
2223     }
2224   }
2225   // then recursively add using directives found in #include files
2226   // to files that have not been visited.
2227   for (fnli.toFirst();(fn=fnli.current());++fnli)
2228   {
2229     FileNameIterator fni(*fn);
2230     FileDef *fd;
2231     for (fni.toFirst();(fd=fni.current());++fni)
2232     {
2233       if (!fd->visited)
2234       {
2235         //printf("----- adding using directives for file %s\n",fd->name().data());
2236         fd->addIncludedUsingDirectives();
2237       }
2238     }
2239   }
2240 }
2241
2242 //----------------------------------------------------------------------
2243
2244 static MemberDef *addVariableToClass(
2245     EntryNav *rootNav,
2246     ClassDef *cd,
2247     MemberType mtype,
2248     const QCString &name,
2249     bool fromAnnScope,
2250     MemberDef *fromAnnMemb,
2251     Protection prot,
2252     Relationship related)
2253 {
2254   Entry *root = rootNav->entry();
2255
2256   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2257   QCString scopeSeparator="::";
2258   SrcLangExt lang = cd->getLanguage();
2259   if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2260   {
2261     qualScope = substitute(qualScope,"::",".");
2262     scopeSeparator=".";
2263   }
2264   Debug::print(Debug::Variables,0,
2265       "  class variable:\n"
2266       "    `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2267       qPrint(root->type),
2268       qPrint(qualScope),
2269       qPrint(name),
2270       qPrint(root->args),
2271       root->protection,
2272       fromAnnScope,
2273       qPrint(root->initializer)
2274               );
2275
2276   QCString def;
2277   if (!root->type.isEmpty())
2278   {
2279     if (related || mtype==MemberType_Friend || Config_getBool(HIDE_SCOPE_NAMES))
2280     {
2281       if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2282       {
2283         def="using "+name+" = "+root->type.mid(7);
2284       }
2285       else
2286       {
2287         def=root->type+" "+name+root->args;
2288       }
2289     }
2290     else
2291     {
2292       if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2293       {
2294         def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2295       }
2296       else
2297       {
2298         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2299       }
2300     }
2301   }
2302   else
2303   {
2304     if (Config_getBool(HIDE_SCOPE_NAMES))
2305     {
2306       def=name+root->args;
2307     }
2308     else
2309     {
2310       def=qualScope+scopeSeparator+name+root->args;
2311     }
2312   }
2313   def.stripPrefix("static ");
2314
2315   // see if the member is already found in the same scope
2316   // (this may be the case for a static member that is initialized
2317   //  outside the class)
2318   MemberName *mn=Doxygen::memberNameSDict->find(name);
2319   if (mn)
2320   {
2321     MemberNameIterator mni(*mn);
2322     MemberDef *md;
2323     for (mni.toFirst();(md=mni.current());++mni)
2324     {
2325       //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2326       //    md->getClassDef(),cd,root->type.data(),md->typeString());
2327       if (md->getClassDef()==cd &&
2328           removeRedundantWhiteSpace(root->type)==md->typeString())
2329         // member already in the scope
2330       {
2331
2332         if (root->lang==SrcLangExt_ObjC &&
2333             root->mtype==Property &&
2334             md->memberType()==MemberType_Variable)
2335         { // Objective-C 2.0 property
2336           // turn variable into a property
2337           md->setProtection(root->protection);
2338           cd->reclassifyMember(md,MemberType_Property);
2339         }
2340         addMemberDocs(rootNav,md,def,0,FALSE);
2341         //printf("    Member already found!\n");
2342         return md;
2343       }
2344     }
2345   }
2346
2347   QCString fileName = root->fileName;
2348   if (fileName.isEmpty() && rootNav->tagInfo())
2349   {
2350     fileName = rootNav->tagInfo()->tagName;
2351   }
2352
2353   // new member variable, typedef or enum value
2354   MemberDef *md=new MemberDef(
2355       fileName,root->startLine,root->startColumn,
2356       root->type,name,root->args,root->exception,
2357       prot,Normal,root->stat,related,
2358       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2359   md->setTagInfo(rootNav->tagInfo());
2360   md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2361   //md->setDefFile(root->fileName);
2362   //md->setDefLine(root->startLine);
2363   md->setDocumentation(root->doc,root->docFile,root->docLine);
2364   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2365   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2366   md->setDefinition(def);
2367   md->setBitfields(root->bitfields);
2368   md->addSectionsToDefinition(root->anchors);
2369   md->setFromAnonymousScope(fromAnnScope);
2370   md->setFromAnonymousMember(fromAnnMemb);
2371   //md->setIndentDepth(indentDepth);
2372   md->setBodySegment(root->bodyLine,root->endBodyLine);
2373   md->setInitializer(root->initializer);
2374   md->setMaxInitLines(root->initLines);
2375   md->setMemberGroupId(root->mGrpId);
2376   md->setMemberSpecifiers(root->spec);
2377   md->setReadAccessor(root->read);
2378   md->setWriteAccessor(root->write);
2379   md->enableCallGraph(root->callGraph);
2380   md->enableCallerGraph(root->callerGraph);
2381   md->setHidden(root->hidden);
2382   md->setArtificial(root->artificial);
2383   md->setLanguage(root->lang);
2384   md->setId(root->id);
2385   addMemberToGroups(root,md);
2386   //if (root->mGrpId!=-1)
2387   //{
2388   //  printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2389   //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
2390   //
2391   md->setBodyDef(rootNav->fileDef());
2392
2393   //printf("    Adding member=%s\n",md->name().data());
2394   // add the member to the global list
2395   if (mn)
2396   {
2397     mn->append(md);
2398   }
2399   else // new variable name
2400   {
2401     mn = new MemberName(name);
2402     mn->append(md);
2403     //printf("Adding memberName=%s\n",mn->memberName());
2404     //Doxygen::memberNameDict.insert(name,mn);
2405     //Doxygen::memberNameList.append(mn);
2406     Doxygen::memberNameSDict->append(name,mn);
2407     // add the member to the class
2408   }
2409   //printf("    New member adding to %s (%p)!\n",cd->name().data(),cd);
2410   cd->insertMember(md);
2411   md->setRefItems(root->sli);
2412
2413   //TODO: insert FileDef instead of filename strings.
2414   cd->insertUsedFile(rootNav->fileDef());
2415   rootNav->changeSection(Entry::EMPTY_SEC);
2416   return md;
2417 }
2418
2419 //----------------------------------------------------------------------
2420
2421 static MemberDef *addVariableToFile(
2422     EntryNav *rootNav,
2423     MemberType mtype,
2424     const QCString &scope,
2425     const QCString &name,
2426     bool fromAnnScope,
2427     /*int indentDepth,*/
2428     MemberDef *fromAnnMemb)
2429 {
2430   Entry *root = rootNav->entry();
2431   Debug::print(Debug::Variables,0,
2432       "  global variable:\n"
2433       "    type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2434       qPrint(root->type),
2435       qPrint(scope),
2436       qPrint(name),
2437       qPrint(root->args),
2438       root->protection,
2439       mtype,
2440       root->lang
2441               );
2442
2443   FileDef *fd = rootNav->fileDef();
2444
2445   // see if we have a typedef that should hide a struct or union
2446   if (mtype==MemberType_Typedef && Config_getBool(TYPEDEF_HIDES_STRUCT))
2447   {
2448     QCString type = root->type;
2449     type.stripPrefix("typedef ");
2450     if (type.left(7)=="struct " || type.left(6)=="union ")
2451     {
2452       type.stripPrefix("struct ");
2453       type.stripPrefix("union ");
2454       static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2455       int l,s;
2456       s = re.match(type,0,&l);
2457       if (s>=0)
2458       {
2459         QCString typeValue = type.mid(s,l);
2460         ClassDef *cd = getClass(typeValue);
2461         if (cd)
2462         {
2463           // this typedef should hide compound name cd, so we
2464           // change the name that is displayed from cd.
2465           cd->setClassName(name);
2466           cd->setDocumentation(root->doc,root->docFile,root->docLine);
2467           cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2468           return 0;
2469         }
2470       }
2471     }
2472   }
2473
2474   // see if the function is inside a namespace
2475   NamespaceDef *nd = 0;
2476   if (!scope.isEmpty())
2477   {
2478     if (scope.find('@')!=-1) return 0; // anonymous scope!
2479     //nscope=removeAnonymousScopes(scope);
2480     //if (!nscope.isEmpty())
2481     //{
2482     nd = getResolvedNamespace(scope);
2483     //}
2484   }
2485   QCString def;
2486
2487   // determine the definition of the global variable
2488   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' &&
2489       !Config_getBool(HIDE_SCOPE_NAMES)
2490      )
2491     // variable is inside a namespace, so put the scope before the name
2492   {
2493     SrcLangExt lang = nd->getLanguage();
2494     QCString sep=getLanguageSpecificSeparator(lang);
2495
2496     if (!root->type.isEmpty())
2497     {
2498       if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2499       {
2500         def="using "+nd->name()+sep+name+" = "+root->type;
2501       }
2502       else // normal member
2503       {
2504         def=root->type+" "+nd->name()+sep+name+root->args;
2505       }
2506     }
2507     else
2508     {
2509       def=nd->name()+sep+name+root->args;
2510     }
2511   }
2512   else
2513   {
2514     if (!root->type.isEmpty() && !root->name.isEmpty())
2515     {
2516       if (name.at(0)=='@') // dummy variable representing anonymous union
2517       {
2518         def=root->type;
2519       }
2520       else
2521       {
2522         if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2523         {
2524           def="using "+root->name+" = "+root->type.mid(7);
2525         }
2526         else // normal member
2527         {
2528           def=root->type+" "+name+root->args;
2529         }
2530       }
2531     }
2532     else
2533     {
2534       def=name+root->args;
2535     }
2536   }
2537   def.stripPrefix("static ");
2538
2539   MemberName *mn=Doxygen::functionNameSDict->find(name);
2540   if (mn)
2541   {
2542     //QCString nscope=removeAnonymousScopes(scope);
2543     //NamespaceDef *nd=0;
2544     //if (!nscope.isEmpty())
2545     if (!scope.isEmpty())
2546     {
2547       nd = getResolvedNamespace(scope);
2548     }
2549     MemberNameIterator mni(*mn);
2550     MemberDef *md;
2551     for (mni.toFirst();(md=mni.current());++mni)
2552     {
2553       if (
2554           ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2555             root->fileName==md->getFileDef()->absFilePath()
2556            ) // both variable names in the same file
2557            || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2558           )
2559           && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2560           && !md->isEnumerate() // in C# an enum value and enum can have the same name
2561          )
2562         // variable already in the scope
2563       {
2564         bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2565                           md->argsString()!=root->args &&
2566                           root->args.find('[')!=-1;
2567         bool staticsInDifferentFiles =
2568                           root->stat && md->isStatic() &&
2569                           root->fileName!=md->getDefFileName();
2570
2571         if (md->getFileDef() &&
2572             !isPHPArray && // not a php array
2573             !staticsInDifferentFiles
2574            )
2575           // not a php array variable
2576         {
2577
2578           Debug::print(Debug::Variables,0,
2579               "    variable already found: scope=%s\n",qPrint(md->getOuterScope()->name()));
2580           addMemberDocs(rootNav,md,def,0,FALSE);
2581           md->setRefItems(root->sli);
2582           return md;
2583         }
2584       }
2585     }
2586   }
2587
2588   QCString fileName = root->fileName;
2589   if (fileName.isEmpty() && rootNav->tagInfo())
2590   {
2591     fileName = rootNav->tagInfo()->tagName;
2592   }
2593
2594   Debug::print(Debug::Variables,0,
2595     "    new variable, nd=%s tagInfo=%p!\n",nd?qPrint(nd->name()):"<global>",rootNav->tagInfo());
2596   // new global variable, enum value or typedef
2597   MemberDef *md=new MemberDef(
2598       fileName,root->startLine,root->startColumn,
2599       root->type,name,root->args,0,
2600       root->protection, Normal,root->stat,Member,
2601       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2602   md->setTagInfo(rootNav->tagInfo());
2603   md->setMemberSpecifiers(root->spec);
2604   md->setDocumentation(root->doc,root->docFile,root->docLine);
2605   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2606   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2607   md->addSectionsToDefinition(root->anchors);
2608   md->setFromAnonymousScope(fromAnnScope);
2609   md->setFromAnonymousMember(fromAnnMemb);
2610   md->setInitializer(root->initializer);
2611   md->setMaxInitLines(root->initLines);
2612   md->setMemberGroupId(root->mGrpId);
2613   md->setDefinition(def);
2614   md->setLanguage(root->lang);
2615   md->setId(root->id);
2616   md->enableCallGraph(root->callGraph);
2617   md->enableCallerGraph(root->callerGraph);
2618   md->setExplicitExternal(root->explicitExternal);
2619   //md->setOuterScope(fd);
2620   if (!root->explicitExternal)
2621   {
2622     md->setBodySegment(root->bodyLine,root->endBodyLine);
2623     md->setBodyDef(fd);
2624   }
2625   addMemberToGroups(root,md);
2626
2627   md->setRefItems(root->sli);
2628   if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2629   {
2630     md->setNamespace(nd);
2631     nd->insertMember(md);
2632   }
2633
2634   // add member to the file (we do this even if we have already inserted
2635   // it into the namespace.
2636   if (fd)
2637   {
2638     md->setFileDef(fd);
2639     fd->insertMember(md);
2640   }
2641
2642   // add member definition to the list of globals
2643   if (mn)
2644   {
2645     mn->append(md);
2646   }
2647   else
2648   {
2649     mn = new MemberName(name);
2650     mn->append(md);
2651     Doxygen::functionNameSDict->append(name,mn);
2652   }
2653   rootNav->changeSection(Entry::EMPTY_SEC);
2654   return md;
2655 }
2656
2657 /*! See if the return type string \a type is that of a function pointer
2658  *  \returns -1 if this is not a function pointer variable or
2659  *           the index at which the closing brace of (...*name) was found.
2660  */
2661 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2662 {
2663   if (lang == SrcLangExt_Fortran || lang == SrcLangExt_VHDL)
2664   {
2665     return -1; // Fortran and VHDL do not have function pointers
2666   }
2667   static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2668   int i=-1,l;
2669   int bb=type.find('<');
2670   int be=type.findRev('>');
2671   if (!type.isEmpty() &&             // return type is non-empty
2672       (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2673       type.find("operator")==-1 &&   // not an operator
2674       (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2675                                     // not a function pointer return type
2676       !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2677      )
2678   {
2679     if (pLength) *pLength=l;
2680     //printf("findFunctionPtr=%d\n",i);
2681     return i;
2682   }
2683   else
2684   {
2685     //printf("findFunctionPtr=%d\n",-1);
2686     return -1;
2687   }
2688 }
2689
2690
2691 /*! Returns TRUE iff \a type is a class within scope \a context.
2692  *  Used to detect variable declarations that look like function prototypes.
2693  */
2694 static bool isVarWithConstructor(EntryNav *rootNav)
2695 {
2696   static QRegExp initChars("[0-9\"'&*!^]+");
2697   static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2698   bool result=FALSE;
2699   bool typeIsClass;
2700   QCString type;
2701   Definition *ctx = 0;
2702   FileDef *fd = 0;
2703   int ti;
2704
2705   //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2706   rootNav->loadEntry(g_storage);
2707   Entry *root = rootNav->entry();
2708
2709   if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2710   { // inside a class
2711     result=FALSE;
2712     goto done;
2713   }
2714   else if ((fd = rootNav->fileDef()) &&
2715             (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2716           )
2717   { // inside a .c file
2718     result=FALSE;
2719     goto done;
2720   }
2721   if (root->type.isEmpty())
2722   {
2723     result=FALSE;
2724     goto done;
2725   }
2726   if (!rootNav->parent()->name().isEmpty())
2727   {
2728     ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2729   }
2730   type = root->type;
2731   // remove qualifiers
2732   findAndRemoveWord(type,"const");
2733   findAndRemoveWord(type,"static");
2734   findAndRemoveWord(type,"volatile");
2735   //if (type.left(6)=="const ") type=type.right(type.length()-6);
2736   typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2737   if (!typeIsClass && (ti=type.find('<'))!=-1)
2738   {
2739     typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2740   }
2741   if (typeIsClass) // now we still have to check if the arguments are
2742                    // types or values. Since we do not have complete type info
2743                    // we need to rely on heuristics :-(
2744   {
2745     //printf("typeIsClass\n");
2746     ArgumentList *al = root->argList;
2747     if (al==0 || al->isEmpty())
2748     {
2749       result=FALSE; // empty arg list -> function prototype.
2750       goto done;
2751     }
2752     ArgumentListIterator ali(*al);
2753     Argument *a;
2754     for (ali.toFirst();(a=ali.current());++ali)
2755     {
2756       if (!a->name.isEmpty() || !a->defval.isEmpty())
2757       {
2758         if (a->name.find(initChars)==0)
2759         {
2760           result=TRUE;
2761         }
2762         else
2763         {
2764           result=FALSE; // arg has (type,name) pair -> function prototype
2765         }
2766         goto done;
2767       }
2768       if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0)
2769       {
2770         result=FALSE; // arg type is a known type
2771         goto done;
2772       }
2773       if (checkIfTypedef(ctx,fd,a->type))
2774       {
2775          //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2776          result=FALSE; // argument is a typedef
2777          goto done;
2778       }
2779       if (a->type.at(a->type.length()-1)=='*' ||
2780           a->type.at(a->type.length()-1)=='&')
2781                      // type ends with * or & => pointer or reference
2782       {
2783         result=FALSE;
2784         goto done;
2785       }
2786       if (a->type.find(initChars)==0)
2787       {
2788         result=TRUE; // argument type starts with typical initializer char
2789         goto done;
2790       }
2791       QCString resType=resolveTypeDef(ctx,a->type);
2792       if (resType.isEmpty()) resType=a->type;
2793       int len;
2794       if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2795       {
2796         resType=resType.left(len);
2797         //printf("resType=%s\n",resType.data());
2798         if (resType=="int"    || resType=="long" || resType=="float" ||
2799             resType=="double" || resType=="char" || resType=="signed" ||
2800             resType=="const"  || resType=="unsigned" || resType=="void")
2801         {
2802           result=FALSE; // type keyword -> function prototype
2803           goto done;
2804         }
2805       }
2806     }
2807     result=TRUE;
2808   }
2809
2810 done:
2811   //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2812   //                                          root->type.data(),result);
2813   rootNav->releaseEntry();
2814   return result;
2815 }
2816
2817 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2818 {
2819     rootNav->loadEntry(g_storage);
2820     Entry *root = rootNav->entry();
2821
2822     Debug::print(Debug::Variables,0,
2823                   "VARIABLE_SEC: \n"
2824                   "  type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2825                    qPrint(root->type),
2826                    qPrint(root->name),
2827                    qPrint(root->args),
2828                    root->bodyLine,
2829                    root->mGrpId,
2830                    qPrint(root->relates)
2831                 );
2832     //printf("root->parent->name=%s\n",root->parent->name.data());
2833
2834     if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2835         (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2836     {
2837       // recover from parse error caused by redundant braces
2838       // like in "int *(var[10]);", which is parsed as
2839       // type="" name="int *" args="(var[10])"
2840
2841       root->type=root->name;
2842       static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2843       int l=0;
2844       int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2845       if (i!=-1)
2846       {
2847         root->name=root->args.mid(i,l);
2848         root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2849       }
2850       //printf("new: type=`%s' name=`%s' args=`%s'\n",
2851       //    root->type.data(),root->name.data(),root->args.data());
2852     }
2853     else
2854     {
2855       int i=isFuncPtr;
2856       if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2857       Debug::print(Debug::Variables,0,"  functionPtr? %s\n",i!=-1?"yes":"no");
2858       if (i!=-1) // function pointer
2859       {
2860         int ai = root->type.find('[',i);
2861         if (ai>i) // function pointer array
2862         {
2863           root->args.prepend(root->type.right(root->type.length()-ai));
2864           root->type=root->type.left(ai);
2865         }
2866         else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2867         {
2868           root->type=root->type.left(root->type.length()-1);
2869           root->args.prepend(") ");
2870           //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2871         }
2872       }
2873     }
2874
2875     QCString scope,name=removeRedundantWhiteSpace(root->name);
2876
2877     // find the scope of this variable
2878     EntryNav *p = rootNav->parent();
2879     while ((p->section() & Entry::SCOPE_MASK))
2880     {
2881       QCString scopeName = p->name();
2882       if (!scopeName.isEmpty())
2883       {
2884         scope.prepend(scopeName);
2885         break;
2886       }
2887       p=p->parent();
2888     }
2889
2890     MemberType mtype;
2891     QCString type=root->type.stripWhiteSpace();
2892     ClassDef *cd=0;
2893     bool isRelated=FALSE;
2894     bool isMemberOf=FALSE;
2895
2896     QCString classScope=stripAnonymousNamespaceScope(scope);
2897     classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2898     QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2899
2900     if (root->name.findRev("::")!=-1)
2901     {
2902       if (root->type=="friend class" || root->type=="friend struct" ||
2903           root->type=="friend union")
2904       {
2905          cd=getClass(scope);
2906          if (cd)
2907          {
2908            addVariableToClass(rootNav,  // entry
2909                               cd,    // class to add member to
2910                               MemberType_Friend, // type of member
2911                               name, // name of the member
2912                               FALSE,  // from Anonymous scope
2913                               0,      // anonymous member
2914                               Public, // protection
2915                               Member  // related to a class
2916                              );
2917          }
2918       }
2919       goto nextMember;
2920                /* skip this member, because it is a
2921                 * static variable definition (always?), which will be
2922                 * found in a class scope as well, but then we know the
2923                 * correct protection level, so only then it will be
2924                 * inserted in the correct list!
2925                 */
2926     }
2927
2928     if (type=="@")
2929       mtype=MemberType_EnumValue;
2930     else if (type.left(8)=="typedef ")
2931       mtype=MemberType_Typedef;
2932     else if (type.left(7)=="friend ")
2933       mtype=MemberType_Friend;
2934     else if (root->mtype==Property)
2935       mtype=MemberType_Property;
2936     else if (root->mtype==Event)
2937       mtype=MemberType_Event;
2938     else
2939       mtype=MemberType_Variable;
2940
2941     if (!root->relates.isEmpty()) // related variable
2942     {
2943       isRelated=TRUE;
2944       isMemberOf=(root->relatesType == MemberOf);
2945       if (getClass(root->relates)==0 && !scope.isEmpty())
2946         scope=mergeScopes(scope,root->relates);
2947       else
2948         scope=root->relates;
2949     }
2950
2951     cd=getClass(scope);
2952     if (cd==0 && classScope!=scope) cd=getClass(classScope);
2953     if (cd)
2954     {
2955       MemberDef *md=0;
2956
2957       // if cd is an anonymous (=tag less) scope we insert the member
2958       // into a non-anonymous parent scope as well. This is needed to
2959       // be able to refer to it using \var or \fn
2960
2961       //int indentDepth=0;
2962       int si=scope.find('@');
2963       //int anonyScopes = 0;
2964       //bool added=FALSE;
2965
2966       static bool inlineSimpleStructs = Config_getBool(INLINE_SIMPLE_STRUCTS);
2967       if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2968       {
2969         QCString pScope;
2970         ClassDef *pcd=0;
2971         pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2972         if (!pScope.isEmpty())
2973           pScope.prepend(annScopePrefix);
2974         else if (annScopePrefix.length()>2)
2975           pScope=annScopePrefix.left(annScopePrefix.length()-2);
2976         if (name.at(0)!='@')
2977         {
2978           if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2979           {
2980             md=addVariableToClass(rootNav,  // entry
2981                                   pcd,   // class to add member to
2982                                   mtype, // member type
2983                                   name,  // member name
2984                                   TRUE,  // from anonymous scope
2985                                   0,     // from anonymous member
2986                                   root->protection,
2987                                   isMemberOf ? Foreign : isRelated ? Related : Member
2988                                  );
2989             //added=TRUE;
2990           }
2991           else // anonymous scope inside namespace or file => put variable in the global scope
2992           {
2993             if (mtype==MemberType_Variable)
2994             {
2995               md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0);
2996             }
2997             //added=TRUE;
2998           }
2999         }
3000       }
3001
3002       //printf("name=`%s' scope=%s scope.right=%s\n",
3003       //                   name.data(),scope.data(),
3004       //                   scope.right(scope.length()-si).data());
3005       addVariableToClass(rootNav,   // entry
3006                          cd,     // class to add member to
3007                          mtype,  // member type
3008                          name,   // name of the member
3009                          FALSE,  // from anonymous scope
3010                          md,     // from anonymous member
3011                          root->protection,
3012                          isMemberOf ? Foreign : isRelated ? Related : Member);
3013     }
3014     else if (!name.isEmpty()) // global variable
3015     {
3016       //printf("Inserting member in global scope %s!\n",scope.data());
3017       addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
3018     }
3019
3020 nextMember:
3021     rootNav->releaseEntry();
3022 }
3023
3024 //----------------------------------------------------------------------
3025 // Searches the Entry tree for typedef documentation sections.
3026 // If found they are stored in their class or in the global list.
3027 static void buildTypedefList(EntryNav *rootNav)
3028 {
3029   //printf("buildVarList(%s)\n",rootNav->name().data());
3030   if (!rootNav->name().isEmpty() &&
3031       rootNav->section()==Entry::VARIABLE_SEC &&
3032       rootNav->type().find("typedef ")!=-1 // its a typedef
3033      )
3034   {
3035     addVariable(rootNav);
3036   }
3037   if (rootNav->children())
3038   {
3039     EntryNavListIterator eli(*rootNav->children());
3040     EntryNav *e;
3041     for (;(e=eli.current());++eli)
3042     {
3043       if (e->section()!=Entry::ENUM_SEC)
3044       {
3045         buildTypedefList(e);
3046       }
3047     }
3048   }
3049 }
3050
3051 //----------------------------------------------------------------------
3052 // Searches the Entry tree for Variable documentation sections.
3053 // If found they are stored in their class or in the global list.
3054
3055 static void buildVarList(EntryNav *rootNav)
3056 {
3057   //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
3058   int isFuncPtr=-1;
3059   if (!rootNav->name().isEmpty() &&
3060       (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
3061       (
3062        (rootNav->section()==Entry::VARIABLE_SEC    // it's a variable
3063        ) ||
3064        (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable
3065         (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
3066        ) ||
3067        (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
3068         isVarWithConstructor(rootNav)
3069        )
3070       )
3071      ) // documented variable
3072   {
3073     addVariable(rootNav,isFuncPtr);
3074   }
3075   if (rootNav->children())
3076   {
3077     EntryNavListIterator eli(*rootNav->children());
3078     EntryNav *e;
3079     for (;(e=eli.current());++eli)
3080     {
3081       if (e->section()!=Entry::ENUM_SEC)
3082       {
3083         buildVarList(e);
3084       }
3085     }
3086   }
3087 }
3088
3089 //----------------------------------------------------------------------
3090 // Searches the Entry tree for Interface sections (UNO IDL only).
3091 // If found they are stored in their service or in the global list.
3092 //
3093
3094 static void addInterfaceOrServiceToServiceOrSingleton(
3095         EntryNav *const rootNav,
3096         ClassDef *const cd,
3097         QCString const& rname)
3098 {
3099   Entry *const root = rootNav->entry();
3100   FileDef *const fd = rootNav->fileDef();
3101   enum MemberType const type = (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC)
3102       ? MemberType_Interface
3103       : MemberType_Service;
3104   QCString fileName = root->fileName;
3105   if (fileName.isEmpty() && rootNav->tagInfo())
3106   {
3107     fileName = rootNav->tagInfo()->tagName;
3108   }
3109   MemberDef *const md = new MemberDef(
3110       fileName, root->startLine, root->startColumn, root->type, rname,
3111       "", "", root->protection, root->virt, root->stat, Member,
3112       type, 0, root->argList);
3113   md->setTagInfo(rootNav->tagInfo());
3114   md->setMemberClass(cd);
3115   md->setDocumentation(root->doc,root->docFile,root->docLine);
3116   md->setDocsForDefinition(false);
3117   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3118   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3119   md->setBodySegment(root->bodyLine,root->endBodyLine);
3120   md->setMemberSpecifiers(root->spec);
3121   md->setMemberGroupId(root->mGrpId);
3122   md->setTypeConstraints(root->typeConstr);
3123   md->setLanguage(root->lang);
3124   md->setBodyDef(fd);
3125   md->setFileDef(fd);
3126   md->addSectionsToDefinition(root->anchors);
3127   QCString const def = root->type + " " + rname;
3128   md->setDefinition(def);
3129   md->enableCallGraph(root->callGraph);
3130   md->enableCallerGraph(root->callerGraph);
3131
3132   Debug::print(Debug::Functions,0,
3133       "  Interface Member:\n"
3134       "    `%s' `%s' proto=%d\n"
3135       "    def=`%s'\n",
3136       qPrint(root->type),
3137       qPrint(rname),
3138       root->proto,
3139       qPrint(def)
3140               );
3141
3142   // add member to the global list of all members
3143   MemberName *mn;
3144   if ((mn=Doxygen::memberNameSDict->find(rname)))
3145   {
3146     mn->append(md);
3147   }
3148   else
3149   {
3150     mn = new MemberName(rname);
3151     mn->append(md);
3152     Doxygen::memberNameSDict->append(rname,mn);
3153   }
3154
3155   // add member to the class cd
3156   cd->insertMember(md);
3157   // also add the member as a "base" (to get nicer diagrams)
3158   // "optional" interface/service get Protected which turns into dashed line
3159   BaseInfo base(rname,
3160           (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3161   findClassRelation(rootNav,cd,cd,&base,0,DocumentedOnly,true)
3162   || findClassRelation(rootNav,cd,cd,&base,0,Undocumented,true);
3163   // add file to list of used files
3164   cd->insertUsedFile(fd);
3165
3166   addMemberToGroups(root,md);
3167   rootNav->changeSection(Entry::EMPTY_SEC);
3168   md->setRefItems(root->sli);
3169 }
3170
3171 static void buildInterfaceAndServiceList(EntryNav *const rootNav)
3172 {
3173   if (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
3174       rootNav->section()==Entry::INCLUDED_SERVICE_SEC)
3175   {
3176     rootNav->loadEntry(g_storage);
3177     Entry *const root = rootNav->entry();
3178
3179     Debug::print(Debug::Functions,0,
3180                  "EXPORTED_INTERFACE_SEC:\n"
3181                  "  `%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",
3182                  qPrint(root->type),
3183                  qPrint(rootNav->parent()->name()),
3184                  qPrint(root->name),
3185                  qPrint(root->args),
3186                  qPrint(root->relates),
3187                  root->relatesType,
3188                  qPrint(root->fileName),
3189                  root->startLine,
3190                  root->bodyLine,
3191                  root->tArgLists ? (int)root->tArgLists->count() : -1,
3192                  root->mGrpId,
3193                  root->spec,
3194                  root->proto,
3195                  qPrint(root->docFile)
3196                 );
3197
3198     QCString const rname = removeRedundantWhiteSpace(root->name);
3199
3200     if (!rname.isEmpty())
3201     {
3202       QCString const scope = rootNav->parent()->name();
3203       ClassDef *const cd = getClass(scope);
3204       assert(cd);
3205       if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3206                  (ClassDef::Service   == cd->compoundType()) ||
3207                  (ClassDef::Singleton == cd->compoundType())))
3208       {
3209         addInterfaceOrServiceToServiceOrSingleton(rootNav,cd,rname);
3210       }
3211       else
3212       {
3213         assert(false); // was checked by scanner.l
3214       }
3215     }
3216     else if (rname.isEmpty())
3217     {
3218       warn(root->fileName,root->startLine,
3219            "Illegal member name found.");
3220     }
3221
3222     rootNav->releaseEntry();
3223   }
3224   // can only have these in IDL anyway
3225   switch (rootNav->lang())
3226   {
3227     case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3228     case SrcLangExt_IDL:
3229         RECURSE_ENTRYTREE(buildInterfaceAndServiceList,rootNav);
3230         break;
3231     default:
3232         return; // nothing to do here
3233   }
3234 }
3235
3236
3237 //----------------------------------------------------------------------
3238 // Searches the Entry tree for Function sections.
3239 // If found they are stored in their class or in the global list.
3240
3241 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
3242                   const QCString &rname,bool isFriend)
3243 {
3244   Entry *root = rootNav->entry();
3245   FileDef *fd=rootNav->fileDef();
3246
3247   int l;
3248   static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3249   int ts=root->type.find('<');
3250   int te=root->type.findRev('>');
3251   int i=re.match(root->type,0,&l);
3252   if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
3253   {
3254     i=-1;
3255   }
3256
3257   if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3258       !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3259   {
3260     root->args+=root->type.right(root->type.length()-i-l);
3261     root->type=root->type.left(i+l);
3262   }
3263
3264   QCString name=removeRedundantWhiteSpace(rname);
3265   if (name.left(2)=="::") name=name.right(name.length()-2);
3266
3267   MemberType mtype;
3268   if (isFriend)                 mtype=MemberType_Friend;
3269   else if (root->mtype==Signal) mtype=MemberType_Signal;
3270   else if (root->mtype==Slot)   mtype=MemberType_Slot;
3271   else if (root->mtype==DCOP)   mtype=MemberType_DCOP;
3272   else                          mtype=MemberType_Function;
3273
3274   // strip redundant template specifier for constructors
3275   if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3276      name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3277   {
3278     name=name.left(i);
3279   }
3280
3281   QCString fileName = root->fileName;
3282   if (fileName.isEmpty() && rootNav->tagInfo())
3283   {
3284     fileName = rootNav->tagInfo()->tagName;
3285   }
3286
3287   //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
3288   //    root->name.data(),root->args.data(),argListToString(root->argList).data()
3289   //   );
3290
3291   // adding class member
3292   MemberDef *md=new MemberDef(
3293       fileName,root->startLine,root->startColumn,
3294       root->type,name,root->args,root->exception,
3295       root->protection,root->virt,
3296       root->stat && root->relatesType != MemberOf,
3297       root->relates.isEmpty() ? Member :
3298           root->relatesType == MemberOf ? Foreign : Related,
3299       mtype,root->tArgLists ? root->tArgLists->getLast() : 0,root->argList);
3300   md->setTagInfo(rootNav->tagInfo());
3301   md->setMemberClass(cd);
3302   md->setDocumentation(root->doc,root->docFile,root->docLine);
3303   md->setDocsForDefinition(!root->proto);
3304   md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3305   md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3306   md->setBodySegment(root->bodyLine,root->endBodyLine);
3307   md->setMemberSpecifiers(root->spec);
3308   md->setMemberGroupId(root->mGrpId);
3309   md->setTypeConstraints(root->typeConstr);
3310   md->setLanguage(root->lang);
3311   md->setId(root->id);
3312   md->setBodyDef(fd);
3313   md->setFileDef(fd);
3314   //md->setScopeTemplateArguments(root->tArgList);
3315   md->addSectionsToDefinition(root->anchors);
3316   QCString def;
3317   QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3318   SrcLangExt lang = cd->getLanguage();
3319   QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3320   if (scopeSeparator!="::")
3321   {
3322     qualScope = substitute(qualScope,"::",scopeSeparator);
3323   }
3324   if (lang==SrcLangExt_PHP)
3325   {
3326     // for PHP we use Class::method and Namespace\method
3327     scopeSeparator="::";
3328   }
3329   if (!root->relates.isEmpty() || isFriend || Config_getBool(HIDE_SCOPE_NAMES))
3330   {
3331     if (!root->type.isEmpty())
3332     {
3333       if (root->argList)
3334       {
3335         def=root->type+" "+name;
3336       }
3337       else
3338       {
3339         def=root->type+" "+name+root->args;
3340       }
3341     }
3342     else
3343     {
3344       if (root->argList)
3345       {
3346         def=name;
3347       }
3348       else
3349       {
3350         def=name+root->args;
3351       }
3352     }
3353   }
3354   else
3355   {
3356     if (!root->type.isEmpty())
3357     {
3358       if (root->argList)
3359       {
3360         def=root->type+" "+qualScope+scopeSeparator+name;
3361       }
3362       else
3363       {
3364         def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3365       }
3366     }
3367     else
3368     {
3369       if (root->argList)
3370       {
3371         def=qualScope+scopeSeparator+name;
3372       }
3373       else
3374       {
3375         def=qualScope+scopeSeparator+name+root->args;
3376       }
3377     }
3378   }
3379   if (def.left(7)=="friend ") def=def.right(def.length()-7);
3380   md->setDefinition(def);
3381   md->enableCallGraph(root->callGraph);
3382   md->enableCallerGraph(root->callerGraph);
3383
3384   Debug::print(Debug::Functions,0,
3385       "  Func Member:\n"
3386       "    `%s' `%s'::`%s' `%s' proto=%d\n"
3387       "    def=`%s'\n",
3388       qPrint(root->type),
3389       qPrint(qualScope),
3390       qPrint(rname),
3391       qPrint(root->args),
3392       root->proto,
3393       qPrint(def)
3394               );
3395
3396   // add member to the global list of all members
3397   //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3398   MemberName *mn;
3399   if ((mn=Doxygen::memberNameSDict->find(name)))
3400   {
3401     mn->append(md);
3402   }
3403   else
3404   {
3405     mn = new MemberName(name);
3406     mn->append(md);
3407     Doxygen::memberNameSDict->append(name,mn);
3408   }
3409
3410   // add member to the class cd
3411   cd->insertMember(md);
3412   // add file to list of used files
3413   cd->insertUsedFile(fd);
3414
3415   addMemberToGroups(root,md);
3416   rootNav->changeSection(Entry::EMPTY_SEC);
3417   md->setRefItems(root->sli);
3418 }
3419
3420
3421 static void buildFunctionList(EntryNav *rootNav)
3422 {
3423   if (rootNav->section()==Entry::FUNCTION_SEC)
3424   {
3425     rootNav->loadEntry(g_storage);
3426     Entry *root = rootNav->entry();
3427
3428     Debug::print(Debug::Functions,0,
3429                  "FUNCTION_SEC:\n"
3430                  "  `%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",
3431                  qPrint(root->type),
3432                  qPrint(rootNav->parent()->name()),
3433                  qPrint(root->name),
3434                  qPrint(root->args),
3435                  qPrint(root->relates),
3436                  root->relatesType,
3437                  qPrint(root->fileName),
3438                  root->startLine,
3439                  root->bodyLine,
3440                  root->tArgLists ? (int)root->tArgLists->count() : -1,
3441                  root->mGrpId,
3442                  root->spec,
3443                  root->proto,
3444                  qPrint(root->docFile)
3445                 );
3446
3447     bool isFriend=root->type.find("friend ")!=-1;
3448     QCString rname = removeRedundantWhiteSpace(root->name);
3449     //printf("rname=%s\n",rname.data());
3450
3451     QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3452     if (!rname.isEmpty() && scope.find('@')==-1)
3453     {
3454       ClassDef *cd=0;
3455       // check if this function's parent is a class
3456       scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3457
3458       FileDef *rfd=rootNav->fileDef();
3459
3460       int memIndex=rname.findRev("::");
3461
3462       cd=getClass(scope);
3463       if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3464       {
3465         // strip scope from name
3466         rname=rname.right(rname.length()-rootNav->parent()->name().length()-2);
3467       }
3468
3469       NamespaceDef *nd = 0;
3470       bool isMember=FALSE;
3471       if (memIndex!=-1)
3472       {
3473         int ts=rname.find('<');
3474         int te=rname.find('>');
3475         if (memIndex>0 && (ts==-1 || te==-1))
3476         {
3477           // note: the following code was replaced by inMember=TRUE to deal with a
3478           // function rname='X::foo' of class X inside a namespace also called X...
3479           // bug id 548175
3480           //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3481           //isMember = nd==0;
3482           //if (nd)
3483           //{
3484           //  // strip namespace scope from name
3485           //  scope=rname.left(memIndex);
3486           //  rname=rname.right(rname.length()-memIndex-2);
3487           //}
3488           isMember = TRUE;
3489         }
3490         else
3491         {
3492           isMember=memIndex<ts || memIndex>te;
3493         }
3494       }
3495
3496       static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3497       int ts=root->type.find('<');
3498       int te=root->type.findRev('>');
3499       int ti;
3500       if (!rootNav->parent()->name().isEmpty() &&
3501           (rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
3502           cd &&
3503           // do some fuzzy things to exclude function pointers
3504           (root->type.isEmpty() ||
3505            ((ti=root->type.find(re,0))==-1 ||      // type does not contain ..(..*
3506             (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3507            root->args.find(")[")!=-1) ||           // and args not )[.. -> function pointer
3508            root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3509            cd->getLanguage()!=SrcLangExt_Cpp                               // language other than C
3510           )
3511          )
3512       {
3513         Debug::print(Debug::Functions,0,"  --> member %s of class %s!\n",
3514             qPrint(rname),qPrint(cd->name()));
3515         addMethodToClass(rootNav,cd,rname,isFriend);
3516       }
3517       else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK)
3518                  || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3519                 ) &&
3520                !isMember &&
3521                (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3522                root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3523               )
3524       // no member => unrelated function
3525       {
3526         /* check the uniqueness of the function name in the file.
3527          * A file could contain a function prototype and a function definition
3528          * or even multiple function prototypes.
3529          */
3530         bool found=FALSE;
3531         MemberName *mn;
3532         MemberDef *md=0;
3533         if ((mn=Doxygen::functionNameSDict->find(rname)))
3534         {
3535           Debug::print(Debug::Functions,0,"  --> function %s already found!\n",qPrint(rname));
3536           MemberNameIterator mni(*mn);
3537           for (mni.toFirst();(!found && (md=mni.current()));++mni)
3538           {
3539             NamespaceDef *mnd = md->getNamespaceDef();
3540             NamespaceDef *rnd = 0;
3541             //printf("root namespace=%s\n",rootNav->parent()->name().data());
3542             QCString fullScope = scope;
3543             QCString parentScope = rootNav->parent()->name();
3544             if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3545             {
3546               if (!scope.isEmpty()) fullScope.prepend("::");
3547               fullScope.prepend(parentScope);
3548             }
3549             //printf("fullScope=%s\n",fullScope.data());
3550             rnd = getResolvedNamespace(fullScope);
3551             FileDef *mfd = md->getFileDef();
3552             QCString nsName,rnsName;
3553             if (mnd)  nsName = mnd->name().copy();
3554             if (rnd) rnsName = rnd->name().copy();
3555             //printf("matching arguments for %s%s %s%s\n",
3556             //    md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3557             ArgumentList *mdAl = md->argumentList();
3558             ArgumentList *mdTempl = md->templateArguments();
3559
3560             // in case of template functions, we need to check if the
3561             // functions have the same number of template parameters
3562             bool sameNumTemplateArgs = TRUE;
3563             bool matchingReturnTypes = TRUE;
3564             if (mdTempl!=0 && root->tArgLists)
3565             {
3566               if (mdTempl->count()!=root->tArgLists->getLast()->count())
3567               {
3568                 sameNumTemplateArgs = FALSE;
3569               }
3570               if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3571               {
3572                 matchingReturnTypes = FALSE;
3573               }
3574             }
3575
3576             bool staticsInDifferentFiles =
3577                     root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3578
3579             if (
3580                 matchArguments2(md->getOuterScope(),mfd,mdAl,
3581                                 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3582                                 FALSE) &&
3583                 sameNumTemplateArgs &&
3584                 matchingReturnTypes &&
3585                 !staticsInDifferentFiles
3586                )
3587             {
3588               GroupDef *gd=0;
3589               if (root->groups->getFirst()!=0)
3590               {
3591                 gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
3592               }
3593               //printf("match!\n");
3594               //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3595               // see if we need to create a new member
3596               found=(mnd && rnd && nsName==rnsName) ||   // members are in the same namespace
3597                     ((mnd==0 && rnd==0 && mfd!=0 &&       // no external reference and
3598                       mfd->absFilePath()==root->fileName // prototype in the same file
3599                      )
3600                     );
3601               // otherwise, allow a duplicate global member with the same argument list
3602               if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3603               {
3604                 // member is already in the group, so we don't want to add it again.
3605                 found=TRUE;
3606               }
3607
3608               //printf("combining function with prototype found=%d in namespace %s\n",
3609               //    found,nsName.data());
3610
3611               if (found)
3612               {
3613                 // merge argument lists
3614                 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
3615                 // merge documentation
3616                 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3617                 {
3618                   ArgumentList *argList = new ArgumentList;
3619                   stringToArgumentList(root->args,argList);
3620                   if (root->proto)
3621                   {
3622                     //printf("setDeclArgumentList to %p\n",argList);
3623                     md->setDeclArgumentList(argList);
3624                   }
3625                   else
3626                   {
3627                     md->setArgumentList(argList);
3628                   }
3629                 }
3630
3631                 md->setDocumentation(root->doc,root->docFile,root->docLine);
3632                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3633                 md->setDocsForDefinition(!root->proto);
3634                 if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3635                 {
3636                   md->setBodySegment(root->bodyLine,root->endBodyLine);
3637                   md->setBodyDef(rfd);
3638                 }
3639
3640                 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3641                 {
3642                   md->setArgsString(root->args);
3643                 }
3644                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3645
3646                 md->addSectionsToDefinition(root->anchors);
3647
3648                 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3649                 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3650
3651                 // merge ingroup specifiers
3652                 if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
3653                 {
3654                   addMemberToGroups(root,md);
3655                 }
3656                 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3657                 {
3658                   //printf("existing member is grouped, new member not\n");
3659                   root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3660                 }
3661                 else if (md->getGroupDef()!=0 && root->groups->getFirst()!=0)
3662                 {
3663                   //printf("both members are grouped\n");
3664                 }
3665
3666                 // if md is a declaration and root is the corresponding
3667                 // definition, then turn md into a definition.
3668                 if (md->isPrototype() && !root->proto)
3669                 {
3670                   md->setPrototype(FALSE);
3671                 }
3672               }
3673             }
3674           }
3675         }
3676         if (!found) /* global function is unique with respect to the file */
3677         {
3678           Debug::print(Debug::Functions,0,"  --> new function %s found!\n",qPrint(rname));
3679           //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3680           //       root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3681
3682           // new global function
3683           ArgumentList *tArgList = root->tArgLists ? root->tArgLists->getLast() : 0;
3684           QCString name=removeRedundantWhiteSpace(rname);
3685           md=new MemberDef(
3686               root->fileName,root->startLine,root->startColumn,
3687               root->type,name,root->args,root->exception,
3688               root->protection,root->virt,root->stat,Member,
3689               MemberType_Function,tArgList,root->argList);
3690
3691           md->setTagInfo(rootNav->tagInfo());
3692           md->setLanguage(root->lang);
3693           md->setId(root->id);
3694           //md->setDefFile(root->fileName);
3695           //md->setDefLine(root->startLine);
3696           md->setDocumentation(root->doc,root->docFile,root->docLine);
3697           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3698           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3699           md->setPrototype(root->proto);
3700           md->setDocsForDefinition(!root->proto);
3701           md->setTypeConstraints(root->typeConstr);
3702           //md->setBody(root->body);
3703           md->setBodySegment(root->bodyLine,root->endBodyLine);
3704           FileDef *fd=rootNav->fileDef();
3705           md->setBodyDef(fd);
3706           md->addSectionsToDefinition(root->anchors);
3707           md->setMemberSpecifiers(root->spec);
3708           md->setMemberGroupId(root->mGrpId);
3709
3710           // see if the function is inside a namespace that was not part of
3711           // the name already (in that case nd should be non-zero already)
3712           if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3713           {
3714             //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3715             QCString nscope=rootNav->parent()->name();
3716             if (!nscope.isEmpty())
3717             {
3718               nd = getResolvedNamespace(nscope);
3719             }
3720           }
3721
3722           if (!scope.isEmpty())
3723           {
3724             QCString sep = getLanguageSpecificSeparator(root->lang);
3725             if (sep!="::")
3726             {
3727               scope = substitute(scope,"::",sep);
3728             }
3729             scope+=sep;
3730           }
3731
3732           QCString def;
3733           if (!root->type.isEmpty())
3734           {
3735             if (root->argList)
3736             {
3737               def=root->type+" "+scope+name;
3738             }
3739             else
3740             {
3741               def=root->type+" "+scope+name+root->args;
3742             }
3743           }
3744           else
3745           {
3746             if (root->argList)
3747             {
3748               def=scope+name.copy();
3749             }
3750             else
3751             {
3752               def=scope+name+root->args;
3753             }
3754           }
3755           Debug::print(Debug::Functions,0,
3756                      "  Global Function:\n"
3757                      "    `%s' `%s'::`%s' `%s' proto=%d\n"
3758                      "    def=`%s'\n",
3759                      qPrint(root->type),
3760                      qPrint(rootNav->parent()->name()),
3761                      qPrint(rname),
3762                      qPrint(root->args),
3763                      root->proto,
3764                      qPrint(def)
3765                     );
3766           md->setDefinition(def);
3767           md->enableCallGraph(root->callGraph);
3768           md->enableCallerGraph(root->callerGraph);
3769           //if (root->mGrpId!=-1)
3770           //{
3771           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
3772           //}
3773
3774           md->setRefItems(root->sli);
3775           if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3776           {
3777             // add member to namespace
3778             md->setNamespace(nd);
3779             nd->insertMember(md);
3780           }
3781           if (fd)
3782           {
3783             // add member to the file (we do this even if we have already
3784             // inserted it into the namespace)
3785             md->setFileDef(fd);
3786             fd->insertMember(md);
3787           }
3788
3789           // add member to the list of file members
3790           //printf("Adding member=%s\n",md->name().data());
3791           MemberName *mn;
3792           if ((mn=Doxygen::functionNameSDict->find(name)))
3793           {
3794             mn->append(md);
3795           }
3796           else
3797           {
3798             mn = new MemberName(name);
3799             mn->append(md);
3800             Doxygen::functionNameSDict->append(name,mn);
3801           }
3802           addMemberToGroups(root,md);
3803           if (root->relatesType == Simple) // if this is a relatesalso command,
3804                                            // allow find Member to pick it up
3805           {
3806             rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished
3807                                                       // with this entry.
3808
3809           }
3810         }
3811         else
3812         {
3813           FileDef *fd=rootNav->fileDef();
3814           if (fd)
3815           {
3816             // add member to the file (we do this even if we have already
3817             // inserted it into the namespace)
3818             fd->insertMember(md);
3819           }
3820         }
3821
3822         //printf("unrelated function %d `%s' `%s' `%s'\n",
3823         //    root->parent->section,root->type.data(),rname.data(),root->args.data());
3824       }
3825       else
3826       {
3827           Debug::print(Debug::Functions,0,"  --> %s not processed!\n",qPrint(rname));
3828       }
3829     }
3830     else if (rname.isEmpty())
3831     {
3832         warn(root->fileName,root->startLine,
3833              "Illegal member name found."
3834             );
3835     }
3836
3837     rootNav->releaseEntry();
3838   }
3839   RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3840 }
3841
3842 //----------------------------------------------------------------------
3843
3844 static void findFriends()
3845 {
3846   //printf("findFriends()\n");
3847   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3848   MemberName *fn;
3849   for (;(fn=fnli.current());++fnli) // for each global function name
3850   {
3851     //printf("Function name=`%s'\n",fn->memberName());
3852     MemberName *mn;
3853     if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3854     { // there are members with the same name
3855       //printf("Function name is also a member name\n");
3856       MemberNameIterator fni(*fn);
3857       MemberDef *fmd;
3858       for (;(fmd=fni.current());++fni) // for each function with that name
3859       {
3860         MemberNameIterator mni(*mn);
3861         MemberDef *mmd;
3862         for (;(mmd=mni.current());++mni) // for each member with that name
3863         {
3864           //printf("Checking for matching arguments
3865           //        mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3866           //    mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3867           ArgumentList *mmdAl = mmd->argumentList();
3868           ArgumentList *fmdAl = fmd->argumentList();
3869           if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3870               matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl,
3871                               fmd->getOuterScope(), fmd->getFileDef(), fmdAl,
3872                               TRUE
3873                              )
3874
3875              ) // if the member is related and the arguments match then the
3876                // function is actually a friend.
3877           {
3878             mergeArguments(mmdAl,fmdAl);
3879             if (!fmd->documentation().isEmpty())
3880             {
3881               mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3882             }
3883             else if (!mmd->documentation().isEmpty())
3884             {
3885               fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3886             }
3887             if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3888             {
3889               mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3890             }
3891             else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3892             {
3893               fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3894             }
3895             if (!fmd->inbodyDocumentation().isEmpty())
3896             {
3897               mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3898             }
3899             else if (!mmd->inbodyDocumentation().isEmpty())
3900             {
3901               fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3902             }
3903             //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3904             if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3905             {
3906               mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3907               mmd->setBodyDef(fmd->getBodyDef());
3908               //mmd->setBodyMember(fmd);
3909             }
3910             else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3911             {
3912               fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3913               fmd->setBodyDef(mmd->getBodyDef());
3914               //fmd->setBodyMember(mmd);
3915             }
3916             mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3917
3918             mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3919             mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3920             fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3921             fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3922           }
3923         }
3924       }
3925     }
3926   }
3927 }
3928
3929 //----------------------------------------------------------------------
3930
3931 static void transferFunctionDocumentation()
3932 {
3933   //printf("---- transferFunctionDocumentation()\n");
3934
3935   // find matching function declaration and definitions.
3936   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3937   MemberName *mn;
3938   for (;(mn=mnli.current());++mnli)
3939   {
3940     //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3941     MemberDef *mdef=0,*mdec=0;
3942     MemberNameIterator mni1(*mn);
3943     /* find a matching function declaration and definition for this function */
3944     for (;(mdec=mni1.current());++mni1)
3945     {
3946       if (mdec->isPrototype() ||
3947           (mdec->isVariable() && mdec->isExternal())
3948          )
3949       {
3950         MemberNameIterator mni2(*mn);
3951         for (;(mdef=mni2.current());++mni2)
3952         {
3953           combineDeclarationAndDefinition(mdec,mdef);
3954         }
3955       }
3956     }
3957   }
3958 }
3959
3960 //----------------------------------------------------------------------
3961
3962 static void transferFunctionReferences()
3963 {
3964   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3965   MemberName *mn;
3966   for (;(mn=mnli.current());++mnli)
3967   {
3968     MemberDef *md,*mdef=0,*mdec=0;
3969     MemberNameIterator mni(*mn);
3970     /* find a matching function declaration and definition for this function */
3971     for (;(md=mni.current());++mni)
3972     {
3973       if (md->isPrototype())
3974         mdec=md;
3975       else if (md->isVariable() && md->isExternal())
3976         mdec=md;
3977
3978       if (md->isFunction() && !md->isStatic() && !md->isPrototype())
3979         mdef=md;
3980       else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3981         mdef=md;
3982     }
3983     if (mdef && mdec)
3984     {
3985       ArgumentList *mdefAl = mdef->argumentList();
3986       ArgumentList *mdecAl = mdec->argumentList();
3987       if (
3988           matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
3989                           mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
3990                           TRUE
3991             )
3992          ) /* match found */
3993       {
3994         MemberSDict *defDict = mdef->getReferencesMembers();
3995         MemberSDict *decDict = mdec->getReferencesMembers();
3996         if (defDict!=0)
3997         {
3998           MemberSDict::IteratorDict msdi(*defDict);
3999           MemberDef *rmd;
4000           for (msdi.toFirst();(rmd=msdi.current());++msdi)
4001           {
4002             if (decDict==0 || decDict->find(rmd->name())==0)
4003             {
4004               mdec->addSourceReferences(rmd);
4005             }
4006           }
4007         }
4008         if (decDict!=0)
4009         {
4010           MemberSDict::IteratorDict msdi(*decDict);
4011           MemberDef *rmd;
4012           for (msdi.toFirst();(rmd=msdi.current());++msdi)
4013           {
4014             if (defDict==0 || defDict->find(rmd->name())==0)
4015             {
4016               mdef->addSourceReferences(rmd);
4017             }
4018           }
4019         }
4020
4021         defDict = mdef->getReferencedByMembers();
4022         decDict = mdec->getReferencedByMembers();
4023         if (defDict!=0)
4024         {
4025           MemberSDict::IteratorDict msdi(*defDict);
4026           MemberDef *rmd;
4027           for (msdi.toFirst();(rmd=msdi.current());++msdi)
4028           {
4029             if (decDict==0 || decDict->find(rmd->name())==0)
4030             {
4031               mdec->addSourceReferencedBy(rmd);
4032             }
4033           }
4034         }
4035         if (decDict!=0)
4036         {
4037           MemberSDict::IteratorDict msdi(*decDict);
4038           MemberDef *rmd;
4039           for (msdi.toFirst();(rmd=msdi.current());++msdi)
4040           {
4041             if (defDict==0 || defDict->find(rmd->name())==0)
4042             {
4043               mdef->addSourceReferencedBy(rmd);
4044             }
4045           }
4046         }
4047       }
4048     }
4049   }
4050 }
4051
4052 //----------------------------------------------------------------------
4053
4054 static void transferRelatedFunctionDocumentation()
4055 {
4056   // find match between function declaration and definition for
4057   // related functions
4058   MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4059   MemberName *mn;
4060   for (mnli.toFirst();(mn=mnli.current());++mnli)
4061   {
4062     MemberDef *md;
4063     MemberNameIterator mni(*mn);
4064     /* find a matching function declaration and definition for this function */
4065     for (mni.toFirst();(md=mni.current());++mni) // for each global function
4066     {
4067       //printf("  Function `%s'\n",md->name().data());
4068       MemberName *rmn;
4069       if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
4070       {
4071         //printf("  Member name found\n");
4072         MemberDef *rmd;
4073         MemberNameIterator rmni(*rmn);
4074         for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
4075         {
4076           ArgumentList *mdAl = md->argumentList();
4077           ArgumentList *rmdAl = rmd->argumentList();
4078           //printf("  Member found: related=`%d'\n",rmd->isRelated());
4079           if ((rmd->isRelated() || rmd->isForeign()) && // related function
4080               matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4081                               rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
4082                               TRUE
4083                              )
4084              )
4085           {
4086             //printf("  Found related member `%s'\n",md->name().data());
4087             if (rmd->relatedAlso())
4088               md->setRelatedAlso(rmd->relatedAlso());
4089             else if (rmd->isForeign())
4090               md->makeForeign();
4091             else
4092               md->makeRelated();
4093           }
4094         }
4095       }
4096     }
4097   }
4098 }
4099
4100 //----------------------------------------------------------------------
4101
4102 /*! make a dictionary of all template arguments of class cd
4103  * that are part of the base class name.
4104  * Example: A template class A with template arguments <R,S,T>
4105  * that inherits from B<T,T,S> will have T and S in the dictionary.
4106  */
4107 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
4108 {
4109   QDict<int> *templateNames = new QDict<int>(17);
4110   templateNames->setAutoDelete(TRUE);
4111   static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
4112   if (templateArguments)
4113   {
4114     ArgumentListIterator ali(*templateArguments);
4115     Argument *arg;
4116     int count=0;
4117     for (ali.toFirst();(arg=ali.current());++ali,count++)
4118     {
4119       int i,p=0,l;
4120       while ((i=re.match(name,p,&l))!=-1)
4121       {
4122         QCString n = name.mid(i,l);
4123         if (n==arg->name)
4124         {
4125           if (templateNames->find(n)==0)
4126           {
4127             templateNames->insert(n,new int(count));
4128           }
4129         }
4130         p=i+l;
4131       }
4132     }
4133   }
4134   return templateNames;
4135 }
4136
4137 /*! Searches a class from within \a context and \a cd and returns its
4138  *  definition if found (otherwise 0 is returned).
4139  */
4140 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
4141 {
4142   ClassDef *result=0;
4143   if (cd==0)
4144   {
4145     return result;
4146   }
4147   FileDef *fd=cd->getFileDef();
4148   if (context && cd!=context)
4149   {
4150     result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
4151   }
4152   if (result==0)
4153   {
4154     result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
4155   }
4156   if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4157   {
4158     result = getClass(name);
4159   }
4160   if (result==0 &&
4161       (cd->getLanguage()==SrcLangExt_CSharp || cd->getLanguage()==SrcLangExt_Java) &&
4162       name.find('<')!=-1)
4163   {
4164     result = Doxygen::genericsDict->find(name);
4165   }
4166   //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4167   //       name.data(),
4168   //       context ? context->name().data() : "<none>",
4169   //       cd      ? cd->name().data()      : "<none>",
4170   //       result  ? result->name().data()  : "<none>",
4171   //       Doxygen::classSDict->find(name)
4172   //      );
4173   return result;
4174 }
4175
4176
4177 static void findUsedClassesForClass(EntryNav *rootNav,
4178                            Definition *context,
4179                            ClassDef *masterCd,
4180                            ClassDef *instanceCd,
4181                            bool isArtificial,
4182                            ArgumentList *actualArgs=0,
4183                            QDict<int> *templateNames=0
4184                            )
4185 {
4186   masterCd->visited=TRUE;
4187   ArgumentList *formalArgs = masterCd->templateArguments();
4188   if (masterCd->memberNameInfoSDict())
4189   {
4190     MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
4191     MemberNameInfo *mni;
4192     for (;(mni=mnili.current());++mnili)
4193     {
4194       MemberNameInfoIterator mnii(*mni);
4195       MemberInfo *mi;
4196       for (mnii.toFirst();(mi=mnii.current());++mnii)
4197       {
4198         MemberDef *md=mi->memberDef;
4199         if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4200         {
4201           //printf("    Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
4202           QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4203           QCString typedefValue = resolveTypeDef(masterCd,type);
4204           if (!typedefValue.isEmpty())
4205           {
4206             type = typedefValue;
4207           }
4208           int pos=0;
4209           QCString usedClassName;
4210           QCString templSpec;
4211           bool found=FALSE;
4212           // the type can contain template variables, replace them if present
4213           if (actualArgs)
4214           {
4215             type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4216           }
4217
4218           //printf("      template substitution gives=%s\n",type.data());
4219           while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
4220           {
4221             // find the type (if any) that matches usedClassName
4222             ClassDef *typeCd = getResolvedClass(masterCd,
4223                 masterCd->getFileDef(),
4224                 usedClassName,
4225                 0,0,
4226                 FALSE,TRUE
4227                 );
4228             //printf("====>  usedClassName=%s -> typeCd=%s\n",
4229             //     usedClassName.data(),typeCd?typeCd->name().data():"<none>");
4230             if (typeCd)
4231             {
4232               usedClassName = typeCd->name();
4233             }
4234
4235             int sp=usedClassName.find('<');
4236             if (sp==-1) sp=0;
4237             int si=usedClassName.findRev("::",sp);
4238             if (si!=-1)
4239             {
4240               // replace any namespace aliases
4241               replaceNamespaceAliases(usedClassName,si);
4242             }
4243             // add any template arguments to the class
4244             QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4245             //printf("    usedName=%s\n",usedName.data());
4246
4247             bool delTempNames=FALSE;
4248             if (templateNames==0)
4249             {
4250               templateNames = getTemplateArgumentsInName(formalArgs,usedName);
4251               delTempNames=TRUE;
4252             }
4253             BaseInfo bi(usedName,Public,Normal);
4254             findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
4255
4256             if (masterCd->templateArguments())
4257             {
4258               ArgumentListIterator ali(*masterCd->templateArguments());
4259               Argument *arg;
4260               int count=0;
4261               for (ali.toFirst();(arg=ali.current());++ali,++count)
4262               {
4263                 if (arg->name==usedName) // type is a template argument
4264                 {
4265                   found=TRUE;
4266                   Debug::print(Debug::Classes,0,"    New used class `%s'\n", qPrint(usedName));
4267
4268                   ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
4269                   if (usedCd==0)
4270                   {
4271                     usedCd = new ClassDef(
4272                         masterCd->getDefFileName(),masterCd->getDefLine(),
4273                         masterCd->getDefColumn(),
4274                         usedName,
4275                         ClassDef::Class);
4276                     //printf("making %s a template argument!!!\n",usedCd->name().data());
4277                     usedCd->makeTemplateArgument();
4278                     usedCd->setUsedOnly(TRUE);
4279                     usedCd->setLanguage(masterCd->getLanguage());
4280                     Doxygen::hiddenClasses->append(usedName,usedCd);
4281                   }
4282                   if (isArtificial) usedCd->setArtificial(TRUE);
4283                   Debug::print(Debug::Classes,0,"      Adding used class `%s' (1)\n", qPrint(usedCd->name()));
4284                   instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4285                   usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4286                 }
4287               }
4288             }
4289
4290             if (!found)
4291             {
4292               ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4293               //printf("Looking for used class %s: result=%s master=%s\n",
4294               //    usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
4295
4296               if (usedCd)
4297               {
4298                 found=TRUE;
4299                 Debug::print(Debug::Classes,0,"    Adding used class `%s' (2)\n", qPrint(usedCd->name()));
4300                 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
4301                 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4302               }
4303             }
4304             if (delTempNames)
4305             {
4306               delete templateNames;
4307               templateNames=0;
4308             }
4309           }
4310           if (!found && !type.isEmpty()) // used class is not documented in any scope
4311           {
4312             ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4313             if (usedCd==0 && !Config_getBool(HIDE_UNDOC_RELATIONS))
4314             {
4315               if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4316               {
4317                 type+=md->argsString();
4318               }
4319               Debug::print(Debug::Classes,0,"  New undocumented used class `%s'\n", qPrint(type));
4320               usedCd = new ClassDef(
4321                   masterCd->getDefFileName(),masterCd->getDefLine(),
4322                   masterCd->getDefColumn(),
4323                   type,ClassDef::Class);
4324               usedCd->setUsedOnly(TRUE);
4325               usedCd->setLanguage(masterCd->getLanguage());
4326               Doxygen::hiddenClasses->append(type,usedCd);
4327             }
4328             if (usedCd)
4329             {
4330               if (isArtificial) usedCd->setArtificial(TRUE);
4331               Debug::print(Debug::Classes,0,"    Adding used class `%s' (3)\n", qPrint(usedCd->name()));
4332               instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4333               usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4334             }
4335           }
4336         }
4337       }
4338     }
4339   }
4340   else
4341   {
4342     //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4343   }
4344 }
4345
4346 static void findBaseClassesForClass(
4347       EntryNav *rootNav,
4348       Definition *context,
4349       ClassDef *masterCd,
4350       ClassDef *instanceCd,
4351       FindBaseClassRelation_Mode mode,
4352       bool isArtificial,
4353       ArgumentList *actualArgs=0,
4354       QDict<int> *templateNames=0
4355     )
4356 {
4357   Entry *root = rootNav->entry();
4358   //if (masterCd->visited) return;
4359   masterCd->visited=TRUE;
4360   // The base class could ofcouse also be a non-nested class
4361   ArgumentList *formalArgs = masterCd->templateArguments();
4362   QListIterator<BaseInfo> bii(*root->extends);
4363   BaseInfo *bi=0;
4364   for (bii.toFirst();(bi=bii.current());++bii)
4365   {
4366     //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4367     //    masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4368     bool delTempNames=FALSE;
4369     if (templateNames==0)
4370     {
4371       templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4372       delTempNames=TRUE;
4373     }
4374     BaseInfo tbi(bi->name,bi->prot,bi->virt);
4375     if (actualArgs) // substitute the formal template arguments of the base class
4376     {
4377       tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4378     }
4379     //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4380
4381     if (mode==DocumentedOnly)
4382     {
4383       // find a documented base class in the correct scope
4384       if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4385       {
4386         // 1.8.2: decided to show inheritance relations even if not documented,
4387         //        we do make them artificial, so they do not appear in the index
4388         //if (!Config_getBool(HIDE_UNDOC_RELATIONS))
4389         bool b = Config_getBool(HIDE_UNDOC_RELATIONS) ? TRUE : isArtificial;
4390         //{
4391           // no documented base class -> try to find an undocumented one
4392           findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4393         //}
4394       }
4395     }
4396     else if (mode==TemplateInstances)
4397     {
4398       findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4399     }
4400     if (delTempNames)
4401     {
4402       delete templateNames;
4403       templateNames=0;
4404     }
4405   }
4406 }
4407
4408 //----------------------------------------------------------------------
4409
4410 static bool findTemplateInstanceRelation(Entry *root,
4411             Definition *context,
4412             ClassDef *templateClass,const QCString &templSpec,
4413             QDict<int> *templateNames,
4414             bool isArtificial)
4415 {
4416   Debug::print(Debug::Classes,0,"    derived from template %s with parameters %s\n",
4417          qPrint(templateClass->name()),qPrint(templSpec));
4418   //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4419   //    templateClass->name().data(),templSpec.data());
4420   //if (templateNames)
4421   //{
4422   //  QDictIterator<int> qdi(*templateNames);
4423   //  int *tempArgIndex;
4424   //  for (;(tempArgIndex=qdi.current());++qdi)
4425   //  {
4426   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4427   //  }
4428   //}
4429   //printf("\n");
4430
4431   bool existingClass = (templSpec ==
4432                         tempArgListToString(templateClass->templateArguments(),root->lang)
4433                        );
4434   if (existingClass) return TRUE;
4435
4436   bool freshInstance=FALSE;
4437   ClassDef *instanceClass = templateClass->insertTemplateInstance(
4438                      root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4439   if (isArtificial) instanceClass->setArtificial(TRUE);
4440   instanceClass->setLanguage(root->lang);
4441
4442   if (freshInstance)
4443   {
4444     Debug::print(Debug::Classes,0,"      found fresh instance '%s'!\n",qPrint(instanceClass->name()));
4445     Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4446     instanceClass->setTemplateBaseClassNames(templateNames);
4447
4448     // search for new template instances caused by base classes of
4449     // instanceClass
4450     EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4451     if (templateRootNav)
4452     {
4453       bool unloadNeeded=FALSE;
4454       Entry *templateRoot = templateRootNav->entry();
4455       if (templateRoot==0) // not yet loaded
4456       {
4457         templateRootNav->loadEntry(g_storage);
4458         templateRoot = templateRootNav->entry();
4459         ASSERT(templateRoot!=0); // now it should really be loaded
4460         unloadNeeded=TRUE;
4461       }
4462
4463       Debug::print(Debug::Classes,0,"        template root found %s templSpec=%s!\n",
4464           qPrint(templateRoot->name),qPrint(templSpec));
4465       ArgumentList *templArgs = new ArgumentList;
4466       stringToArgumentList(templSpec,templArgs);
4467       findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4468           TemplateInstances,isArtificial,templArgs,templateNames);
4469
4470       findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4471           isArtificial,templArgs,templateNames);
4472       delete templArgs;
4473
4474       if (unloadNeeded) // still cleanup to do
4475       {
4476         templateRootNav->releaseEntry();
4477       }
4478     }
4479     else
4480     {
4481       Debug::print(Debug::Classes,0,"        no template root entry found!\n");
4482       // TODO: what happened if we get here?
4483     }
4484
4485     //Debug::print(Debug::Classes,0,"    Template instance %s : \n",instanceClass->name().data());
4486     //ArgumentList *tl = templateClass->templateArguments();
4487   }
4488   else
4489   {
4490     Debug::print(Debug::Classes,0,"      instance already exists!\n");
4491   }
4492   return TRUE;
4493 }
4494
4495 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4496 {
4497   QCString n=name;
4498   int index=n.find('<');
4499   if (index!=-1)
4500   {
4501     n=n.left(index);
4502   }
4503   bool result = rightScopeMatch(scope,n);
4504   return result;
4505 }
4506
4507 /*! Searches for the end of a template in prototype \a s starting from
4508  *  character position \a startPos. If the end was found the position
4509  *  of the closing \> is returned, otherwise -1 is returned.
4510  *
4511  *  Handles exotic cases such as
4512  *  \code
4513  *    Class<(id<0)>
4514  *    Class<bits<<2>
4515  *    Class<"<">
4516  *    Class<'<'>
4517  *    Class<(")<")>
4518  *  \endcode
4519  */
4520 static int findEndOfTemplate(const QCString &s,int startPos)
4521 {
4522   // locate end of template
4523   int e=startPos;
4524   int brCount=1;
4525   int roundCount=0;
4526   int len = s.length();
4527   bool insideString=FALSE;
4528   bool insideChar=FALSE;
4529   char pc = 0;
4530   while (e<len && brCount!=0)
4531   {
4532     char c=s.at(e);
4533     switch(c)
4534     {
4535       case '<':
4536         if (!insideString && !insideChar)
4537         {
4538           if (e<len-1 && s.at(e+1)=='<')
4539             e++;
4540           else if (roundCount==0)
4541             brCount++;
4542         }
4543         break;
4544       case '>':
4545         if (!insideString && !insideChar)
4546         {
4547           if (e<len-1 && s.at(e+1)=='>')
4548             e++;
4549           else if (roundCount==0)
4550             brCount--;
4551         }
4552         break;
4553       case '(':
4554         if (!insideString && !insideChar)
4555           roundCount++;
4556         break;
4557       case ')':
4558         if (!insideString && !insideChar)
4559           roundCount--;
4560         break;
4561       case '"':
4562         if (!insideChar)
4563         {
4564           if (insideString && pc!='\\')
4565             insideString=FALSE;
4566           else
4567             insideString=TRUE;
4568         }
4569         break;
4570       case '\'':
4571         if (!insideString)
4572         {
4573           if (insideChar && pc!='\\')
4574             insideChar=FALSE;
4575           else
4576             insideChar=TRUE;
4577         }
4578         break;
4579     }
4580     pc = c;
4581     e++;
4582   }
4583   return brCount==0 ? e : -1;
4584 }
4585
4586 static bool findClassRelation(
4587                            EntryNav *rootNav,
4588                            Definition *context,
4589                            ClassDef *cd,
4590                            BaseInfo *bi,
4591                            QDict<int> *templateNames,
4592                            FindBaseClassRelation_Mode mode,
4593                            bool isArtificial
4594                           )
4595 {
4596   //printf("findClassRelation(class=%s base=%s templateNames=",
4597   //    cd->name().data(),bi->name.data());
4598   //if (templateNames)
4599   //{
4600   //  QDictIterator<int> qdi(*templateNames);
4601   //  int *tempArgIndex;
4602   //  for (;(tempArgIndex=qdi.current());++qdi)
4603   //  {
4604   //    printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4605   //  }
4606   //}
4607   //printf("\n");
4608
4609   Entry *root = rootNav->entry();
4610
4611   QCString biName=bi->name;
4612   bool explicitGlobalScope=FALSE;
4613   //printf("findClassRelation: biName=`%s'\n",biName.data());
4614   if (biName.left(2)=="::") // explicit global scope
4615   {
4616      biName=biName.right(biName.length()-2);
4617      explicitGlobalScope=TRUE;
4618   }
4619
4620   EntryNav *parentNode=rootNav->parent();
4621   bool lastParent=FALSE;
4622   do // for each parent scope, starting with the largest scope
4623      // (in case of nested classes)
4624   {
4625     QCString scopeName= parentNode ? parentNode->name().data() : "";
4626     int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4627     do // try all parent scope prefixes, starting with the largest scope
4628     {
4629       //printf("scopePrefix=`%s' biName=`%s'\n",
4630       //    scopeName.left(scopeOffset).data(),biName.data());
4631
4632       QCString baseClassName=biName;
4633       if (scopeOffset>0)
4634       {
4635         baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4636       }
4637       //QCString stripped;
4638       //baseClassName=stripTemplateSpecifiersFromScope
4639       //                    (removeRedundantWhiteSpace(baseClassName),TRUE,
4640       //                    &stripped);
4641       MemberDef *baseClassTypeDef=0;
4642       QCString templSpec;
4643       ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4644                                            cd->getFileDef(),
4645                                            baseClassName,
4646                                            &baseClassTypeDef,
4647                                            &templSpec,
4648                                            mode==Undocumented,
4649                                            TRUE
4650                                           );
4651       //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4652       //    baseClassName.data(),baseClass,cd,explicitGlobalScope);
4653       //printf("    scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4654       //                    cd ? cd->name().data():"<none>",
4655       //                    baseClassName.data(),
4656       //                    baseClass?baseClass->name().data():"<none>",
4657       //                    templSpec.data()
4658       //      );
4659       //if (baseClassName.left(root->name.length())!=root->name ||
4660       //    baseClassName.at(root->name.length())!='<'
4661       //   ) // Check for base class with the same name.
4662       //     // If found then look in the outer scope for a match
4663       //     // and prevent recursion.
4664       if (!isRecursiveBaseClass(rootNav->name(),baseClassName)
4665           || explicitGlobalScope
4666           // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4667           // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4668           || (rootNav->lang()==SrcLangExt_IDL &&
4669               (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
4670                rootNav->section()==Entry::INCLUDED_SERVICE_SEC)))
4671       {
4672         Debug::print(
4673             Debug::Classes,0,"    class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4674             qPrint(baseClassName),
4675             qPrint(rootNav->name()),
4676             (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4677             (bi->virt==Normal)?"normal":"virtual",
4678             qPrint(templSpec)
4679            );
4680
4681         int i=baseClassName.find('<');
4682         int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4683         if (si==-1) si=0;
4684         if (baseClass==0 && (root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java))
4685         {
4686           // for Java/C# strip the template part before looking for matching
4687           baseClass = Doxygen::genericsDict->find(baseClassName.left(i));
4688           //printf("looking for '%s' result=%p\n",baseClassName.data(),baseClass);
4689         }
4690         if (baseClass==0 && i!=-1)
4691           // base class has template specifiers
4692         {
4693           // TODO: here we should try to find the correct template specialization
4694           // but for now, we only look for the unspecializated base class.
4695           int e=findEndOfTemplate(baseClassName,i+1);
4696           //printf("baseClass==0 i=%d e=%d\n",i,e);
4697           if (e!=-1) // end of template was found at e
4698           {
4699             templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4700             baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4701             baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4702                 cd->getFileDef(),
4703                 baseClassName,
4704                 &baseClassTypeDef,
4705                 0, //&templSpec,
4706                 mode==Undocumented,
4707                 TRUE
4708                 );
4709             //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4710             //      baseClass,baseClassName.data(),templSpec.data());
4711           }
4712         }
4713         else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4714                                                     // know it is a template, so see if
4715                                                     // we can also link to the explicit
4716                                                     // instance (for instance if a class
4717                                                     // derived from a template argument)
4718         {
4719           //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4720           ClassDef *templClass=getClass(baseClass->name()+templSpec);
4721           if (templClass)
4722           {
4723             // use the template instance instead of the template base.
4724             baseClass = templClass;
4725             templSpec.resize(0);
4726           }
4727         }
4728
4729         //printf("cd=%p baseClass=%p\n",cd,baseClass);
4730         bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4731         //printf("1. found=%d\n",found);
4732         if (!found && si!=-1)
4733         {
4734           QCString tmpTemplSpec;
4735           // replace any namespace aliases
4736           replaceNamespaceAliases(baseClassName,si);
4737           baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4738                                      cd->getFileDef(),
4739                                      baseClassName,
4740                                      &baseClassTypeDef,
4741                                      &tmpTemplSpec,
4742                                      mode==Undocumented,
4743                                      TRUE
4744                                     );
4745           found=baseClass!=0 && baseClass!=cd;
4746           if (found) templSpec = tmpTemplSpec;
4747         }
4748         //printf("2. found=%d\n",found);
4749
4750         //printf("root->name=%s biName=%s baseClassName=%s\n",
4751         //        root->name.data(),biName.data(),baseClassName.data());
4752         //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4753         //{
4754         //  baseClassName+="-g";
4755         //}
4756
4757         if (!found)
4758         {
4759           baseClass=findClassWithinClassContext(context,cd,baseClassName);
4760           //printf("findClassWithinClassContext(%s,%s)=%p\n",
4761           //    cd->name().data(),baseClassName.data(),baseClass);
4762           found = baseClass!=0 && baseClass!=cd;
4763
4764         }
4765         if (!found)
4766         {
4767           // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4768           // the class name also in the alias mapping.
4769           QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4770           if (aliasName) // see if it is indeed a class.
4771           {
4772             baseClass=getClass(*aliasName);
4773             found = baseClass!=0 && baseClass!=cd;
4774           }
4775         }
4776         bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4777         // make templSpec canonical
4778         // warning: the following line doesn't work for Mixin classes (see bug 560623)
4779         // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4780
4781         //printf("3. found=%d\n",found);
4782         if (found)
4783         {
4784           Debug::print(Debug::Classes,0,"    Documented base class `%s' templSpec=%s\n",qPrint(biName),qPrint(templSpec));
4785           // add base class to this class
4786
4787           // if templSpec is not empty then we should "instantiate"
4788           // the template baseClass. A new ClassDef should be created
4789           // to represent the instance. To be able to add the (instantiated)
4790           // members and documentation of a template class
4791           // (inserted in that template class at a later stage),
4792           // the template should know about its instances.
4793           // the instantiation process, should be done in a recursive way,
4794           // since instantiating a template may introduce new inheritance
4795           // relations.
4796           if (!templSpec.isEmpty() && mode==TemplateInstances)
4797           {
4798             // if baseClass is actually a typedef then we should not
4799             // instantiate it, since typedefs are in a different namespace
4800             // see bug531637 for an example where this would otherwise hang
4801             // doxygen
4802             if (baseClassTypeDef==0)
4803             {
4804               //printf("       => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4805               findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4806             }
4807           }
4808           else if (mode==DocumentedOnly || mode==Undocumented)
4809           {
4810             //printf("       => insert base class\n");
4811             QCString usedName;
4812             if (baseClassTypeDef || cd->isCSharp())
4813             {
4814               usedName=biName;
4815               //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4816             }
4817             static bool sipSupport = Config_getBool(SIP_SUPPORT);
4818             if (sipSupport) bi->prot=Public;
4819             if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4820             {
4821               cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4822               // add this class as super class to the base class
4823               baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4824             }
4825             else
4826             {
4827               warn(root->fileName,root->startLine,
4828                   "Detected potential recursive class relation "
4829                   "between class %s and base class %s!",
4830                   cd->name().data(),baseClass->name().data()
4831                   );
4832             }
4833           }
4834           return TRUE;
4835         }
4836         else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4837         {
4838           Debug::print(Debug::Classes,0,
4839                        "    New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4840                        qPrint(biName),qPrint(baseClassName),qPrint(templSpec),isArtificial
4841                       );
4842           baseClass=0;
4843           if (isATemplateArgument)
4844           {
4845             baseClass=Doxygen::hiddenClasses->find(baseClassName);
4846             if (baseClass==0)
4847             {
4848               baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4849                                  baseClassName,
4850                                  ClassDef::Class);
4851               Doxygen::hiddenClasses->append(baseClassName,baseClass);
4852               if (isArtificial) baseClass->setArtificial(TRUE);
4853               baseClass->setLanguage(root->lang);
4854             }
4855           }
4856           else
4857           {
4858             baseClass=Doxygen::classSDict->find(baseClassName);
4859             //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4860             //    baseClassName.data(),baseClass,biName.data(),templSpec.data());
4861             if (baseClass==0)
4862             {
4863               baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4864                   baseClassName,
4865                   ClassDef::Class);
4866               Doxygen::classSDict->append(baseClassName,baseClass);
4867               if (isArtificial) baseClass->setArtificial(TRUE);
4868               baseClass->setLanguage(root->lang);
4869               int si = baseClassName.findRev("::");
4870               if (si!=-1) // class is nested
4871               {
4872                 Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,rootNav->tagInfo());
4873                 if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4874                 {
4875                   baseClass->setArtificial(TRUE); // see bug678139
4876                 }
4877               }
4878             }
4879           }
4880           if (biName.right(2)=="-p")
4881           {
4882             biName="<"+biName.left(biName.length()-2)+">";
4883           }
4884           // add base class to this class
4885           cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4886           // add this class as super class to the base class
4887           baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4888           // the undocumented base was found in this file
4889           baseClass->insertUsedFile(rootNav->fileDef());
4890           baseClass->setOuterScope(Doxygen::globalScope);
4891           if (baseClassName.right(2)=="-p")
4892           {
4893             baseClass->setCompoundType(ClassDef::Protocol);
4894           }
4895           return TRUE;
4896         }
4897         else
4898         {
4899           Debug::print(Debug::Classes,0,"    Base class `%s' not found\n",qPrint(biName));
4900         }
4901       }
4902       else
4903       {
4904         if (mode!=TemplateInstances)
4905         {
4906           warn(root->fileName,root->startLine,
4907               "Detected potential recursive class relation "
4908               "between class %s and base class %s!\n",
4909               root->name.data(),baseClassName.data()
4910               );
4911         }
4912         // for mode==TemplateInstance this case is quite common and
4913         // indicates a relation between a template class and a template
4914         // instance with the same name.
4915       }
4916       if (scopeOffset==0)
4917       {
4918         scopeOffset=-1;
4919       }
4920       else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4921       {
4922         scopeOffset=0;
4923       }
4924       //printf("new scopeOffset=`%d'",scopeOffset);
4925     } while (scopeOffset>=0);
4926
4927     if (parentNode==0)
4928     {
4929       lastParent=TRUE;
4930     }
4931     else
4932     {
4933       parentNode=parentNode->parent();
4934     }
4935   } while (lastParent);
4936
4937   return FALSE;
4938 }
4939
4940 //----------------------------------------------------------------------
4941 // Computes the base and super classes for each class in the tree
4942
4943 static bool isClassSection(EntryNav *rootNav)
4944 {
4945   if ( !rootNav->name().isEmpty() )
4946   {
4947     if (rootNav->section() & Entry::COMPOUND_MASK)
4948          // is it a compound (class, struct, union, interface ...)
4949     {
4950       return TRUE;
4951     }
4952     else if (rootNav->section() & Entry::COMPOUNDDOC_MASK)
4953          // is it a documentation block with inheritance info.
4954     {
4955       rootNav->loadEntry(g_storage);
4956       Entry *root = rootNav->entry();
4957       bool extends = root->extends->count()>0;
4958       rootNav->releaseEntry();
4959       if (extends) return TRUE;
4960     }
4961   }
4962   return FALSE;
4963 }
4964
4965
4966 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
4967  */
4968 static void findClassEntries(EntryNav *rootNav)
4969 {
4970   if (isClassSection(rootNav))
4971   {
4972     g_classEntries.insert(rootNav->name(),rootNav);
4973   }
4974   RECURSE_ENTRYTREE(findClassEntries,rootNav);
4975 }
4976
4977 static QCString extractClassName(EntryNav *rootNav)
4978 {
4979   // strip any anonymous scopes first
4980   QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4981   bName=stripTemplateSpecifiersFromScope(bName);
4982   int i;
4983   if ((rootNav->lang()==SrcLangExt_CSharp || rootNav->lang()==SrcLangExt_Java) &&
4984       (i=bName.find('<'))!=-1)
4985   {
4986     // a Java/C# generic class looks like a C++ specialization, so we need to strip the
4987     // template part before looking for matches
4988     bName=bName.left(i);
4989   }
4990   return bName;
4991 }
4992
4993 /*! Using the dictionary build by findClassEntries(), this
4994  *  function will look for additional template specialization that
4995  *  exists as inheritance relations only. These instances will be
4996  *  added to the template they are derived from.
4997  */
4998 static void findInheritedTemplateInstances()
4999 {
5000   ClassSDict::Iterator cli(*Doxygen::classSDict);
5001   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5002   QDictIterator<EntryNav> edi(g_classEntries);
5003   EntryNav *rootNav;
5004   for (;(rootNav=edi.current());++edi)
5005   {
5006     ClassDef *cd;
5007     QCString bName = extractClassName(rootNav);
5008     Debug::print(Debug::Classes,0,"  Inheritance: Class %s : \n",qPrint(bName));
5009     if ((cd=getClass(bName)))
5010     {
5011       rootNav->loadEntry(g_storage);
5012       //printf("Class %s %d\n",cd->name().data(),root->extends->count());
5013       findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
5014       rootNav->releaseEntry();
5015     }
5016   }
5017 }
5018
5019 static void findUsedTemplateInstances()
5020 {
5021   ClassSDict::Iterator cli(*Doxygen::classSDict);
5022   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5023   QDictIterator<EntryNav> edi(g_classEntries);
5024   EntryNav *rootNav;
5025   for (;(rootNav=edi.current());++edi)
5026   {
5027     ClassDef *cd;
5028     QCString bName = extractClassName(rootNav);
5029     Debug::print(Debug::Classes,0,"  Usage: Class %s : \n",qPrint(bName));
5030     if ((cd=getClass(bName)))
5031     {
5032       rootNav->loadEntry(g_storage);
5033       findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
5034       cd->addTypeConstraints();
5035       rootNav->releaseEntry();
5036     }
5037   }
5038 }
5039
5040 static void computeClassRelations()
5041 {
5042   ClassSDict::Iterator cli(*Doxygen::classSDict);
5043   for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5044   QDictIterator<EntryNav> edi(g_classEntries);
5045   EntryNav *rootNav;
5046   for (;(rootNav=edi.current());++edi)
5047   {
5048     ClassDef *cd;
5049
5050     rootNav->loadEntry(g_storage);
5051     Entry *root = rootNav->entry();
5052     QCString bName = extractClassName(rootNav);
5053     Debug::print(Debug::Classes,0,"  Relations: Class %s : \n",qPrint(bName));
5054     if ((cd=getClass(bName)))
5055     {
5056       findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
5057     }
5058     int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
5059     if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
5060         bName.right(2)!="::")
5061     {
5062       if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
5063           (guessSection(root->fileName)==Entry::HEADER_SEC ||
5064            Config_getBool(EXTRACT_LOCAL_CLASSES)) && // not defined in source file
5065            protectionLevelVisible(root->protection) && // hidden by protection
5066            !Config_getBool(HIDE_UNDOC_CLASSES) // undocumented class are visible
5067          )
5068         warn_undoc(
5069                    root->fileName,root->startLine,
5070                    "Compound %s is not documented.",
5071                    root->name.data()
5072              );
5073     }
5074
5075     rootNav->releaseEntry();
5076   }
5077 }
5078
5079 static void computeTemplateClassRelations()
5080 {
5081   QDictIterator<EntryNav> edi(g_classEntries);
5082   EntryNav *rootNav;
5083   for (;(rootNav=edi.current());++edi)
5084   {
5085     rootNav->loadEntry(g_storage);
5086     Entry *root = rootNav->entry();
5087
5088     QCString bName=stripAnonymousNamespaceScope(root->name);
5089     bName=stripTemplateSpecifiersFromScope(bName);
5090     ClassDef *cd=getClass(bName);
5091     // strip any anonymous scopes first
5092     QDict<ClassDef> *templInstances = 0;
5093     if (cd && (templInstances=cd->getTemplateInstances()))
5094     {
5095       Debug::print(Debug::Classes,0,"  Template class %s : \n",qPrint(cd->name()));
5096       QDictIterator<ClassDef> tdi(*templInstances);
5097       ClassDef *tcd;
5098       for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
5099       {
5100         Debug::print(Debug::Classes,0,"    Template instance %s : \n",qPrint(tcd->name()));
5101         QCString templSpec = tdi.currentKey();
5102         ArgumentList *templArgs = new ArgumentList;
5103         stringToArgumentList(templSpec,templArgs);
5104         QList<BaseInfo> *baseList=root->extends;
5105         QListIterator<BaseInfo> it(*baseList);
5106         BaseInfo *bi;
5107         for (;(bi=it.current());++it) // for each base class of the template
5108         {
5109           // check if the base class is a template argument
5110           BaseInfo tbi(bi->name,bi->prot,bi->virt);
5111           ArgumentList *tl = cd->templateArguments();
5112           if (tl)
5113           {
5114             QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
5115             QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
5116             // for each template name that we inherit from we need to
5117             // substitute the formal with the actual arguments
5118             QDict<int> *actualTemplateNames = new QDict<int>(17);
5119             actualTemplateNames->setAutoDelete(TRUE);
5120             QDictIterator<int> qdi(*templateNames);
5121             for (qdi.toFirst();qdi.current();++qdi)
5122             {
5123               int templIndex = *qdi.current();
5124               Argument *actArg = 0;
5125               if (templIndex<(int)templArgs->count())
5126               {
5127                 actArg=templArgs->at(templIndex);
5128               }
5129               if (actArg!=0 &&
5130                   baseClassNames!=0 &&
5131                   baseClassNames->find(actArg->type)!=0 &&
5132                   actualTemplateNames->find(actArg->type)==0
5133                  )
5134               {
5135                 actualTemplateNames->insert(actArg->type,new int(templIndex));
5136               }
5137             }
5138             delete templateNames;
5139
5140             tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
5141             // find a documented base class in the correct scope
5142             if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
5143             {
5144               // no documented base class -> try to find an undocumented one
5145               findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
5146             }
5147             delete actualTemplateNames;
5148           }
5149         }
5150         delete templArgs;
5151       } // class has no base classes
5152     }
5153
5154     rootNav->releaseEntry();
5155   }
5156 }
5157
5158 //-----------------------------------------------------------------------
5159 // compute the references (anchors in HTML) for each function in the file
5160
5161 static void computeMemberReferences()
5162 {
5163   ClassSDict::Iterator cli(*Doxygen::classSDict);
5164   ClassDef *cd=0;
5165   for (cli.toFirst();(cd=cli.current());++cli)
5166   {
5167     cd->computeAnchors();
5168   }
5169   FileNameListIterator fnli(*Doxygen::inputNameList);
5170   FileName *fn;
5171   for (fnli.toFirst();(fn=fnli.current());++fnli)
5172   {
5173     FileNameIterator fni(*fn);
5174     FileDef *fd;
5175     for (;(fd=fni.current());++fni)
5176     {
5177       fd->computeAnchors();
5178     }
5179   }
5180   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5181   NamespaceDef *nd=0;
5182   for (nli.toFirst();(nd=nli.current());++nli)
5183   {
5184     nd->computeAnchors();
5185   }
5186   GroupSDict::Iterator gli(*Doxygen::groupSDict);
5187   GroupDef *gd;
5188   for (gli.toFirst();(gd=gli.current());++gli)
5189   {
5190     gd->computeAnchors();
5191   }
5192 }
5193
5194 //----------------------------------------------------------------------
5195
5196 static void addListReferences()
5197 {
5198   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
5199   MemberName *mn=0;
5200   for (mnli.toFirst();(mn=mnli.current());++mnli)
5201   {
5202     MemberNameIterator mni(*mn);
5203     MemberDef *md=0;
5204     for (mni.toFirst();(md=mni.current());++mni)
5205     {
5206       md->visited=FALSE;
5207     }
5208   }
5209   MemberNameSDict::Iterator fmnli(*Doxygen::functionNameSDict);
5210   for (fmnli.toFirst();(mn=fmnli.current());++fmnli)
5211   {
5212     MemberNameIterator mni(*mn);
5213     MemberDef *md=0;
5214     for (mni.toFirst();(md=mni.current());++mni)
5215     {
5216       md->visited=FALSE;
5217     }
5218   }
5219
5220   ClassSDict::Iterator cli(*Doxygen::classSDict);
5221   ClassDef *cd=0;
5222   for (cli.toFirst();(cd=cli.current());++cli)
5223   {
5224     cd->addListReferences();
5225   }
5226
5227   FileNameListIterator fnli(*Doxygen::inputNameList);
5228   FileName *fn;
5229   for (fnli.toFirst();(fn=fnli.current());++fnli)
5230   {
5231     FileNameIterator fni(*fn);
5232     FileDef *fd;
5233     for (;(fd=fni.current());++fni)
5234     {
5235       fd->addListReferences();
5236     }
5237   }
5238
5239   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5240   NamespaceDef *nd=0;
5241   for (nli.toFirst();(nd=nli.current());++nli)
5242   {
5243     nd->addListReferences();
5244   }
5245
5246   GroupSDict::Iterator gli(*Doxygen::groupSDict);
5247   GroupDef *gd;
5248   for (gli.toFirst();(gd=gli.current());++gli)
5249   {
5250     gd->addListReferences();
5251   }
5252
5253   PageSDict::Iterator pdi(*Doxygen::pageSDict);
5254   PageDef *pd=0;
5255   for (pdi.toFirst();(pd=pdi.current());++pdi)
5256   {
5257     QCString name = pd->getOutputFileBase();
5258     if (pd->getGroupDef())
5259     {
5260       name = pd->getGroupDef()->getOutputFileBase();
5261     }
5262     {
5263       QList<ListItemInfo> *xrefItems = pd->xrefListItems();
5264       addRefItem(xrefItems,
5265           name,
5266           theTranslator->trPage(TRUE,TRUE),
5267           name,pd->title(),0,0);
5268     }
5269   }
5270
5271   DirSDict::Iterator ddi(*Doxygen::directories);
5272   DirDef *dd = 0;
5273   for (ddi.toFirst();(dd=ddi.current());++ddi)
5274   {
5275     QCString name = dd->getOutputFileBase();
5276     //if (dd->getGroupDef())
5277     //{
5278     //  name = dd->getGroupDef()->getOutputFileBase();
5279     //}
5280     QList<ListItemInfo> *xrefItems = dd->xrefListItems();
5281     addRefItem(xrefItems,
5282         name,
5283         theTranslator->trDir(TRUE,TRUE),
5284         name,dd->displayName(),0,0);
5285   }
5286 }
5287
5288 //----------------------------------------------------------------------
5289
5290 static void generateXRefPages()
5291 {
5292   QDictIterator<RefList> di(*Doxygen::xrefLists);
5293   RefList *rl;
5294   for (di.toFirst();(rl=di.current());++di)
5295   {
5296     rl->generatePage();
5297   }
5298 }
5299
5300 //----------------------------------------------------------------------
5301 // Copy the documentation in entry `root' to member definition `md' and
5302 // set the function declaration of the member to `funcDecl'. If the boolean
5303 // over_load is set the standard overload text is added.
5304
5305 static void addMemberDocs(EntryNav *rootNav,
5306                    MemberDef *md, const char *funcDecl,
5307                    ArgumentList *al,
5308                    bool over_load,
5309                    NamespaceSDict *
5310                   )
5311 {
5312   Entry *root = rootNav->entry();
5313   //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
5314   //     root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
5315   QCString fDecl=funcDecl;
5316   // strip extern specifier
5317   fDecl.stripPrefix("extern ");
5318   md->setDefinition(fDecl);
5319   md->enableCallGraph(root->callGraph);
5320   md->enableCallerGraph(root->callerGraph);
5321   ClassDef     *cd=md->getClassDef();
5322   NamespaceDef *nd=md->getNamespaceDef();
5323   QCString fullName;
5324   if (cd)
5325     fullName = cd->name();
5326   else if (nd)
5327     fullName = nd->name();
5328
5329   if (!fullName.isEmpty()) fullName+="::";
5330   fullName+=md->name();
5331   FileDef *rfd=rootNav->fileDef();
5332
5333   // TODO determine scope based on root not md
5334   Definition *rscope = md->getOuterScope();
5335
5336   ArgumentList *mdAl = md->argumentList();
5337   if (al)
5338   {
5339     //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5340     mergeArguments(mdAl,al,!root->doc.isEmpty());
5341   }
5342   else
5343   {
5344     if (
5345           matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
5346                            rscope,rfd,root->argList,
5347                            TRUE
5348                          )
5349        )
5350     {
5351       //printf("merging arguments (2)\n");
5352       mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
5353     }
5354   }
5355   if (over_load)  // the \overload keyword was used
5356   {
5357     QCString doc=getOverloadDocs();
5358     if (!root->doc.isEmpty())
5359     {
5360       doc+="<p>";
5361       doc+=root->doc;
5362     }
5363     md->setDocumentation(doc,root->docFile,root->docLine);
5364     md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5365     md->setDocsForDefinition(!root->proto);
5366   }
5367   else
5368   {
5369     //printf("overwrite!\n");
5370     md->setDocumentation(root->doc,root->docFile,root->docLine);
5371     md->setDocsForDefinition(!root->proto);
5372
5373     //printf("overwrite!\n");
5374     md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5375
5376     if (
5377         (md->inbodyDocumentation().isEmpty() ||
5378          !rootNav->parent()->name().isEmpty()
5379         ) && !root->inbodyDocs.isEmpty()
5380        )
5381     {
5382       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5383     }
5384   }
5385
5386   //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5387   //    md->initializer().data(),md->initializer().isEmpty(),
5388   //    root->initializer.data(),root->initializer.isEmpty()
5389   //   );
5390   if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5391   {
5392     //printf("setInitializer\n");
5393     md->setInitializer(root->initializer);
5394   }
5395
5396   md->setMaxInitLines(root->initLines);
5397
5398   if (rfd)
5399   {
5400     if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5401        )
5402     {
5403       //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5404       md->setBodySegment(root->bodyLine,root->endBodyLine);
5405       md->setBodyDef(rfd);
5406     }
5407
5408     md->setRefItems(root->sli);
5409   }
5410
5411   md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5412   md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5413
5414   md->mergeMemberSpecifiers(root->spec);
5415   md->addSectionsToDefinition(root->anchors);
5416   addMemberToGroups(root,md);
5417   if (cd) cd->insertUsedFile(rfd);
5418   //printf("root->mGrpId=%d\n",root->mGrpId);
5419   if (root->mGrpId!=-1)
5420   {
5421     if (md->getMemberGroupId()!=-1)
5422     {
5423       if (md->getMemberGroupId()!=root->mGrpId)
5424       {
5425         warn(
5426              root->fileName,root->startLine,
5427              "member %s belongs to two different groups. The second "
5428              "one found here will be ignored.",
5429              md->name().data()
5430             );
5431       }
5432     }
5433     else // set group id
5434     {
5435       //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5436       md->setMemberGroupId(root->mGrpId);
5437     }
5438   }
5439 }
5440
5441 //----------------------------------------------------------------------
5442 // find a class definition given the scope name and (optionally) a
5443 // template list specifier
5444
5445 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5446                          const char *scopeName)
5447 {
5448   ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5449   return tcd;
5450 }
5451
5452
5453 //----------------------------------------------------------------------
5454 // Adds the documentation contained in `root' to a global function
5455 // with name `name' and argument list `args' (for overloading) and
5456 // function declaration `decl' to the corresponding member definition.
5457
5458 static bool findGlobalMember(EntryNav *rootNav,
5459                            const QCString &namespaceName,
5460                            const char *type,
5461                            const char *name,
5462                            const char *tempArg,
5463                            const char *,
5464                            const char *decl)
5465 {
5466   Entry *root = rootNav->entry();
5467   Debug::print(Debug::FindMembers,0,
5468        "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5469           qPrint(namespaceName),qPrint(type),qPrint(name),qPrint(tempArg),qPrint(decl));
5470   QCString n=name;
5471   if (n.isEmpty()) return FALSE;
5472   if (n.find("::")!=-1) return FALSE; // skip undefined class members
5473   MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5474   if (mn==0)
5475   {
5476     mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5477   }
5478   if (mn) // function name defined
5479   {
5480     Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5481     //int count=0;
5482     MemberNameIterator mni(*mn);
5483     MemberDef *md;
5484     bool found=FALSE;
5485     for (mni.toFirst();(md=mni.current()) && !found;++mni)
5486     {
5487       NamespaceDef *nd=md->getNamespaceDef();
5488
5489       //printf("Namespace namespaceName=%s nd=%s\n",
5490       //    namespaceName.data(),nd ? nd->name().data() : "<none>");
5491
5492       FileDef *fd=rootNav->fileDef();
5493       //printf("File %s\n",fd ? fd->name().data() : "<none>");
5494       NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5495       //SDict<Definition> *cl = fd ? fd->getUsedClasses()    : 0;
5496       //printf("NamespaceList %p\n",nl);
5497
5498       // search in the list of namespaces that are imported via a
5499       // using declaration
5500       bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5501
5502       if ((namespaceName.isEmpty() && nd==0) ||  // not in a namespace
5503           (nd && nd->name()==namespaceName) ||   // or in the same namespace
5504           viaUsingDirective                      // member in `using' namespace
5505          )
5506       {
5507         Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5508             qPrint(md->name()),qPrint(namespaceName));
5509
5510         NamespaceDef *rnd = 0;
5511         if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5512
5513         ArgumentList *mdAl = md->argumentList();
5514         bool matching=
5515           (mdAl==0 && root->argList->count()==0) ||
5516           md->isVariable() || md->isTypedef() || /* in case of function pointers */
5517           matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl,
5518                           rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5519                           FALSE);
5520
5521         // for template members we need to check if the number of
5522         // template arguments is the same, otherwise we are dealing with
5523         // different functions.
5524         if (matching && root->tArgLists)
5525         {
5526           ArgumentList *mdTempl = md->templateArguments();
5527           if (mdTempl)
5528           {
5529             if (root->tArgLists->getLast()->count()!=mdTempl->count())
5530             {
5531               matching=FALSE;
5532             }
5533           }
5534         }
5535
5536         //printf("%s<->%s\n",
5537         //    argListToString(md->argumentList()).data(),
5538         //    argListToString(root->argList).data());
5539
5540         // for static members we also check if the comment block was found in
5541         // the same file. This is needed because static members with the same
5542         // name can be in different files. Thus it would be wrong to just
5543         // put the comment block at the first syntactically matching member.
5544         if (matching && md->isStatic() &&
5545             md->getDefFileName()!=root->fileName &&
5546             mn->count()>1)
5547         {
5548           matching = FALSE;
5549         }
5550
5551         // for template member we also need to check the return type
5552         if (md->templateArguments()!=0 && root->tArgLists!=0)
5553         {
5554           //printf("Comparing return types '%s'<->'%s'\n",
5555           //    md->typeString(),type);
5556           if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
5557               qstrcmp(md->typeString(),type)!=0)
5558           {
5559             //printf(" ---> no matching\n");
5560             matching = FALSE;
5561           }
5562         }
5563
5564         if (matching) // add docs to the member
5565         {
5566           Debug::print(Debug::FindMembers,0,"5. Match found\n");
5567           addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5568           found=TRUE;
5569         }
5570       }
5571     }
5572     if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5573     {
5574       QCString fullFuncDecl=decl;
5575       if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5576       QCString warnMsg =
5577          QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5578       if (mn->count()>0)
5579       {
5580         warnMsg+="\nPossible candidates:\n";
5581         for (mni.toFirst();(md=mni.current());++mni)
5582         {
5583           warnMsg+=" '";
5584           warnMsg+=substitute(md->declaration(),"%","%%");
5585           warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5586                    " of file"+md->getDefFileName()+"\n";
5587         }
5588       }
5589       warn(root->fileName,root->startLine,warnMsg);
5590     }
5591   }
5592   else // got docs for an undefined member!
5593   {
5594     if (root->type!="friend class" &&
5595         root->type!="friend struct" &&
5596         root->type!="friend union" &&
5597         root->type!="friend" &&
5598         (!Config_getBool(TYPEDEF_HIDES_STRUCT) ||
5599          root->type.find("typedef ")==-1)
5600        )
5601     {
5602       warn(root->fileName,root->startLine,
5603            "documented symbol `%s' was not declared or defined.",decl
5604           );
5605     }
5606   }
5607   return TRUE;
5608 }
5609
5610 static bool isSpecialization(
5611                   const QList<ArgumentList> &srcTempArgLists,
5612                   const QList<ArgumentList> &dstTempArgLists
5613     )
5614 {
5615     QListIterator<ArgumentList> srclali(srcTempArgLists);
5616     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5617     for (;srclali.current();++srclali,++dstlali)
5618     {
5619       ArgumentList *sal = srclali.current();
5620       ArgumentList *dal = dstlali.current();
5621       if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5622     }
5623     return FALSE;
5624 }
5625
5626 static bool scopeIsTemplate(Definition *d)
5627 {
5628   bool result=FALSE;
5629   if (d && d->definitionType()==Definition::TypeClass)
5630   {
5631     result = ((ClassDef*)d)->templateArguments() || scopeIsTemplate(d->getOuterScope());
5632   }
5633   return result;
5634 }
5635
5636 static QCString substituteTemplatesInString(
5637     const QList<ArgumentList> &srcTempArgLists,
5638     const QList<ArgumentList> &dstTempArgLists,
5639     ArgumentList *funcTempArgList, // can be used to match template specializations
5640     const QCString &src
5641     )
5642 {
5643   QCString dst;
5644   QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5645   //printf("type=%s\n",sa->type.data());
5646   int i,p=0,l;
5647   while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5648   {
5649     bool found=FALSE;
5650     dst+=src.mid(p,i-p);
5651     QCString name=src.mid(i,l);
5652
5653     QListIterator<ArgumentList> srclali(srcTempArgLists);
5654     QListIterator<ArgumentList> dstlali(dstTempArgLists);
5655     for (;srclali.current() && !found;++srclali,++dstlali)
5656     {
5657       ArgumentListIterator tsali(*srclali.current());
5658       ArgumentListIterator tdali(*dstlali.current());
5659       ArgumentListIterator *fali=0;
5660       Argument *tsa =0,*tda=0, *fa=0;
5661       if (funcTempArgList)
5662       {
5663         fali = new ArgumentListIterator(*funcTempArgList);
5664         fa = fali->current();
5665       }
5666
5667       for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5668       {
5669         tda = tdali.current();
5670         //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5671         //    tsa->type.data(),tsa->name.data(),
5672         //    tda->type.data(),tda->name.data());
5673         if (name==tsa->name)
5674         {
5675           if (tda && tda->name.isEmpty())
5676           {
5677             int vc=0;
5678             if (tda->type.left(6)=="class ") vc=6;
5679             else if (tda->type.left(9)=="typename ") vc=9;
5680             if (vc>0) // convert type=="class T" to type=="class" name=="T"
5681             {
5682               tda->name = tda->type.mid(vc);
5683               tda->type = tda->type.left(vc-1);
5684             }
5685           }
5686           if (tda && !tda->name.isEmpty())
5687           {
5688             name=tda->name; // substitute
5689             found=TRUE;
5690           }
5691           else if (fa)
5692           {
5693             name=fa->type;
5694             found=TRUE;
5695           }
5696         }
5697         if (tda)
5698           ++tdali;
5699         else if (fali)
5700         { ++(*fali); fa=fali->current(); }
5701       }
5702
5703       delete fali;
5704       //printf("   srcList='%s' dstList='%s faList='%s'\n",
5705       //  argListToString(srclali.current()).data(),
5706       //  argListToString(dstlali.current()).data(),
5707       //  funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5708     }
5709     dst+=name;
5710     p=i+l;
5711   }
5712   dst+=src.right(src.length()-p);
5713   //printf("  substituteTemplatesInString(%s)=%s\n",
5714   //    src.data(),dst.data());
5715   return dst;
5716 }
5717
5718 static void substituteTemplatesInArgList(
5719                   const QList<ArgumentList> &srcTempArgLists,
5720                   const QList<ArgumentList> &dstTempArgLists,
5721                   ArgumentList *src,
5722                   ArgumentList *dst,
5723                   ArgumentList *funcTempArgs = 0
5724                  )
5725 {
5726   ArgumentListIterator sali(*src);
5727   ArgumentListIterator dali(*dst);
5728   Argument *sa=0;
5729   Argument *da=dali.current();
5730
5731   for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5732   {
5733     QCString dstType = substituteTemplatesInString(
5734                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5735                                   sa->type);
5736     QCString dstArray = substituteTemplatesInString(
5737                                   srcTempArgLists,dstTempArgLists,funcTempArgs,
5738                                   sa->array);
5739     if (da==0)
5740     {
5741       da=new Argument(*sa);
5742       dst->append(da);
5743       da->type=dstType;
5744       da->array=dstArray;
5745       da=0;
5746     }
5747     else
5748     {
5749       da->type=dstType;
5750       da->type=dstArray;
5751       ++dali;
5752       da=dali.current();
5753     }
5754   }
5755   dst->constSpecifier     = src->constSpecifier;
5756   dst->volatileSpecifier  = src->volatileSpecifier;
5757   dst->pureSpecifier      = src->pureSpecifier;
5758   dst->trailingReturnType = substituteTemplatesInString(
5759                              srcTempArgLists,dstTempArgLists,
5760                              funcTempArgs,src->trailingReturnType);
5761   //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5762   //    argListToString(src).data(),argListToString(dst).data()
5763   //    );
5764 }
5765
5766
5767
5768 /*! This function tries to find a member (in a documented class/file/namespace)
5769  * that corresponds to the function/variable declaration given in \a funcDecl.
5770  *
5771  * The boolean \a overloaded is used to specify whether or not a standard
5772  * overload documentation line should be generated.
5773  *
5774  * The boolean \a isFunc is a hint that indicates that this is a function
5775  * instead of a variable or typedef.
5776  */
5777 static void findMember(EntryNav *rootNav,
5778                        QCString funcDecl,
5779                        bool overloaded,
5780                        bool isFunc
5781                       )
5782 {
5783   Entry *root = rootNav->entry();
5784
5785   Debug::print(Debug::FindMembers,0,
5786                "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5787                "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5788                "spec=%lld lang=%x\n",
5789                root,qPrint(funcDecl),qPrint(root->relates),overloaded,isFunc,root->mGrpId,
5790                root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5791                root->spec,root->lang
5792               );
5793
5794   QCString scopeName;
5795   QCString className;
5796   QCString namespaceName;
5797   QCString funcType;
5798   QCString funcName;
5799   QCString funcArgs;
5800   QCString funcTempList;
5801   QCString exceptions;
5802   QCString funcSpec;
5803   bool isRelated=FALSE;
5804   bool isMemberOf=FALSE;
5805   bool isFriend=FALSE;
5806   bool done;
5807   do
5808   {
5809     done=TRUE;
5810     if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5811     {
5812       isFriend=TRUE;
5813       done=FALSE;
5814     }
5815     if (funcDecl.stripPrefix("inline "))
5816     {
5817       root->spec|=Entry::Inline;
5818       done=FALSE;
5819     }
5820     if (funcDecl.stripPrefix("explicit "))
5821     {
5822       root->spec|=Entry::Explicit;
5823       done=FALSE;
5824     }
5825     if (funcDecl.stripPrefix("mutable "))
5826     {
5827       root->spec|=Entry::Mutable;
5828       done=FALSE;
5829     }
5830     if (funcDecl.stripPrefix("virtual "))
5831     {
5832       done=FALSE;
5833     }
5834   } while (!done);
5835
5836   // delete any ; from the function declaration
5837   int sep;
5838   while ((sep=funcDecl.find(';'))!=-1)
5839   {
5840     funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5841   }
5842
5843   // make sure the first character is a space to simplify searching.
5844   if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5845
5846   // remove some superfluous spaces
5847   funcDecl= substitute(
5848               substitute(
5849                 substitute(funcDecl,"~ ","~"),
5850                 ":: ","::"
5851               ),
5852               " ::","::"
5853             ).stripWhiteSpace();
5854
5855   //printf("funcDecl=`%s'\n",funcDecl.data());
5856   if (isFriend && funcDecl.left(6)=="class ")
5857   {
5858     //printf("friend class\n");
5859     funcDecl=funcDecl.right(funcDecl.length()-6);
5860     funcName = funcDecl.copy();
5861   }
5862   else if (isFriend && funcDecl.left(7)=="struct ")
5863   {
5864     funcDecl=funcDecl.right(funcDecl.length()-7);
5865     funcName = funcDecl.copy();
5866   }
5867   else
5868   {
5869     // extract information from the declarations
5870     parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5871                 funcArgs,funcTempList,exceptions
5872                );
5873   }
5874   //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5875   //    scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5876
5877   // the class name can also be a namespace name, we decide this later.
5878   // if a related class name is specified and the class name could
5879   // not be derived from the function declaration, then use the
5880   // related field.
5881   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5882   //    scopeName.data(),className.data(),namespaceName.data());
5883   if (!root->relates.isEmpty())
5884   {                             // related member, prefix user specified scope
5885     isRelated=TRUE;
5886     isMemberOf=(root->relatesType == MemberOf);
5887     if (getClass(root->relates)==0 && !scopeName.isEmpty())
5888     {
5889       scopeName= mergeScopes(scopeName,root->relates);
5890     }
5891     else
5892     {
5893       scopeName = root->relates;
5894     }
5895   }
5896
5897   if (root->relates.isEmpty() && rootNav->parent() &&
5898       ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5899        (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5900       ) &&
5901       !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName
5902                                      // with the scope in which it was found
5903   {
5904     QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5905     if (!scopeName.isEmpty() &&
5906         (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5907     {
5908       scopeName = joinedName;
5909     }
5910     else
5911     {
5912       scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5913     }
5914   }
5915   else // see if we can prefix a namespace or class that is used from the file
5916   {
5917      FileDef *fd=rootNav->fileDef();
5918      if (fd)
5919      {
5920        NamespaceSDict *fnl = fd->getUsedNamespaces();
5921        if (fnl)
5922        {
5923          QCString joinedName;
5924          NamespaceDef *fnd;
5925          NamespaceSDict::Iterator nsdi(*fnl);
5926          for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5927          {
5928            joinedName = fnd->name()+"::"+scopeName;
5929            if (Doxygen::namespaceSDict->find(joinedName))
5930            {
5931              scopeName=joinedName;
5932              break;
5933            }
5934          }
5935        }
5936      }
5937   }
5938   scopeName=stripTemplateSpecifiersFromScope(
5939       removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
5940
5941   // funcSpec contains the last template specifiers of the given scope.
5942   // If this method does not have any template arguments or they are
5943   // empty while funcSpec is not empty we assume this is a
5944   // specialization of a method. If not, we clear the funcSpec and treat
5945   // this as a normal method of a template class.
5946   if (!(root->tArgLists &&
5947         root->tArgLists->count()>0 &&
5948         root->tArgLists->getFirst()->count()==0
5949        )
5950      )
5951   {
5952     funcSpec.resize(0);
5953   }
5954
5955   // split scope into a namespace and a class part
5956   extractNamespaceName(scopeName,className,namespaceName,TRUE);
5957   //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5958   //       scopeName.data(),className.data(),namespaceName.data());
5959
5960   //namespaceName=removeAnonymousScopes(namespaceName);
5961   if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5962
5963   //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5964   // merge class and namespace scopes again
5965   scopeName.resize(0);
5966   if (!namespaceName.isEmpty())
5967   {
5968     if (className.isEmpty())
5969     {
5970       scopeName=namespaceName;
5971     }
5972     else if (!root->relates.isEmpty() || // relates command with explicit scope
5973              !getClass(className)) // class name only exists in a namespace
5974     {
5975       scopeName=namespaceName+"::"+className;
5976     }
5977     else
5978     {
5979       scopeName=className;
5980     }
5981   }
5982   else if (!className.isEmpty())
5983   {
5984     scopeName=className;
5985   }
5986   //printf("new scope=`%s'\n",scopeName.data());
5987
5988   QCString tempScopeName=scopeName;
5989   ClassDef *cd=getClass(scopeName);
5990   if (cd)
5991   {
5992     if (funcSpec.isEmpty())
5993     {
5994       int argListIndex=0;
5995       tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists,&argListIndex);
5996     }
5997     else
5998     {
5999       tempScopeName=scopeName+funcSpec;
6000     }
6001   }
6002   //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
6003   //    scopeName.data(),cd,root->tArgLists,tempScopeName.data());
6004
6005   //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6006   // rebuild the function declaration (needed to get the scope right).
6007   if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool(HIDE_SCOPE_NAMES))
6008   {
6009     if (!funcType.isEmpty())
6010     {
6011       if (isFunc) // a function -> we use argList for the arguments
6012       {
6013         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
6014       }
6015       else
6016       {
6017         funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
6018       }
6019     }
6020     else
6021     {
6022       if (isFunc) // a function => we use argList for the arguments
6023       {
6024         funcDecl=tempScopeName+"::"+funcName+funcTempList;
6025       }
6026       else // variable => add `argument' list
6027       {
6028         funcDecl=tempScopeName+"::"+funcName+funcArgs;
6029       }
6030     }
6031   }
6032   else // build declaration without scope
6033   {
6034     if (!funcType.isEmpty()) // but with a type
6035     {
6036       if (isFunc) // function => omit argument list
6037       {
6038         funcDecl=funcType+" "+funcName+funcTempList;
6039       }
6040       else // variable => add `argument' list
6041       {
6042         funcDecl=funcType+" "+funcName+funcArgs;
6043       }
6044     }
6045     else // no type
6046     {
6047       if (isFunc)
6048       {
6049         funcDecl=funcName+funcTempList;
6050       }
6051       else
6052       {
6053         funcDecl=funcName+funcArgs;
6054       }
6055     }
6056   }
6057
6058   if (funcType=="template class" && !funcTempList.isEmpty())
6059     return;   // ignore explicit template instantiations
6060
6061   Debug::print(Debug::FindMembers,0,
6062            "findMember() Parse results:\n"
6063            "  namespaceName=`%s'\n"
6064            "  className=`%s`\n"
6065            "  funcType=`%s'\n"
6066            "  funcSpec=`%s'\n"
6067            "  funcName=`%s'\n"
6068            "  funcArgs=`%s'\n"
6069            "  funcTempList=`%s'\n"
6070            "  funcDecl=`%s'\n"
6071            "  related=`%s'\n"
6072            "  exceptions=`%s'\n"
6073            "  isRelated=%d\n"
6074            "  isMemberOf=%d\n"
6075            "  isFriend=%d\n"
6076            "  isFunc=%d\n\n",
6077            qPrint(namespaceName),qPrint(className),
6078            qPrint(funcType),qPrint(funcSpec),qPrint(funcName),qPrint(funcArgs),qPrint(funcTempList),
6079            qPrint(funcDecl),qPrint(root->relates),qPrint(exceptions),isRelated,isMemberOf,isFriend,
6080            isFunc
6081           );
6082
6083   MemberName *mn=0;
6084   if (!funcName.isEmpty()) // function name is valid
6085   {
6086     Debug::print(Debug::FindMembers,0,
6087                  "1. funcName=`%s'\n",funcName.data());
6088     if (funcName.left(9)=="operator ") // strip class scope from cast operator
6089     {
6090       funcName = substitute(funcName,className+"::","");
6091     }
6092     if (!funcTempList.isEmpty()) // try with member specialization
6093     {
6094       mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
6095     }
6096     if (mn==0) // try without specialization
6097     {
6098       mn=Doxygen::memberNameSDict->find(funcName);
6099     }
6100     if (!isRelated && mn) // function name already found
6101     {
6102       Debug::print(Debug::FindMembers,0,
6103                    "2. member name exists (%d members with this name)\n",mn->count());
6104       if (!className.isEmpty()) // class name is valid
6105       {
6106         if (funcSpec.isEmpty()) // not a member specialization
6107         {
6108           int count=0;
6109           int noMatchCount=0;
6110           MemberNameIterator mni(*mn);
6111           MemberDef *md;
6112           bool memFound=FALSE;
6113           for (mni.toFirst();!memFound && (md=mni.current());++mni)
6114           {
6115             ClassDef *cd=md->getClassDef();
6116             Debug::print(Debug::FindMembers,0,
6117                 "3. member definition found, "
6118                 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
6119                 qPrint(scopeName),cd ? qPrint(cd->name()) : "<none>",
6120                 qPrint(md->argsString()),
6121                 qPrint(root->fileName));
6122             //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
6123             FileDef *fd=rootNav->fileDef();
6124             NamespaceDef *nd=0;
6125             if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
6126
6127             //printf("scopeName %s->%s\n",scopeName.data(),
6128             //       stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
6129
6130             ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
6131             if (tcd==0 && cd && stripAnonymousNamespaceScope(cd->name())==scopeName)
6132             {
6133               // don't be fooled by anonymous scopes
6134               tcd=cd;
6135             }
6136             //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
6137             //    scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
6138
6139             if (cd && tcd==cd) // member's classes match
6140             {
6141               Debug::print(Debug::FindMembers,0,
6142                   "4. class definition %s found\n",cd->name().data());
6143
6144               // get the template parameter lists found at the member declaration
6145               QList<ArgumentList> declTemplArgs;
6146               cd->getTemplateParameterLists(declTemplArgs);
6147               ArgumentList *templAl = md->templateArguments();
6148               if (templAl)
6149               {
6150                 declTemplArgs.append(templAl);
6151               }
6152
6153               // get the template parameter lists found at the member definition
6154               QList<ArgumentList> *defTemplArgs = root->tArgLists;
6155               //printf("defTemplArgs=%p\n",defTemplArgs);
6156
6157               // do we replace the decl argument lists with the def argument lists?
6158               bool substDone=FALSE;
6159               ArgumentList *argList=0;
6160
6161               /* substitute the occurrences of class template names in the
6162                * argument list before matching
6163                */
6164               ArgumentList *mdAl = md->argumentList();
6165               if (declTemplArgs.count()>0 && defTemplArgs &&
6166                   declTemplArgs.count()==defTemplArgs->count() &&
6167                   mdAl
6168                  )
6169               {
6170                 /* the function definition has template arguments
6171                  * and the class definition also has template arguments, so
6172                  * we must substitute the template names of the class by that
6173                  * of the function definition before matching.
6174                  */
6175                 argList = new ArgumentList;
6176                 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
6177                     mdAl,argList);
6178
6179                 substDone=TRUE;
6180               }
6181               else /* no template arguments, compare argument lists directly */
6182               {
6183                 argList = mdAl;
6184               }
6185
6186               Debug::print(Debug::FindMembers,0,
6187                   "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
6188                   qPrint(argListToString(argList,TRUE)),qPrint(argListToString(root->argList,TRUE)),
6189                   qPrint(className),qPrint(namespaceName)
6190                   );
6191
6192               bool matching=
6193                 md->isVariable() || md->isTypedef() || // needed for function pointers
6194                 (mdAl==0 && root->argList->count()==0) ||
6195                 matchArguments2(
6196                     md->getClassDef(),md->getFileDef(),argList,
6197                     cd,fd,root->argList,
6198                     TRUE);
6199
6200               if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
6201               {
6202                 matching = FALSE; // don't match methods and attributes with the same name
6203               }
6204
6205               // for template member we also need to check the return type
6206               if (md->templateArguments()!=0 && root->tArgLists!=0)
6207               {
6208                 QCString memType = md->typeString();
6209                 memType.stripPrefix("static "); // see bug700696
6210                 funcType=substitute(stripTemplateSpecifiersFromScope(funcType,TRUE),
6211                                     className+"::",""); // see bug700693 & bug732594
6212                 memType=substitute(stripTemplateSpecifiersFromScope(memType,TRUE),
6213                                     className+"::",""); // see bug758900
6214                 Debug::print(Debug::FindMembers,0,
6215                    "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
6216                     qPrint(md->typeString()),qPrint(funcType),
6217                     md->templateArguments()->count(),root->tArgLists->getLast()->count());
6218                 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
6219                     qstrcmp(memType,funcType))
6220                 {
6221                   //printf(" ---> no matching\n");
6222                   matching = FALSE;
6223                 }
6224               }
6225               bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
6226               bool classIsTemplate = scopeIsTemplate(md->getClassDef());
6227               bool mdIsTemplate    = md->templateArguments()!=0;
6228               bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
6229               bool rootIsTemplate  = root->tArgLists!=0;
6230               //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
6231               if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
6232                   (mdIsTemplate || rootIsTemplate) && // either md or root is a template
6233                   ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
6234                  )
6235               {
6236                 // Method with template return type does not match method without return type
6237                 // even if the parameters are the same. See also bug709052
6238                 Debug::print(Debug::FindMembers,0,
6239                     "5b. Comparing return types: template v.s. non-template\n");
6240                 matching = FALSE;
6241               }
6242
6243
6244               Debug::print(Debug::FindMembers,0,
6245                   "6. match results of matchArguments2 = %d\n",matching);
6246
6247               if (substDone) // found a new argument list
6248               {
6249                 if (matching) // replace member's argument list
6250                 {
6251                   md->setDefinitionTemplateParameterLists(root->tArgLists);
6252                   md->setArgumentList(argList); // new owner of the list => no delete
6253                 }
6254                 else // no match
6255                 {
6256                   if (!funcTempList.isEmpty() &&
6257                       isSpecialization(declTemplArgs,*defTemplArgs))
6258                   {
6259                     // check if we are dealing with a partial template
6260                     // specialization. In this case we add it to the class
6261                     // even though the member arguments do not match.
6262
6263                     // TODO: copy other aspects?
6264                     root->protection=md->protection(); // copy protection level
6265                     addMethodToClass(rootNav,cd,md->name(),isFriend);
6266                     return;
6267                   }
6268                   delete argList;
6269                 }
6270               }
6271               if (matching)
6272               {
6273                 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
6274                 count++;
6275                 memFound=TRUE;
6276               }
6277             }
6278             else if (cd && cd!=tcd) // we did find a class with the same name as cd
6279                                     // but in a different namespace
6280             {
6281               noMatchCount++;
6282             }
6283           }
6284           if (count==0 && rootNav->parent() &&
6285               rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6286           {
6287             goto localObjCMethod;
6288           }
6289           if (count==0 && !(isFriend && funcType=="class"))
6290           {
6291             int candidates=0;
6292             ClassDef *ecd = 0, *ucd = 0;
6293             MemberDef *emd = 0, *umd = 0;
6294             if (mn->count()>0)
6295             {
6296               //printf("Assume template class\n");
6297               for (mni.toFirst();(md=mni.current());++mni)
6298               {
6299                 ClassDef *ccd=md->getClassDef();
6300                 MemberDef *cmd=md;
6301                 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
6302                 if (ccd!=0 && rightScopeMatch(ccd->name(),className))
6303                 {
6304                   ArgumentList *templAl = md->templateArguments();
6305                   if (root->tArgLists && templAl!=0 &&
6306                       root->tArgLists->getLast()->count()<=templAl->count())
6307                   {
6308                     addMethodToClass(rootNav,ccd,md->name(),isFriend);
6309                     return;
6310                   }
6311                   if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
6312                   { // exact argument list match -> remember
6313                     ucd = ecd = ccd;
6314                     umd = emd = cmd;
6315                     Debug::print(Debug::FindMembers,0,
6316                      "7. new candidate className=%s scope=%s args=%s exact match\n",
6317                          qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6318                   }
6319                   else // arguments do not match, but member name and scope do -> remember
6320                   {
6321                     ucd = ccd;
6322                     umd = cmd;
6323                     Debug::print(Debug::FindMembers,0,
6324                      "7. new candidate className=%s scope=%s args=%s no match\n",
6325                          qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6326                   }
6327                   candidates++;
6328                 }
6329               }
6330             }
6331             static bool strictProtoMatching = Config_getBool(STRICT_PROTO_MATCHING);
6332             if (!strictProtoMatching)
6333             {
6334               if (candidates==1 && ucd && umd)
6335               {
6336                 // we didn't find an actual match on argument lists, but there is only 1 member with this
6337                 // name in the same scope, so that has to be the one.
6338                 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
6339                 return;
6340               }
6341               else if (candidates>1 && ecd && emd)
6342               {
6343                 // we didn't find a unique match using type resolution,
6344                 // but one of the matches has the exact same signature so
6345                 // we take that one.
6346                 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
6347                 return;
6348               }
6349             }
6350
6351             QCString warnMsg = "no ";
6352             if (noMatchCount>1) warnMsg+="uniquely ";
6353             warnMsg+="matching class member found for \n";
6354
6355             if (root->tArgLists)
6356             {
6357               QListIterator<ArgumentList> alli(*root->tArgLists);
6358               ArgumentList *al;
6359               for (;(al=alli.current());++alli)
6360               {
6361                 warnMsg+="  template ";
6362                 warnMsg+=tempArgListToString(al,root->lang);
6363                 warnMsg+='\n';
6364               }
6365             }
6366             QCString fullFuncDecl=funcDecl.copy();
6367             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6368
6369             warnMsg+="  ";
6370             warnMsg+=fullFuncDecl;
6371             warnMsg+='\n';
6372
6373             if (candidates>0)
6374             {
6375               warnMsg+="Possible candidates:\n";
6376               for (mni.toFirst();(md=mni.current());++mni)
6377               {
6378                 ClassDef *cd=md->getClassDef();
6379                 if (cd!=0 && rightScopeMatch(cd->name(),className))
6380                 {
6381                   ArgumentList *templAl = md->templateArguments();
6382                   if (templAl!=0)
6383                   {
6384                     warnMsg+="  'template ";
6385                     warnMsg+=tempArgListToString(templAl,root->lang);
6386                     warnMsg+='\n';
6387                   }
6388                   warnMsg+="  ";
6389                   if (md->typeString())
6390                   {
6391                     warnMsg+=md->typeString();
6392                     warnMsg+=' ';
6393                   }
6394                   QCString qScope = cd->qualifiedNameWithTemplateParameters();
6395                   if (!qScope.isEmpty())
6396                     warnMsg+=qScope+"::"+md->name();
6397                   if (md->argsString())
6398                     warnMsg+=md->argsString();
6399                   if (noMatchCount>1)
6400                   {
6401                     warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6402                              " of file "+md->getDefFileName();
6403                   }
6404
6405                   warnMsg+='\n';
6406                 }
6407               }
6408             }
6409             warn_simple(root->fileName,root->startLine,warnMsg);
6410           }
6411         }
6412         else if (cd) // member specialization
6413         {
6414           MemberNameIterator mni(*mn);
6415           MemberDef *declMd=0;
6416           MemberDef *md=0;
6417           for (mni.toFirst();(md=mni.current());++mni)
6418           {
6419             if (md->getClassDef()==cd)
6420             {
6421               // TODO: we should probably also check for matching arguments
6422               declMd = md;
6423               break;
6424             }
6425           }
6426           MemberType mtype=MemberType_Function;
6427           ArgumentList *tArgList = new ArgumentList;
6428           //  getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6429           md=new MemberDef(
6430               root->fileName,root->startLine,root->startColumn,
6431               funcType,funcName,funcArgs,exceptions,
6432               declMd ? declMd->protection() : root->protection,
6433               root->virt,root->stat,Member,
6434               mtype,tArgList,root->argList);
6435           //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6436           md->setTagInfo(rootNav->tagInfo());
6437           md->setLanguage(root->lang);
6438           md->setId(root->id);
6439           md->setMemberClass(cd);
6440           md->setTemplateSpecialization(TRUE);
6441           md->setTypeConstraints(root->typeConstr);
6442           md->setDefinition(funcDecl);
6443           md->enableCallGraph(root->callGraph);
6444           md->enableCallerGraph(root->callerGraph);
6445           md->setDocumentation(root->doc,root->docFile,root->docLine);
6446           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6447           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6448           md->setDocsForDefinition(!root->proto);
6449           md->setPrototype(root->proto);
6450           md->addSectionsToDefinition(root->anchors);
6451           md->setBodySegment(root->bodyLine,root->endBodyLine);
6452           FileDef *fd=rootNav->fileDef();
6453           md->setBodyDef(fd);
6454           md->setMemberSpecifiers(root->spec);
6455           md->setMemberGroupId(root->mGrpId);
6456           mn->append(md);
6457           cd->insertMember(md);
6458           md->setRefItems(root->sli);
6459           delete tArgList;
6460         }
6461         else
6462         {
6463           //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6464           //        scopeName.data(),funcName.data(),funcArgs.data());
6465         }
6466       }
6467       else if (overloaded) // check if the function belongs to only one class
6468       {
6469         // for unique overloaded member we allow the class to be
6470         // omitted, this is to be Qt compatible. Using this should
6471         // however be avoided, because it is error prone
6472         MemberNameIterator mni(*mn);
6473         MemberDef *md=mni.toFirst();
6474         ASSERT(md);
6475         ClassDef *cd=md->getClassDef();
6476         ASSERT(cd);
6477         QCString className=cd->name().copy();
6478         ++mni;
6479         bool unique=TRUE;
6480         for (;(md=mni.current());++mni)
6481         {
6482           ClassDef *cd=md->getClassDef();
6483           if (className!=cd->name()) unique=FALSE;
6484         }
6485         if (unique)
6486         {
6487           MemberType mtype;
6488           if      (root->mtype==Signal)  mtype=MemberType_Signal;
6489           else if (root->mtype==Slot)    mtype=MemberType_Slot;
6490           else if (root->mtype==DCOP)    mtype=MemberType_DCOP;
6491           else                           mtype=MemberType_Function;
6492
6493           // new overloaded member function
6494           ArgumentList *tArgList =
6495             getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6496           //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6497           MemberDef *md=new MemberDef(
6498               root->fileName,root->startLine,root->startColumn,
6499               funcType,funcName,funcArgs,exceptions,
6500               root->protection,root->virt,root->stat,Related,
6501               mtype,tArgList,root->argList);
6502           md->setTagInfo(rootNav->tagInfo());
6503           md->setLanguage(root->lang);
6504           md->setId(root->id);
6505           md->setTypeConstraints(root->typeConstr);
6506           md->setMemberClass(cd);
6507           md->setDefinition(funcDecl);
6508           md->enableCallGraph(root->callGraph);
6509           md->enableCallerGraph(root->callerGraph);
6510           QCString doc=getOverloadDocs();
6511           doc+="<p>";
6512           doc+=root->doc;
6513           md->setDocumentation(doc,root->docFile,root->docLine);
6514           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6515           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6516           md->setDocsForDefinition(!root->proto);
6517           md->setPrototype(root->proto);
6518           md->addSectionsToDefinition(root->anchors);
6519           md->setBodySegment(root->bodyLine,root->endBodyLine);
6520           FileDef *fd=rootNav->fileDef();
6521           md->setBodyDef(fd);
6522           md->setMemberSpecifiers(root->spec);
6523           md->setMemberGroupId(root->mGrpId);
6524           mn->append(md);
6525           cd->insertMember(md);
6526           cd->insertUsedFile(fd);
6527           md->setRefItems(root->sli);
6528         }
6529       }
6530       else // unrelated function with the same name as a member
6531       {
6532         if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6533         {
6534           QCString fullFuncDecl=funcDecl.copy();
6535           if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6536           warn(root->fileName,root->startLine,
6537                "Cannot determine class for function\n%s",
6538                fullFuncDecl.data()
6539               );
6540         }
6541       }
6542     }
6543     else if (isRelated && !root->relates.isEmpty())
6544     {
6545       Debug::print(Debug::FindMembers,0,"2. related function\n"
6546               "  scopeName=%s className=%s\n",qPrint(scopeName),qPrint(className));
6547       if (className.isEmpty()) className=root->relates;
6548       ClassDef *cd;
6549       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6550       if ((cd=getClass(scopeName)))
6551       {
6552         bool newMember=TRUE; // assume we have a new member
6553         bool newMemberName=FALSE;
6554         MemberDef *mdDefine=0;
6555         bool isDefine=FALSE;
6556         {
6557           MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6558           if (mn)
6559           {
6560             MemberNameIterator mni(*mn);
6561             mdDefine = mni.current();
6562             while (mdDefine && !isDefine)
6563             {
6564               isDefine = isDefine || mdDefine->isDefine();
6565               if (!isDefine) { ++mni; mdDefine=mni.current(); }
6566             }
6567           }
6568         }
6569
6570         FileDef *fd=rootNav->fileDef();
6571
6572         if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6573         {
6574           mn=new MemberName(funcName);
6575           newMemberName=TRUE; // we create a new member name
6576         }
6577         else
6578         {
6579           MemberNameIterator mni(*mn);
6580           MemberDef *rmd;
6581           while ((rmd=mni.current()) && newMember) // see if we got another member with matching arguments
6582           {
6583             ArgumentList *rmdAl = rmd->argumentList();
6584
6585             newMember=
6586               className!=rmd->getOuterScope()->name() ||
6587               !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6588                                cd,fd,root->argList,
6589                                TRUE);
6590             if (newMember) ++mni;
6591           }
6592           if (!newMember && rmd) // member already exists as rmd -> add docs
6593           {
6594             //printf("addMemberDocs for related member %s\n",root->name.data());
6595             //rmd->setMemberDefTemplateArguments(root->mtArgList);
6596             addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6597           }
6598         }
6599
6600         if (newMember) // need to create a new member
6601         {
6602           MemberType mtype;
6603           if (isDefine)
6604             mtype=MemberType_Define;
6605           else if (root->mtype==Signal)
6606             mtype=MemberType_Signal;
6607           else if (root->mtype==Slot)
6608             mtype=MemberType_Slot;
6609           else if (root->mtype==DCOP)
6610             mtype=MemberType_DCOP;
6611           else
6612             mtype=MemberType_Function;
6613
6614           if (isDefine && mdDefine)
6615           {
6616             mdDefine->setHidden(TRUE);
6617             funcType="#define";
6618             funcArgs=mdDefine->argsString();
6619             funcDecl=funcType + " " + funcName;
6620           }
6621
6622           //printf("New related name `%s' `%d'\n",funcName.data(),
6623           //    root->argList ? (int)root->argList->count() : -1);
6624
6625           // first note that we pass:
6626           //   (root->tArgLists ? root->tArgLists->last() : 0)
6627           // for the template arguments fo the new "member."
6628           // this accurately reflects the template arguments of
6629           // the related function, which don't have to do with
6630           // those of the related class.
6631           MemberDef *md=new MemberDef(
6632               root->fileName,root->startLine,root->startColumn,
6633               funcType,funcName,funcArgs,exceptions,
6634               root->protection,root->virt,
6635               root->stat && !isMemberOf,
6636               isMemberOf ? Foreign : Related,
6637               mtype,
6638               (root->tArgLists ? root->tArgLists->getLast() : 0),
6639               funcArgs.isEmpty() ? 0 : root->argList);
6640
6641           if (isDefine && mdDefine)
6642           {
6643             md->setInitializer(mdDefine->initializer());
6644           }
6645
6646           //
6647           // we still have the problem that
6648           // MemberDef::writeDocumentation() in memberdef.cpp
6649           // writes the template argument list for the class,
6650           // as if this member is a member of the class.
6651           // fortunately, MemberDef::writeDocumentation() has
6652           // a special mechanism that allows us to totally
6653           // override the set of template argument lists that
6654           // are printed.  We use that and set it to the
6655           // template argument lists of the related function.
6656           //
6657           md->setDefinitionTemplateParameterLists(root->tArgLists);
6658
6659           md->setTagInfo(rootNav->tagInfo());
6660
6661
6662
6663           //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6664           //       funcName.data(),funcDecl.data(),root->bodyLine);
6665
6666           // try to find the matching line number of the body from the
6667           // global function list
6668           bool found=FALSE;
6669           if (root->bodyLine==-1)
6670           {
6671             MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6672             if (rmn)
6673             {
6674               MemberNameIterator rmni(*rmn);
6675               MemberDef *rmd;
6676               while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
6677               {
6678                 ArgumentList *rmdAl = rmd->argumentList();
6679                 // check for matching argument lists
6680                 if (
6681                     matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6682                                     cd,fd,root->argList,
6683                                     TRUE)
6684                    )
6685                 {
6686                   found=TRUE;
6687                 }
6688                 if (!found) ++rmni;
6689               }
6690               if (rmd) // member found -> copy line number info
6691               {
6692                 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6693                 md->setBodyDef(rmd->getBodyDef());
6694                 //md->setBodyMember(rmd);
6695               }
6696             }
6697           }
6698           if (!found) // line number could not be found or is available in this
6699                       // entry
6700           {
6701             md->setBodySegment(root->bodyLine,root->endBodyLine);
6702             md->setBodyDef(fd);
6703           }
6704
6705           //if (root->mGrpId!=-1)
6706           //{
6707           //  md->setMemberGroup(memberGroupDict[root->mGrpId]);
6708           //}
6709           md->setMemberClass(cd);
6710           md->setMemberSpecifiers(root->spec);
6711           md->setDefinition(funcDecl);
6712           md->enableCallGraph(root->callGraph);
6713           md->enableCallerGraph(root->callerGraph);
6714           md->setDocumentation(root->doc,root->docFile,root->docLine);
6715           md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6716           md->setDocsForDefinition(!root->proto);
6717           md->setPrototype(root->proto);
6718           md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6719           md->addSectionsToDefinition(root->anchors);
6720           md->setMemberGroupId(root->mGrpId);
6721           md->setLanguage(root->lang);
6722           md->setId(root->id);
6723           //md->setMemberDefTemplateArguments(root->mtArgList);
6724           mn->append(md);
6725           cd->insertMember(md);
6726           cd->insertUsedFile(fd);
6727           md->setRefItems(root->sli);
6728           if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6729           if (!isDefine)
6730           {
6731             addMemberToGroups(root,md);
6732           }
6733           //printf("Adding member=%s\n",md->name().data());
6734           if (newMemberName)
6735           {
6736             //Doxygen::memberNameList.append(mn);
6737             //Doxygen::memberNameDict.insert(funcName,mn);
6738             Doxygen::memberNameSDict->append(funcName,mn);
6739           }
6740         }
6741         if (root->relatesType == Duplicate)
6742         {
6743           if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6744           {
6745             QCString fullFuncDecl=funcDecl.copy();
6746             if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6747             warn(root->fileName,root->startLine,
6748                "Cannot determine file/namespace for relatedalso function\n%s",
6749                fullFuncDecl.data()
6750               );
6751           }
6752         }
6753       }
6754       else
6755       {
6756         warn_undoc(root->fileName,root->startLine,
6757                    "class `%s' for related function `%s' is not "
6758                    "documented.",
6759                    className.data(),funcName.data()
6760                   );
6761       }
6762     }
6763     else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6764     {
6765 localObjCMethod:
6766       ClassDef *cd;
6767       //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6768       if (Config_getBool(EXTRACT_LOCAL_METHODS) && (cd=getClass(scopeName)))
6769       {
6770         Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6771               "  scopeName=%s className=%s\n",qPrint(root->name),qPrint(scopeName),qPrint(className));
6772         //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6773         MemberDef *md=new MemberDef(
6774             root->fileName,root->startLine,root->startColumn,
6775             funcType,funcName,funcArgs,exceptions,
6776             root->protection,root->virt,root->stat,Member,
6777             MemberType_Function,0,root->argList);
6778         md->setTagInfo(rootNav->tagInfo());
6779         md->setLanguage(root->lang);
6780         md->setId(root->id);
6781         md->makeImplementationDetail();
6782         md->setMemberClass(cd);
6783         md->setDefinition(funcDecl);
6784         md->enableCallGraph(root->callGraph);
6785         md->enableCallerGraph(root->callerGraph);
6786         md->setDocumentation(root->doc,root->docFile,root->docLine);
6787         md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6788         md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6789         md->setDocsForDefinition(!root->proto);
6790         md->setPrototype(root->proto);
6791         md->addSectionsToDefinition(root->anchors);
6792         md->setBodySegment(root->bodyLine,root->endBodyLine);
6793         FileDef *fd=rootNav->fileDef();
6794         md->setBodyDef(fd);
6795         md->setMemberSpecifiers(root->spec);
6796         md->setMemberGroupId(root->mGrpId);
6797         cd->insertMember(md);
6798         cd->insertUsedFile(fd);
6799         md->setRefItems(root->sli);
6800         if ((mn=Doxygen::memberNameSDict->find(root->name)))
6801         {
6802           mn->append(md);
6803         }
6804         else
6805         {
6806           mn = new MemberName(root->name);
6807           mn->append(md);
6808           Doxygen::memberNameSDict->append(root->name,mn);
6809         }
6810       }
6811       else
6812       {
6813         // local objective C method found for class without interface
6814       }
6815     }
6816     else // unrelated not overloaded member found
6817     {
6818       bool globMem = findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl);
6819       if (className.isEmpty() && !globMem)
6820       {
6821         warn(root->fileName,root->startLine,
6822              "class for member `%s' cannot "
6823              "be found.", funcName.data()
6824             );
6825       }
6826       else if (!className.isEmpty() && !globMem)
6827       {
6828         warn(root->fileName,root->startLine,
6829              "member `%s' of class `%s' cannot be found",
6830              funcName.data(),className.data());
6831       }
6832     }
6833   }
6834   else
6835   {
6836     // this should not be called
6837     warn(root->fileName,root->startLine,
6838          "member with no name found.");
6839   }
6840   return;
6841 }
6842
6843 //----------------------------------------------------------------------
6844 // find the members corresponding to the different documentation blocks
6845 // that are extracted from the sources.
6846
6847 static void filterMemberDocumentation(EntryNav *rootNav)
6848 {
6849   Entry *root = rootNav->entry();
6850   int i=-1,l;
6851   Debug::print(Debug::FindMembers,0,
6852       "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6853       qPrint(root->type),qPrint(root->inside),qPrint(root->name),qPrint(root->args),root->section,root->spec,root->mGrpId
6854       );
6855   //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6856   bool isFunc=TRUE;
6857
6858   if (root->relatesType == Duplicate && !root->relates.isEmpty())
6859   {
6860     QCString tmp = root->relates;
6861     root->relates.resize(0);
6862     filterMemberDocumentation(rootNav);
6863     root->relates = tmp;
6864   }
6865
6866   if ( // detect func variable/typedef to func ptr
6867       (i=findFunctionPtr(root->type,root->lang,&l))!=-1
6868      )
6869   {
6870     //printf("Fixing function pointer!\n");
6871     // fix type and argument
6872     root->args.prepend(root->type.right(root->type.length()-i-l));
6873     root->type=root->type.left(i+l);
6874     //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6875     isFunc=FALSE;
6876   }
6877   else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1))
6878     // detect function types marked as functions
6879   {
6880     isFunc=FALSE;
6881   }
6882
6883   //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6884   if (root->section==Entry::MEMBERDOC_SEC)
6885   {
6886     //printf("Documentation for inline member `%s' found args=`%s'\n",
6887     //    root->name.data(),root->args.data());
6888     //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
6889     if (root->type.isEmpty())
6890     {
6891       findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6892     }
6893     else
6894     {
6895       findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6896     }
6897   }
6898   else if (root->section==Entry::OVERLOADDOC_SEC)
6899   {
6900     //printf("Overloaded member %s found\n",root->name.data());
6901     findMember(rootNav,root->name,TRUE,isFunc);
6902   }
6903   else if
6904     ((root->section==Entry::FUNCTION_SEC      // function
6905       ||
6906       (root->section==Entry::VARIABLE_SEC &&  // variable
6907        !root->type.isEmpty() &&                // with a type
6908        g_compoundKeywordDict.find(root->type)==0 // that is not a keyword
6909        // (to skip forward declaration of class etc.)
6910       )
6911      )
6912     )
6913     {
6914       //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6915       //    root->name.data(),root->args.data(),root->exception.data());
6916       //if (root->relates.length()) printf("  Relates %s\n",root->relates.data());
6917       //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6918       if (root->type=="friend class" || root->type=="friend struct" ||
6919           root->type=="friend union")
6920       {
6921         findMember(rootNav,
6922             root->type+" "+
6923             root->name,
6924             FALSE,FALSE);
6925
6926       }
6927       else if (!root->type.isEmpty())
6928       {
6929         findMember(rootNav,
6930             root->type+" "+
6931             root->inside+
6932             root->name+
6933             root->args+
6934             root->exception,
6935             FALSE,isFunc);
6936       }
6937       else
6938       {
6939         findMember(rootNav,
6940             root->inside+
6941             root->name+
6942             root->args+
6943             root->exception,
6944             FALSE,isFunc);
6945       }
6946     }
6947   else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6948   {
6949     findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6950   }
6951   else if (root->section==Entry::VARIABLEDOC_SEC)
6952   {
6953     //printf("Documentation for variable %s found\n",root->name.data());
6954     //if (!root->relates.isEmpty()) printf("  Relates %s\n",root->relates.data());
6955     findMember(rootNav,root->name,FALSE,FALSE);
6956   }
6957   else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
6958            root->section==Entry::INCLUDED_SERVICE_SEC)
6959   {
6960     findMember(rootNav,root->type + " " + root->name,FALSE,FALSE);
6961   }
6962   else
6963   {
6964     // skip section
6965     //printf("skip section\n");
6966   }
6967 }
6968
6969 static void findMemberDocumentation(EntryNav *rootNav)
6970 {
6971   if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6972       rootNav->section()==Entry::OVERLOADDOC_SEC ||
6973       rootNav->section()==Entry::FUNCTION_SEC ||
6974       rootNav->section()==Entry::VARIABLE_SEC ||
6975       rootNav->section()==Entry::VARIABLEDOC_SEC ||
6976       rootNav->section()==Entry::DEFINE_SEC ||
6977       rootNav->section()==Entry::INCLUDED_SERVICE_SEC ||
6978       rootNav->section()==Entry::EXPORTED_INTERFACE_SEC
6979      )
6980   {
6981     rootNav->loadEntry(g_storage);
6982
6983     filterMemberDocumentation(rootNav);
6984
6985     rootNav->releaseEntry();
6986   }
6987   if (rootNav->children())
6988   {
6989     EntryNavListIterator eli(*rootNav->children());
6990     EntryNav *e;
6991     for (;(e=eli.current());++eli)
6992     {
6993       if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6994     }
6995   }
6996 }
6997
6998 //----------------------------------------------------------------------
6999
7000 static void findObjCMethodDefinitions(EntryNav *rootNav)
7001 {
7002   if (rootNav->children())
7003   {
7004     EntryNavListIterator eli(*rootNav->children());
7005     EntryNav *objCImplNav;
7006     for (;(objCImplNav=eli.current());++eli)
7007     {
7008       if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
7009       {
7010         EntryNavListIterator seli(*objCImplNav->children());
7011         EntryNav *objCMethodNav;
7012         for (;(objCMethodNav=seli.current());++seli)
7013         {
7014           if (objCMethodNav->section()==Entry::FUNCTION_SEC)
7015           {
7016             objCMethodNav->loadEntry(g_storage);
7017             Entry *objCMethod = objCMethodNav->entry();
7018
7019             //Printf("  Found ObjC method definition %s\n",objCMethod->name.data());
7020             findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
7021                        objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
7022             objCMethod->section=Entry::EMPTY_SEC;
7023
7024             objCMethodNav->releaseEntry();
7025           }
7026         }
7027       }
7028     }
7029   }
7030 }
7031
7032 //----------------------------------------------------------------------
7033 // find and add the enumeration to their classes, namespaces or files
7034
7035 static void findEnums(EntryNav *rootNav)
7036 {
7037   if (rootNav->section()==Entry::ENUM_SEC)
7038   {
7039     rootNav->loadEntry(g_storage);
7040     Entry *root = rootNav->entry();
7041
7042     MemberDef      *md=0;
7043     ClassDef       *cd=0;
7044     FileDef        *fd=0;
7045     NamespaceDef   *nd=0;
7046     MemberNameSDict *mnsd=0;
7047     bool isGlobal;
7048     bool isRelated=FALSE;
7049     bool isMemberOf=FALSE;
7050     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7051     int i;
7052
7053     QCString name;
7054     QCString scope;
7055
7056     if ((i=root->name.findRev("::"))!=-1) // scope is specified
7057     {
7058       scope=root->name.left(i); // extract scope
7059       name=root->name.right(root->name.length()-i-2); // extract name
7060       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7061     }
7062     else // no scope, check the scope in which the docs where found
7063     {
7064       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7065           && !rootNav->parent()->name().isEmpty()
7066          ) // found enum docs inside a compound
7067       {
7068         scope=rootNav->parent()->name();
7069         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7070       }
7071       name=root->name;
7072     }
7073
7074     if (!root->relates.isEmpty())
7075     {   // related member, prefix user specified scope
7076       isRelated=TRUE;
7077       isMemberOf=(root->relatesType == MemberOf);
7078       if (getClass(root->relates)==0 && !scope.isEmpty())
7079         scope=mergeScopes(scope,root->relates);
7080       else
7081         scope=root->relates.copy();
7082       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7083     }
7084
7085     if (cd && !name.isEmpty()) // found a enum inside a compound
7086     {
7087       //printf("Enum `%s'::`%s'\n",cd->name().data(),name.data());
7088       fd=0;
7089       mnsd=Doxygen::memberNameSDict;
7090       isGlobal=FALSE;
7091     }
7092     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7093     {
7094       mnsd=Doxygen::functionNameSDict;
7095       isGlobal=TRUE;
7096     }
7097     else // found a global enum
7098     {
7099       fd=rootNav->fileDef();
7100       mnsd=Doxygen::functionNameSDict;
7101       isGlobal=TRUE;
7102     }
7103
7104     if (!name.isEmpty())
7105     {
7106       // new enum type
7107       md = new MemberDef(
7108           root->fileName,root->startLine,root->startColumn,
7109           0,name,0,0,
7110           root->protection,Normal,FALSE,
7111           isMemberOf ? Foreign : isRelated ? Related : Member,
7112           MemberType_Enumeration,
7113           0,0);
7114       md->setTagInfo(rootNav->tagInfo());
7115       md->setLanguage(root->lang);
7116       md->setId(root->id);
7117       if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7118       md->setBodySegment(root->bodyLine,root->endBodyLine);
7119       md->setBodyDef(rootNav->fileDef());
7120       md->setMemberSpecifiers(root->spec);
7121       md->setEnumBaseType(root->args);
7122       //printf("Enum %s definition at line %d of %s: protection=%d scope=%s\n",
7123       //    root->name.data(),root->bodyLine,root->fileName.data(),root->protection,cd?cd->name().data():"<none>");
7124       md->addSectionsToDefinition(root->anchors);
7125       md->setMemberGroupId(root->mGrpId);
7126       md->enableCallGraph(root->callGraph);
7127       md->enableCallerGraph(root->callerGraph);
7128       //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
7129       md->setRefItems(root->sli);
7130       //printf("found enum %s nd=%p\n",md->name().data(),nd);
7131       bool defSet=FALSE;
7132
7133       QCString baseType = root->args;
7134       if (!baseType.isEmpty())
7135       {
7136         baseType.prepend(" : ");
7137       }
7138
7139       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7140       {
7141         if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7142         {
7143           md->setDefinition(name+baseType);
7144         }
7145         else
7146         {
7147           md->setDefinition(nd->name()+"::"+name+baseType);
7148         }
7149         //printf("definition=%s\n",md->definition());
7150         defSet=TRUE;
7151         md->setNamespace(nd);
7152         nd->insertMember(md);
7153       }
7154
7155       // even if we have already added the enum to a namespace, we still
7156       // also want to add it to other appropriate places such as file
7157       // or class.
7158       if (isGlobal)
7159       {
7160         if (!defSet) md->setDefinition(name+baseType);
7161         if (fd==0 && rootNav->parent())
7162         {
7163           fd=rootNav->parent()->fileDef();
7164         }
7165         if (fd)
7166         {
7167           md->setFileDef(fd);
7168           fd->insertMember(md);
7169         }
7170       }
7171       else if (cd)
7172       {
7173         if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7174         {
7175           md->setDefinition(name+baseType);
7176         }
7177         else
7178         {
7179           md->setDefinition(cd->name()+"::"+name+baseType);
7180         }
7181         cd->insertMember(md);
7182         cd->insertUsedFile(fd);
7183       }
7184       md->setDocumentation(root->doc,root->docFile,root->docLine);
7185       md->setDocsForDefinition(!root->proto);
7186       md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7187       md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7188
7189       //printf("Adding member=%s\n",md->name().data());
7190       MemberName *mn;
7191       if ((mn=(*mnsd)[name]))
7192       {
7193         // this is used if the same enum is in multiple namespaces/classes
7194         mn->append(md);
7195       }
7196       else // new enum name
7197       {
7198         mn = new MemberName(name);
7199         mn->append(md);
7200         mnsd->append(name,mn);
7201         //printf("add %s to new memberName. Now %d members\n",
7202         //       name.data(),mn->count());
7203       }
7204       addMemberToGroups(root,md);
7205     }
7206     rootNav->releaseEntry();
7207   }
7208   else
7209   {
7210     RECURSE_ENTRYTREE(findEnums,rootNav);
7211   }
7212 }
7213
7214 //----------------------------------------------------------------------
7215
7216 static void addEnumValuesToEnums(EntryNav *rootNav)
7217 {
7218   if (rootNav->section()==Entry::ENUM_SEC)
7219     // non anonymous enumeration
7220   {
7221     rootNav->loadEntry(g_storage);
7222     Entry *root = rootNav->entry();
7223
7224     ClassDef       *cd=0;
7225     FileDef        *fd=0;
7226     NamespaceDef   *nd=0;
7227     MemberNameSDict *mnsd=0;
7228     bool isGlobal;
7229     bool isRelated=FALSE;
7230     //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7231     int i;
7232
7233     QCString name;
7234     QCString scope;
7235
7236     if ((i=root->name.findRev("::"))!=-1) // scope is specified
7237     {
7238       scope=root->name.left(i); // extract scope
7239       name=root->name.right(root->name.length()-i-2); // extract name
7240       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7241     }
7242     else // no scope, check the scope in which the docs where found
7243     {
7244       if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7245           && !rootNav->parent()->name().isEmpty()
7246          ) // found enum docs inside a compound
7247       {
7248         scope=rootNav->parent()->name();
7249         if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7250       }
7251       name=root->name;
7252     }
7253
7254     if (!root->relates.isEmpty())
7255     {   // related member, prefix user specified scope
7256       isRelated=TRUE;
7257       if (getClass(root->relates)==0 && !scope.isEmpty())
7258         scope=mergeScopes(scope,root->relates);
7259       else
7260         scope=root->relates.copy();
7261       if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7262     }
7263
7264     if (cd && !name.isEmpty()) // found a enum inside a compound
7265     {
7266       //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
7267       fd=0;
7268       mnsd=Doxygen::memberNameSDict;
7269       isGlobal=FALSE;
7270     }
7271     else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7272     {
7273       //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
7274       mnsd=Doxygen::functionNameSDict;
7275       isGlobal=TRUE;
7276     }
7277     else // found a global enum
7278     {
7279       fd=rootNav->fileDef();
7280       //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
7281       mnsd=Doxygen::functionNameSDict;
7282       isGlobal=TRUE;
7283     }
7284
7285     if (!name.isEmpty())
7286     {
7287       //printf("** name=%s\n",name.data());
7288       MemberName *mn = mnsd->find(name); // for all members with this name
7289       if (mn)
7290       {
7291         MemberNameIterator mni(*mn);
7292         MemberDef *md;
7293         for (mni.toFirst(); (md=mni.current()) ; ++mni)  // for each enum in this list
7294         {
7295           if (md->isEnumerate() && rootNav->children())
7296           {
7297             //printf("   enum with %d children\n",rootNav->children()->count());
7298             EntryNavListIterator eli(*rootNav->children()); // for each enum value
7299             EntryNav *e;
7300             for (;(e=eli.current());++eli)
7301             {
7302               SrcLangExt sle;
7303               if (
7304                    (sle=rootNav->lang())==SrcLangExt_CSharp ||
7305                    sle==SrcLangExt_Java ||
7306                    sle==SrcLangExt_XML ||
7307                    (root->spec&Entry::Strong)
7308                  )
7309               {
7310                 // Unlike classic C/C++ enums, for C++11, C# & Java enum
7311                 // values are only visible inside the enum scope, so we must create
7312                 // them here and only add them to the enum
7313                 e->loadEntry(g_storage);
7314                 Entry *root = e->entry();
7315                 //printf("md->qualifiedName()=%s rootNav->name()=%s tagInfo=%p name=%s\n",
7316                 //    md->qualifiedName().data(),rootNav->name().data(),rootNav->tagInfo(),root->name.data());
7317                 QCString qualifiedName = substitute(rootNav->name(),"::",".");
7318                 if (!scope.isEmpty() && rootNav->tagInfo())
7319                 {
7320                   qualifiedName=substitute(scope,"::",".")+"."+qualifiedName;
7321                 }
7322                 if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7323                     qualifiedName       // enum value scope matches that of the enum
7324                    )
7325                 {
7326                   QCString fileName = root->fileName;
7327                   if (fileName.isEmpty() && rootNav->tagInfo())
7328                   {
7329                     fileName = rootNav->tagInfo()->tagName;
7330                   }
7331                   MemberDef *fmd=new MemberDef(
7332                       fileName,root->startLine,root->startColumn,
7333                       root->type,root->name,root->args,0,
7334                       root->protection, Normal,root->stat,Member,
7335                       MemberType_EnumValue,0,0);
7336                   if      (md->getClassDef())     fmd->setMemberClass(md->getClassDef());
7337                   else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
7338                   else if (md->getFileDef())      fmd->setFileDef(md->getFileDef());
7339                   fmd->setOuterScope(md->getOuterScope());
7340                   fmd->setTagInfo(e->tagInfo());
7341                   fmd->setLanguage(root->lang);
7342                   fmd->setId(root->id);
7343                   fmd->setDocumentation(root->doc,root->docFile,root->docLine);
7344                   fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7345                   fmd->addSectionsToDefinition(root->anchors);
7346                   fmd->setInitializer(root->initializer);
7347                   fmd->setMaxInitLines(root->initLines);
7348                   fmd->setMemberGroupId(root->mGrpId);
7349                   fmd->setExplicitExternal(root->explicitExternal);
7350                   fmd->setRefItems(root->sli);
7351                   fmd->setAnchor();
7352                   md->insertEnumField(fmd);
7353                   fmd->setEnumScope(md,TRUE);
7354                   MemberName *mn=mnsd->find(root->name);
7355                   if (mn)
7356                   {
7357                     mn->append(fmd);
7358                   }
7359                   else
7360                   {
7361                     mn = new MemberName(root->name);
7362                     mn->append(fmd);
7363                     mnsd->append(root->name,mn);
7364                   }
7365                 }
7366                 e->releaseEntry();
7367               }
7368               else
7369               {
7370                 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
7371                 MemberName *fmn=0;
7372                 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
7373                 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
7374                   // get list of members with the same name as the field
7375                 {
7376                   MemberNameIterator fmni(*fmn);
7377                   MemberDef *fmd;
7378                   for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
7379                   {
7380                     if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7381                     {
7382                       //printf("found enum value with same name %s in scope %s\n",
7383                       //    fmd->name().data(),fmd->getOuterScope()->name().data());
7384                       if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7385                       {
7386                         NamespaceDef *fnd=fmd->getNamespaceDef();
7387                         if (fnd==nd) // enum value is inside a namespace
7388                         {
7389                           md->insertEnumField(fmd);
7390                           fmd->setEnumScope(md);
7391                         }
7392                       }
7393                       else if (isGlobal)
7394                       {
7395                         FileDef *ffd=fmd->getFileDef();
7396                         if (ffd==fd) // enum value has file scope
7397                         {
7398                           md->insertEnumField(fmd);
7399                           fmd->setEnumScope(md);
7400                         }
7401                       }
7402                       else if (isRelated && cd) // reparent enum value to
7403                                                 // match the enum's scope
7404                       {
7405                         md->insertEnumField(fmd);   // add field def to list
7406                         fmd->setEnumScope(md);      // cross ref with enum name
7407                         fmd->setEnumClassScope(cd); // cross ref with enum name
7408                         fmd->setOuterScope(cd);
7409                         fmd->makeRelated();
7410                         cd->insertMember(fmd);
7411                       }
7412                       else
7413                       {
7414                         ClassDef *fcd=fmd->getClassDef();
7415                         if (fcd==cd) // enum value is inside a class
7416                         {
7417                           //printf("Inserting enum field %s in enum scope %s\n",
7418                           //    fmd->name().data(),md->name().data());
7419                           md->insertEnumField(fmd); // add field def to list
7420                           fmd->setEnumScope(md);    // cross ref with enum name
7421                         }
7422                       }
7423                     }
7424                   }
7425                 }
7426               }
7427             }
7428           }
7429         }
7430       }
7431     }
7432
7433     rootNav->releaseEntry();
7434   }
7435   else
7436   {
7437     RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7438   }
7439 }
7440
7441
7442 //----------------------------------------------------------------------
7443 // find the documentation blocks for the enumerations
7444
7445 static void findEnumDocumentation(EntryNav *rootNav)
7446 {
7447   if (rootNav->section()==Entry::ENUMDOC_SEC
7448       && !rootNav->name().isEmpty()
7449       && rootNav->name().at(0)!='@'        // skip anonymous enums
7450      )
7451   {
7452     rootNav->loadEntry(g_storage);
7453     Entry *root = rootNav->entry();
7454
7455     //printf("Found docs for enum with name `%s' in context %s\n",
7456     //    root->name.data(),root->parent->name.data());
7457     int i;
7458     QCString name;
7459     QCString scope;
7460     if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7461     {
7462       name=root->name.right(root->name.length()-i-2); // extract name
7463       scope=root->name.left(i); // extract scope
7464       //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7465     }
7466     else // just the name
7467     {
7468       name=root->name;
7469     }
7470     if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7471         && !rootNav->parent()->name().isEmpty()
7472        ) // found enum docs inside a compound
7473     {
7474       if (!scope.isEmpty()) scope.prepend("::");
7475       scope.prepend(rootNav->parent()->name());
7476     }
7477     ClassDef *cd=getClass(scope);
7478
7479     if (!name.isEmpty())
7480     {
7481       bool found=FALSE;
7482       if (cd)
7483       {
7484         //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7485         QCString className=cd->name().copy();
7486         MemberName *mn=Doxygen::memberNameSDict->find(name);
7487         if (mn)
7488         {
7489           MemberNameIterator mni(*mn);
7490           MemberDef *md;
7491           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7492           {
7493             ClassDef *cd=md->getClassDef();
7494             if (cd && cd->name()==className && md->isEnumerate())
7495             {
7496               // documentation outside a compound overrides the documentation inside it
7497 #if 0
7498               if (!md->documentation() || rootNav->parent()->name().isEmpty())
7499 #endif
7500               {
7501                 md->setDocumentation(root->doc,root->docFile,root->docLine);
7502                 md->setDocsForDefinition(!root->proto);
7503               }
7504
7505               // brief descriptions inside a compound override the documentation
7506               // outside it
7507 #if 0
7508               if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7509 #endif
7510               {
7511                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7512               }
7513
7514               if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7515               {
7516                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7517               }
7518
7519               if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7520               {
7521                 md->setMemberGroupId(root->mGrpId);
7522               }
7523
7524               md->addSectionsToDefinition(root->anchors);
7525               md->setRefItems(root->sli);
7526
7527               GroupDef *gd=md->getGroupDef();
7528               if (gd==0 &&root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7529               {
7530                 addMemberToGroups(root,md);
7531               }
7532
7533               found=TRUE;
7534             }
7535           }
7536         }
7537         else
7538         {
7539           //printf("MemberName %s not found!\n",name.data());
7540         }
7541       }
7542       else // enum outside class
7543       {
7544         //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7545         MemberName *mn=Doxygen::functionNameSDict->find(name);
7546         if (mn)
7547         {
7548           MemberNameIterator mni(*mn);
7549           MemberDef *md;
7550           for (mni.toFirst();(md=mni.current()) && !found;++mni)
7551           {
7552             if (md->isEnumerate())
7553             {
7554               md->setDocumentation(root->doc,root->docFile,root->docLine);
7555               md->setDocsForDefinition(!root->proto);
7556               md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7557               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7558               md->addSectionsToDefinition(root->anchors);
7559               md->setMemberGroupId(root->mGrpId);
7560
7561               GroupDef *gd=md->getGroupDef();
7562               if (gd==0 && root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7563               {
7564                 addMemberToGroups(root,md);
7565               }
7566
7567               found=TRUE;
7568             }
7569           }
7570         }
7571       }
7572       if (!found)
7573       {
7574         warn(root->fileName,root->startLine,
7575              "Documentation for undefined enum `%s' found.",
7576              name.data()
7577             );
7578       }
7579     }
7580
7581     rootNav->releaseEntry();
7582   }
7583   RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7584 }
7585
7586 // search for each enum (member or function) in mnl if it has documented
7587 // enum values.
7588 static void findDEV(const MemberNameSDict &mnsd)
7589 {
7590   MemberName *mn;
7591   MemberNameSDict::Iterator mnli(mnsd);
7592   // for each member name
7593   for (mnli.toFirst();(mn=mnli.current());++mnli)
7594   {
7595     MemberDef *md;
7596     MemberNameIterator mni(*mn);
7597     // for each member definition
7598     for (mni.toFirst();(md=mni.current());++mni)
7599     {
7600       if (md->isEnumerate()) // member is an enum
7601       {
7602         MemberList *fmdl = md->enumFieldList();
7603         int documentedEnumValues=0;
7604         if (fmdl) // enum has values
7605         {
7606           MemberListIterator fmni(*fmdl);
7607           MemberDef *fmd;
7608           // for each enum value
7609           for (fmni.toFirst();(fmd=fmni.current());++fmni)
7610           {
7611             if (fmd->isLinkableInProject()) documentedEnumValues++;
7612           }
7613         }
7614         // at least one enum value is documented
7615         if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7616       }
7617     }
7618   }
7619 }
7620
7621 // search for each enum (member or function) if it has documented enum
7622 // values.
7623 static void findDocumentedEnumValues()
7624 {
7625   findDEV(*Doxygen::memberNameSDict);
7626   findDEV(*Doxygen::functionNameSDict);
7627 }
7628
7629 //----------------------------------------------------------------------
7630
7631 static void addMembersToIndex()
7632 {
7633   MemberName *mn;
7634   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7635   // for each member name
7636   for (mnli.toFirst();(mn=mnli.current());++mnli)
7637   {
7638     MemberDef *md;
7639     MemberNameIterator mni(*mn);
7640     // for each member definition
7641     for (mni.toFirst();(md=mni.current());++mni)
7642     {
7643       addClassMemberNameToIndex(md);
7644     }
7645   }
7646   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7647   // for each member name
7648   for (fnli.toFirst();(mn=fnli.current());++fnli)
7649   {
7650     MemberDef *md;
7651     MemberNameIterator mni(*mn);
7652     // for each member definition
7653     for (mni.toFirst();(md=mni.current());++mni)
7654     {
7655       if (md->getNamespaceDef())
7656       {
7657         addNamespaceMemberNameToIndex(md);
7658       }
7659       else
7660       {
7661         addFileMemberNameToIndex(md);
7662       }
7663     }
7664   }
7665 }
7666
7667 //----------------------------------------------------------------------
7668 // computes the relation between all members. For each member `m'
7669 // the members that override the implementation of `m' are searched and
7670 // the member that `m' overrides is searched.
7671
7672 static void computeMemberRelations()
7673 {
7674   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7675   MemberName *mn;
7676   for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7677   {
7678     MemberNameIterator mdi(*mn);
7679     MemberNameIterator bmdi(*mn);
7680     MemberDef *md;
7681     MemberDef *bmd;
7682     for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7683     {
7684       for ( bmdi.toFirst() ; (bmd=bmdi.current()); ++bmdi ) // for each other member with the same name
7685       {
7686         ClassDef *mcd  = md->getClassDef();
7687         if (mcd && mcd->baseClasses())
7688         {
7689           ClassDef *bmcd = bmd->getClassDef();
7690           //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7691           //      mcd->name().data(),md->name().data(),md,
7692           //       bmcd->name().data(),bmd->name().data(),bmd
7693           //      );
7694           if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
7695               (bmd->virtualness()!=Normal ||
7696                bmcd->compoundType()==ClassDef::Interface ||
7697                bmcd->compoundType()==ClassDef::Protocol
7698               ) &&
7699               md->isFunction() &&
7700               mcd->isLinkable() &&
7701               bmcd->isLinkable() &&
7702               mcd->isBaseClass(bmcd,TRUE))
7703           {
7704             //printf("  derived scope\n");
7705             ArgumentList *bmdAl = bmd->argumentList();
7706             ArgumentList *mdAl =  md->argumentList();
7707             //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7708             //        argListToString(bmdAl.pointer()).data(),
7709             //        argListToString(mdAl.pointer()).data()
7710             //      );
7711             if (
7712                 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl,
7713                   md->getOuterScope(), md->getFileDef(), mdAl,
7714                   TRUE
7715                   )
7716                )
7717             {
7718               MemberDef *rmd;
7719               if ((rmd=md->reimplements())==0 ||
7720                   minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7721                  )
7722               {
7723                 //printf("setting (new) reimplements member\n");
7724                 md->setReimplements(bmd);
7725               }
7726               //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7727               bmd->insertReimplementedBy(md);
7728             }
7729           }
7730         }
7731       }
7732     }
7733   }
7734 }
7735
7736
7737 //----------------------------------------------------------------------------
7738 //static void computeClassImplUsageRelations()
7739 //{
7740 //  ClassDef *cd;
7741 //  ClassSDict::Iterator cli(*Doxygen::classSDict);
7742 //  for (;(cd=cli.current());++cli)
7743 //  {
7744 //    cd->determineImplUsageRelation();
7745 //  }
7746 //}
7747
7748 //----------------------------------------------------------------------------
7749
7750 static void createTemplateInstanceMembers()
7751 {
7752   ClassSDict::Iterator cli(*Doxygen::classSDict);
7753   ClassDef *cd;
7754   // for each class
7755   for (cli.toFirst();(cd=cli.current());++cli)
7756   {
7757     // that is a template
7758     QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7759     if (templInstances)
7760     {
7761       QDictIterator<ClassDef> qdi(*templInstances);
7762       ClassDef *tcd=0;
7763       // for each instance of the template
7764       for (qdi.toFirst();(tcd=qdi.current());++qdi)
7765       {
7766         tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7767       }
7768     }
7769   }
7770 }
7771
7772 //----------------------------------------------------------------------------
7773
7774 static void mergeCategories()
7775 {
7776   ClassDef *cd;
7777   ClassSDict::Iterator cli(*Doxygen::classSDict);
7778   // merge members of categories into the class they extend
7779   for (cli.toFirst();(cd=cli.current());++cli)
7780   {
7781     int i=cd->name().find('(');
7782     if (i!=-1) // it is an Objective-C category
7783     {
7784       QCString baseName=cd->name().left(i);
7785       ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7786       if (baseClass)
7787       {
7788         //printf("*** merging members of category %s into %s\n",
7789         //    cd->name().data(),baseClass->name().data());
7790         baseClass->mergeCategory(cd);
7791       }
7792     }
7793   }
7794 }
7795
7796 // builds the list of all members for each class
7797
7798 static void buildCompleteMemberLists()
7799 {
7800   ClassDef *cd;
7801   ClassSDict::Iterator cli(*Doxygen::classSDict);
7802   // merge the member list of base classes into the inherited classes.
7803   for (cli.toFirst();(cd=cli.current());++cli)
7804   {
7805     if (// !cd->isReference() && // not an external class
7806          cd->subClasses()==0 && // is a root of the hierarchy
7807          cd->baseClasses()) // and has at least one base class
7808     {
7809       //printf("*** merging members for %s\n",cd->name().data());
7810       cd->mergeMembers();
7811     }
7812   }
7813   // now sort the member list of all classes.
7814   for (cli.toFirst();(cd=cli.current());++cli)
7815   {
7816     if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7817   }
7818 }
7819
7820 //----------------------------------------------------------------------------
7821
7822 static void generateFileSources()
7823 {
7824   if (Doxygen::inputNameList->count()>0)
7825   {
7826 #if USE_LIBCLANG
7827     static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
7828     if (clangAssistedParsing)
7829     {
7830       QDict<void> g_processedFiles(10007);
7831
7832       // create a dictionary with files to process
7833       QDict<void> g_filesToProcess(10007);
7834       FileNameListIterator fnli(*Doxygen::inputNameList);
7835       FileName *fn;
7836       for (fnli.toFirst();(fn=fnli.current());++fnli)
7837       {
7838         FileNameIterator fni(*fn);
7839         FileDef *fd;
7840         for (;(fd=fni.current());++fni)
7841         {
7842           g_filesToProcess.insert(fd->absFilePath(),(void*)0x8);
7843         }
7844       }
7845       // process source files (and their include dependencies)
7846       for (fnli.toFirst();(fn=fnli.current());++fnli)
7847       {
7848         FileNameIterator fni(*fn);
7849         FileDef *fd;
7850         for (;(fd=fni.current());++fni)
7851         {
7852           if (fd->isSource() && !fd->isReference())
7853           {
7854             QStrList filesInSameTu;
7855             fd->getAllIncludeFilesRecursively(filesInSameTu);
7856             fd->startParsing();
7857             if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7858             {
7859               msg("Generating code for file %s...\n",fd->docName().data());
7860               fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7861
7862             }
7863             else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7864               // we needed to parse the sources even if we do not show them
7865             {
7866               msg("Parsing code for file %s...\n",fd->docName().data());
7867               fd->parseSource(FALSE,filesInSameTu);
7868             }
7869
7870             char *incFile = filesInSameTu.first();
7871             while (incFile && g_filesToProcess.find(incFile))
7872             {
7873               if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile))
7874               {
7875                 QStrList moreFiles;
7876                 bool ambig;
7877                 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
7878                 if (ifd && !ifd->isReference())
7879                 {
7880                   if (ifd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7881                   {
7882                     msg(" Generating code for file %s...\n",ifd->docName().data());
7883                     ifd->writeSource(*g_outputList,TRUE,moreFiles);
7884
7885                   }
7886                   else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
7887                     // we needed to parse the sources even if we do not show them
7888                   {
7889                     msg(" Parsing code for file %s...\n",ifd->docName().data());
7890                     ifd->parseSource(TRUE,moreFiles);
7891                   }
7892                   g_processedFiles.insert(incFile,(void*)0x8);
7893                 }
7894               }
7895               incFile = filesInSameTu.next();
7896             }
7897             fd->finishParsing();
7898             g_processedFiles.insert(fd->absFilePath(),(void*)0x8);
7899           }
7900         }
7901       }
7902       // process remaining files
7903       for (fnli.toFirst();(fn=fnli.current());++fnli)
7904       {
7905         FileNameIterator fni(*fn);
7906         FileDef *fd;
7907         for (;(fd=fni.current());++fni)
7908         {
7909           if (!g_processedFiles.find(fd->absFilePath())) // not yet processed
7910           {
7911             QStrList filesInSameTu;
7912             fd->startParsing();
7913             if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7914             {
7915               msg("Generating code for file %s...\n",fd->docName().data());
7916               fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7917
7918             }
7919             else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7920               // we needed to parse the sources even if we do not show them
7921             {
7922               msg("Parsing code for file %s...\n",fd->docName().data());
7923               fd->parseSource(FALSE,filesInSameTu);
7924             }
7925             fd->finishParsing();
7926           }
7927         }
7928       }
7929     }
7930     else
7931 #endif
7932     {
7933       FileNameListIterator fnli(*Doxygen::inputNameList);
7934       FileName *fn;
7935       for (;(fn=fnli.current());++fnli)
7936       {
7937         FileNameIterator fni(*fn);
7938         FileDef *fd;
7939         for (;(fd=fni.current());++fni)
7940         {
7941           QStrList filesInSameTu;
7942           fd->startParsing();
7943           if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7944           {
7945             msg("Generating code for file %s...\n",fd->docName().data());
7946             fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7947
7948           }
7949           else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7950             // we needed to parse the sources even if we do not show them
7951           {
7952             msg("Parsing code for file %s...\n",fd->docName().data());
7953             fd->parseSource(FALSE,filesInSameTu);
7954           }
7955           fd->finishParsing();
7956         }
7957       }
7958     }
7959   }
7960 }
7961
7962 //----------------------------------------------------------------------------
7963
7964 static void generateFileDocs()
7965 {
7966   if (documentedHtmlFiles==0) return;
7967
7968   if (Doxygen::inputNameList->count()>0)
7969   {
7970     FileNameListIterator fnli(*Doxygen::inputNameList);
7971     FileName *fn;
7972     for (fnli.toFirst();(fn=fnli.current());++fnli)
7973     {
7974       FileNameIterator fni(*fn);
7975       FileDef *fd;
7976       for (fni.toFirst();(fd=fni.current());++fni)
7977       {
7978         bool doc = fd->isLinkableInProject();
7979         if (doc)
7980         {
7981           msg("Generating docs for file %s...\n",fd->docName().data());
7982           fd->writeDocumentation(*g_outputList);
7983         }
7984       }
7985     }
7986   }
7987 }
7988
7989 //----------------------------------------------------------------------------
7990
7991 static void addSourceReferences()
7992 {
7993   // add source references for class definitions
7994   ClassSDict::Iterator cli(*Doxygen::classSDict);
7995   ClassDef *cd=0;
7996   for (cli.toFirst();(cd=cli.current());++cli)
7997   {
7998     FileDef *fd=cd->getBodyDef();
7999     if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
8000     {
8001       fd->addSourceRef(cd->getStartBodyLine(),cd,0);
8002     }
8003   }
8004   // add source references for namespace definitions
8005   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8006   NamespaceDef *nd=0;
8007   for (nli.toFirst();(nd=nli.current());++nli)
8008   {
8009     FileDef *fd=nd->getBodyDef();
8010     if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
8011     {
8012       fd->addSourceRef(nd->getStartBodyLine(),nd,0);
8013     }
8014   }
8015
8016   // add source references for member names
8017   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8018   MemberName *mn=0;
8019   for (mnli.toFirst();(mn=mnli.current());++mnli)
8020   {
8021     MemberNameIterator mni(*mn);
8022     MemberDef *md=0;
8023     for (mni.toFirst();(md=mni.current());++mni)
8024     {
8025       //printf("class member %s: def=%s body=%d link?=%d\n",
8026       //    md->name().data(),
8027       //    md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
8028       //    md->getStartBodyLine(),md->isLinkableInProject());
8029       FileDef *fd=md->getBodyDef();
8030       if (fd &&
8031           md->getStartBodyLine()!=-1 &&
8032           md->isLinkableInProject() &&
8033           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
8034          )
8035       {
8036         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8037         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8038         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8039       }
8040     }
8041   }
8042   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8043   for (fnli.toFirst();(mn=fnli.current());++fnli)
8044   {
8045     MemberNameIterator mni(*mn);
8046     MemberDef *md=0;
8047     for (mni.toFirst();(md=mni.current());++mni)
8048     {
8049       FileDef *fd=md->getBodyDef();
8050       //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
8051       //    md->name().data(),
8052       //    md->getStartBodyLine(),md->getEndBodyLine(),fd,
8053       //    md->isLinkableInProject(),
8054       //    Doxygen::parseSourcesNeeded);
8055       if (fd &&
8056           md->getStartBodyLine()!=-1 &&
8057           md->isLinkableInProject() &&
8058           (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
8059          )
8060       {
8061         //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8062         //    md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8063         fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8064       }
8065     }
8066   }
8067 }
8068
8069 //----------------------------------------------------------------------------
8070
8071 static void sortMemberLists()
8072 {
8073   // sort class member lists
8074   ClassSDict::Iterator cli(*Doxygen::classSDict);
8075   ClassDef *cd=0;
8076   for (cli.toFirst();(cd=cli.current());++cli)
8077   {
8078     cd->sortMemberLists();
8079   }
8080
8081   // sort namespace member lists
8082   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8083   NamespaceDef *nd=0;
8084   for (nli.toFirst();(nd=nli.current());++nli)
8085   {
8086     nd->sortMemberLists();
8087   }
8088
8089   // sort file member lists
8090   FileNameListIterator fnli(*Doxygen::inputNameList);
8091   FileName *fn;
8092   for (;(fn=fnli.current());++fnli)
8093   {
8094     FileNameIterator fni(*fn);
8095     FileDef *fd;
8096     for (;(fd=fni.current());++fni)
8097     {
8098       fd->sortMemberLists();
8099     }
8100   }
8101
8102   // sort group member lists
8103   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8104   GroupDef *gd;
8105   for (gli.toFirst();(gd=gli.current());++gli)
8106   {
8107     gd->sortMemberLists();
8108   }
8109 }
8110
8111 //----------------------------------------------------------------------------
8112 // generate the documentation of all classes
8113
8114 static void generateClassList(ClassSDict &classSDict)
8115 {
8116   ClassSDict::Iterator cli(classSDict);
8117   for ( ; cli.current() ; ++cli )
8118   {
8119     ClassDef *cd=cli.current();
8120
8121     //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
8122     if (cd &&
8123         (cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8124          cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8125         ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8126        )
8127     {
8128       // skip external references, anonymous compounds and
8129       // template instances
8130       if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8131       {
8132         msg("Generating docs for compound %s...\n",cd->name().data());
8133
8134         cd->writeDocumentation(*g_outputList);
8135         cd->writeMemberList(*g_outputList);
8136       }
8137       // even for undocumented classes, the inner classes can be documented.
8138       cd->writeDocumentationForInnerClasses(*g_outputList);
8139     }
8140   }
8141 }
8142
8143 static void generateClassDocs()
8144 {
8145   generateClassList(*Doxygen::classSDict);
8146   generateClassList(*Doxygen::hiddenClasses);
8147 }
8148
8149 //----------------------------------------------------------------------------
8150
8151 static void inheritDocumentation()
8152 {
8153   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8154   MemberName *mn;
8155   //int count=0;
8156   for (;(mn=mnli.current());++mnli)
8157   {
8158     MemberNameIterator mni(*mn);
8159     MemberDef *md;
8160     for (;(md=mni.current());++mni)
8161     {
8162       //printf("%04d Member `%s'\n",count++,md->name().data());
8163       if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
8164       { // no documentation yet
8165         MemberDef *bmd = md->reimplements();
8166         while (bmd && bmd->documentation().isEmpty() &&
8167                       bmd->briefDescription().isEmpty()
8168               )
8169         { // search up the inheritance tree for a documentation member
8170           //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
8171           bmd = bmd->reimplements();
8172         }
8173         if (bmd) // copy the documentation from the reimplemented member
8174         {
8175           md->setInheritsDocsFrom(bmd);
8176           md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8177           md->setDocsForDefinition(bmd->isDocsForDefinition());
8178           md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8179           md->copyArgumentNames(bmd);
8180           md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
8181         }
8182       }
8183     }
8184   }
8185 }
8186
8187 //----------------------------------------------------------------------------
8188
8189 static void combineUsingRelations()
8190 {
8191   // for each file
8192   FileNameListIterator fnli(*Doxygen::inputNameList);
8193   FileName *fn;
8194   for (fnli.toFirst();(fn=fnli.current());++fnli)
8195   {
8196     FileNameIterator fni(*fn);
8197     FileDef *fd;
8198     for (fni.toFirst();(fd=fni.current());++fni)
8199     {
8200       fd->visited=FALSE;
8201     }
8202   }
8203   for (fnli.toFirst();(fn=fnli.current());++fnli)
8204   {
8205     FileNameIterator fni(*fn);
8206     FileDef *fd;
8207     for (fni.toFirst();(fd=fni.current());++fni)
8208     {
8209       fd->combineUsingRelations();
8210     }
8211   }
8212
8213   // for each namespace
8214   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8215   NamespaceDef *nd;
8216   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8217   {
8218     nd->visited=FALSE;
8219   }
8220   for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8221   {
8222     nd->combineUsingRelations();
8223   }
8224 }
8225
8226 //----------------------------------------------------------------------------
8227
8228 static void addMembersToMemberGroup()
8229 {
8230   // for each class
8231   ClassSDict::Iterator cli(*Doxygen::classSDict);
8232   ClassDef *cd;
8233   for ( ; (cd=cli.current()) ; ++cli )
8234   {
8235     cd->addMembersToMemberGroup();
8236   }
8237   // for each file
8238   FileNameListIterator fnli(*Doxygen::inputNameList);
8239   FileName *fn;
8240   for (fnli.toFirst();(fn=fnli.current());++fnli)
8241   {
8242     FileNameIterator fni(*fn);
8243     FileDef *fd;
8244     for (fni.toFirst();(fd=fni.current());++fni)
8245     {
8246       fd->addMembersToMemberGroup();
8247     }
8248   }
8249   // for each namespace
8250   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8251   NamespaceDef *nd;
8252   for ( ; (nd=nli.current()) ; ++nli )
8253   {
8254     nd->addMembersToMemberGroup();
8255   }
8256   // for each group
8257   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8258   GroupDef *gd;
8259   for (gli.toFirst();(gd=gli.current());++gli)
8260   {
8261     gd->addMembersToMemberGroup();
8262   }
8263 }
8264
8265 //----------------------------------------------------------------------------
8266
8267 static void distributeMemberGroupDocumentation()
8268 {
8269   // for each class
8270   ClassSDict::Iterator cli(*Doxygen::classSDict);
8271   ClassDef *cd;
8272   for ( ; (cd=cli.current()) ; ++cli )
8273   {
8274     cd->distributeMemberGroupDocumentation();
8275   }
8276   // for each file
8277   FileNameListIterator fnli(*Doxygen::inputNameList);
8278   FileName *fn;
8279   for (fnli.toFirst();(fn=fnli.current());++fnli)
8280   {
8281     FileNameIterator fni(*fn);
8282     FileDef *fd;
8283     for (fni.toFirst();(fd=fni.current());++fni)
8284     {
8285       fd->distributeMemberGroupDocumentation();
8286     }
8287   }
8288   // for each namespace
8289   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8290   NamespaceDef *nd;
8291   for ( ; (nd=nli.current()) ; ++nli )
8292   {
8293     nd->distributeMemberGroupDocumentation();
8294   }
8295   // for each group
8296   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8297   GroupDef *gd;
8298   for (gli.toFirst();(gd=gli.current());++gli)
8299   {
8300     gd->distributeMemberGroupDocumentation();
8301   }
8302 }
8303
8304 //----------------------------------------------------------------------------
8305
8306 static void findSectionsInDocumentation()
8307 {
8308   // for each class
8309   ClassSDict::Iterator cli(*Doxygen::classSDict);
8310   ClassDef *cd;
8311   for ( ; (cd=cli.current()) ; ++cli )
8312   {
8313     cd->findSectionsInDocumentation();
8314   }
8315   // for each file
8316   FileNameListIterator fnli(*Doxygen::inputNameList);
8317   FileName *fn;
8318   for (fnli.toFirst();(fn=fnli.current());++fnli)
8319   {
8320     FileNameIterator fni(*fn);
8321     FileDef *fd;
8322     for (fni.toFirst();(fd=fni.current());++fni)
8323     {
8324       fd->findSectionsInDocumentation();
8325     }
8326   }
8327   // for each namespace
8328   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8329   NamespaceDef *nd;
8330   for ( ; (nd=nli.current()) ; ++nli )
8331   {
8332     nd->findSectionsInDocumentation();
8333   }
8334   // for each group
8335   GroupSDict::Iterator gli(*Doxygen::groupSDict);
8336   GroupDef *gd;
8337   for (gli.toFirst();(gd=gli.current());++gli)
8338   {
8339     gd->findSectionsInDocumentation();
8340   }
8341   // for each page
8342   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8343   PageDef *pd=0;
8344   for (pdi.toFirst();(pd=pdi.current());++pdi)
8345   {
8346     pd->findSectionsInDocumentation();
8347   }
8348   if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8349 }
8350
8351 static void flushCachedTemplateRelations()
8352 {
8353   // remove all references to classes from the cache
8354   // as there can be new template instances in the inheritance path
8355   // to this class. Optimization: only remove those classes that
8356   // have inheritance instances as direct or indirect sub classes.
8357   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8358   LookupInfo *li=0;
8359   for (ci.toFirst();(li=ci.current());++ci)
8360   {
8361     if (li->classDef)
8362     {
8363       Doxygen::lookupCache->remove(ci.currentKey());
8364     }
8365   }
8366   // remove all cached typedef resolutions whose target is a
8367   // template class as this may now be a template instance
8368   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8369   MemberName *fn;
8370   for (;(fn=fnli.current());++fnli) // for each global function name
8371   {
8372     MemberNameIterator fni(*fn);
8373     MemberDef *fmd;
8374     for (;(fmd=fni.current());++fni) // for each function with that name
8375     {
8376       if (fmd->isTypedefValCached())
8377       {
8378         ClassDef *cd = fmd->getCachedTypedefVal();
8379         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8380       }
8381     }
8382   }
8383   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8384   for (;(fn=mnli.current());++mnli) // for each class method name
8385   {
8386     MemberNameIterator mni(*fn);
8387     MemberDef *fmd;
8388     for (;(fmd=mni.current());++mni) // for each function with that name
8389     {
8390       if (fmd->isTypedefValCached())
8391       {
8392         ClassDef *cd = fmd->getCachedTypedefVal();
8393         if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8394       }
8395     }
8396   }
8397 }
8398
8399 //----------------------------------------------------------------------------
8400
8401 static void flushUnresolvedRelations()
8402 {
8403   // Remove all unresolved references to classes from the cache.
8404   // This is needed before resolving the inheritance relations, since
8405   // it would otherwise not find the inheritance relation
8406   // for C in the example below, as B::I was already found to be unresolvable
8407   // (which is correct if you ignore the inheritance relation between A and B).
8408   //
8409   // class A { class I {} };
8410   // class B : public A {};
8411   // class C : public B::I {};
8412   //
8413   QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8414   LookupInfo *li=0;
8415   for (ci.toFirst();(li=ci.current());++ci)
8416   {
8417     if (li->classDef==0 && li->typeDef==0)
8418     {
8419       Doxygen::lookupCache->remove(ci.currentKey());
8420     }
8421   }
8422
8423   MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8424   MemberName *fn;
8425   for (;(fn=fnli.current());++fnli) // for each global function name
8426   {
8427     MemberNameIterator fni(*fn);
8428     MemberDef *fmd;
8429     for (;(fmd=fni.current());++fni) // for each function with that name
8430     {
8431       fmd->invalidateCachedArgumentTypes();
8432     }
8433   }
8434   MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8435   for (;(fn=mnli.current());++mnli) // for each class method name
8436   {
8437     MemberNameIterator mni(*fn);
8438     MemberDef *fmd;
8439     for (;(fmd=mni.current());++mni) // for each function with that name
8440     {
8441       fmd->invalidateCachedArgumentTypes();
8442     }
8443   }
8444
8445 }
8446
8447 //----------------------------------------------------------------------------
8448
8449 static void findDefineDocumentation(EntryNav *rootNav)
8450 {
8451   if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
8452        rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
8453      )
8454   {
8455     rootNav->loadEntry(g_storage);
8456     Entry *root = rootNav->entry();
8457
8458     //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
8459     //       root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
8460
8461     if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8462     {
8463       MemberDef *md=new MemberDef(rootNav->tagInfo()->tagName,1,1,
8464                     "#define",root->name,root->args,0,
8465                     Public,Normal,FALSE,Member,MemberType_Define,0,0);
8466       md->setTagInfo(rootNav->tagInfo());
8467       md->setLanguage(root->lang);
8468       //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
8469       md->setFileDef(rootNav->parent()->fileDef());
8470       //printf("Adding member=%s\n",md->name().data());
8471       MemberName *mn;
8472       if ((mn=Doxygen::functionNameSDict->find(root->name)))
8473       {
8474         mn->append(md);
8475       }
8476       else
8477       {
8478         mn = new MemberName(root->name);
8479         mn->append(md);
8480         Doxygen::functionNameSDict->append(root->name,mn);
8481       }
8482     }
8483     MemberName *mn=Doxygen::functionNameSDict->find(root->name);
8484     if (mn)
8485     {
8486       MemberNameIterator mni(*mn);
8487       MemberDef *md;
8488       int count=0;
8489       for (;(md=mni.current());++mni)
8490       {
8491         if (md->memberType()==MemberType_Define) count++;
8492       }
8493       if (count==1)
8494       {
8495         for (mni.toFirst();(md=mni.current());++mni)
8496         {
8497           if (md->memberType()==MemberType_Define)
8498           {
8499             md->setDocumentation(root->doc,root->docFile,root->docLine);
8500             md->setDocsForDefinition(!root->proto);
8501             md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8502             if (md->inbodyDocumentation().isEmpty())
8503             {
8504               md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8505             }
8506             md->setBodySegment(root->bodyLine,root->endBodyLine);
8507             md->setBodyDef(rootNav->fileDef());
8508             md->addSectionsToDefinition(root->anchors);
8509             md->setMaxInitLines(root->initLines);
8510             md->setRefItems(root->sli);
8511             if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8512             addMemberToGroups(root,md);
8513           }
8514         }
8515       }
8516       else if (count>1 &&
8517                (!root->doc.isEmpty() ||
8518                 !root->brief.isEmpty() ||
8519                 root->bodyLine!=-1
8520                )
8521               )
8522         // multiple defines don't know where to add docs
8523         // but maybe they are in different files together with their documentation
8524       {
8525         for (mni.toFirst();(md=mni.current());++mni)
8526         {
8527           if (md->memberType()==MemberType_Define)
8528           {
8529             FileDef *fd=md->getFileDef();
8530             if (fd && fd->absFilePath()==root->fileName)
8531               // doc and define in the same file assume they belong together.
8532             {
8533 #if 0
8534               if (md->documentation().isEmpty())
8535 #endif
8536               {
8537                 md->setDocumentation(root->doc,root->docFile,root->docLine);
8538                 md->setDocsForDefinition(!root->proto);
8539               }
8540 #if 0
8541               if (md->briefDescription().isEmpty())
8542 #endif
8543               {
8544                 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8545               }
8546               if (md->inbodyDocumentation().isEmpty())
8547               {
8548                 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8549               }
8550               md->setBodySegment(root->bodyLine,root->endBodyLine);
8551               md->setBodyDef(rootNav->fileDef());
8552               md->addSectionsToDefinition(root->anchors);
8553               md->setRefItems(root->sli);
8554               md->setLanguage(root->lang);
8555               if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8556               addMemberToGroups(root,md);
8557             }
8558           }
8559         }
8560         //warn("define %s found in the following files:\n",root->name.data());
8561         //warn("Cannot determine where to add the documentation found "
8562         //     "at line %d of file %s. \n",
8563         //     root->startLine,root->fileName.data());
8564       }
8565     }
8566     else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8567     {
8568       static bool preEnabled = Config_getBool(ENABLE_PREPROCESSING);
8569       if (preEnabled)
8570       {
8571         warn(root->fileName,root->startLine,
8572              "documentation for unknown define %s found.\n",
8573              root->name.data()
8574             );
8575       }
8576       else
8577       {
8578         warn(root->fileName,root->startLine,
8579              "found documented #define but ignoring it because "
8580              "ENABLE_PREPROCESSING is NO.\n",
8581              root->name.data()
8582             );
8583       }
8584     }
8585
8586     rootNav->releaseEntry();
8587   }
8588   RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8589 }
8590
8591 //----------------------------------------------------------------------------
8592
8593 static void findDirDocumentation(EntryNav *rootNav)
8594 {
8595   if (rootNav->section() == Entry::DIRDOC_SEC)
8596   {
8597     rootNav->loadEntry(g_storage);
8598     Entry *root = rootNav->entry();
8599
8600     QCString normalizedName = root->name;
8601     normalizedName = substitute(normalizedName,"\\","/");
8602     //printf("root->docFile=%s normalizedName=%s\n",
8603     //    root->docFile.data(),normalizedName.data());
8604     if (root->docFile==normalizedName) // current dir?
8605     {
8606       int lastSlashPos=normalizedName.findRev('/');
8607       if (lastSlashPos!=-1) // strip file name
8608       {
8609         normalizedName=normalizedName.left(lastSlashPos);
8610       }
8611     }
8612     if (normalizedName.at(normalizedName.length()-1)!='/')
8613     {
8614       normalizedName+='/';
8615     }
8616     DirDef *dir,*matchingDir=0;
8617     SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8618     for (sdi.toFirst();(dir=sdi.current());++sdi)
8619     {
8620       //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8621       if (dir->name().right(normalizedName.length())==normalizedName)
8622       {
8623         if (matchingDir)
8624         {
8625            warn(root->fileName,root->startLine,
8626              "\\dir command matches multiple directories.\n"
8627              "  Applying the command for directory %s\n"
8628              "  Ignoring the command for directory %s\n",
8629              matchingDir->name().data(),dir->name().data()
8630            );
8631         }
8632         else
8633         {
8634           matchingDir=dir;
8635         }
8636       }
8637     }
8638     if (matchingDir)
8639     {
8640       //printf("Match for with dir %s\n",matchingDir->name().data());
8641       matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8642       matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8643       matchingDir->setRefItems(root->sli);
8644       addDirToGroups(root,matchingDir);
8645     }
8646     else
8647     {
8648       warn(root->fileName,root->startLine,"No matching "
8649           "directory found for command \\dir %s\n",normalizedName.data());
8650     }
8651     rootNav->releaseEntry();
8652   }
8653   RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8654 }
8655
8656
8657 //----------------------------------------------------------------------------
8658 // create a (sorted) list of separate documentation pages
8659
8660 static void buildPageList(EntryNav *rootNav)
8661 {
8662   if (rootNav->section() == Entry::PAGEDOC_SEC)
8663   {
8664     rootNav->loadEntry(g_storage);
8665     Entry *root = rootNav->entry();
8666
8667     if (!root->name.isEmpty())
8668     {
8669       addRelatedPage(rootNav);
8670     }
8671
8672     rootNav->releaseEntry();
8673   }
8674   else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8675   {
8676     rootNav->loadEntry(g_storage);
8677     Entry *root = rootNav->entry();
8678
8679     QCString title=root->args.stripWhiteSpace();
8680     if (title.isEmpty()) title=theTranslator->trMainPage();
8681     //QCString name = Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8682     QCString name = "index";
8683     addRefItem(root->sli,
8684                name,
8685                "page",
8686                name,
8687                title,
8688                0,0
8689                );
8690
8691     rootNav->releaseEntry();
8692   }
8693   RECURSE_ENTRYTREE(buildPageList,rootNav);
8694 }
8695
8696 // search for the main page defined in this project
8697 static void findMainPage(EntryNav *rootNav)
8698 {
8699   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8700   {
8701     rootNav->loadEntry(g_storage);
8702
8703     if (Doxygen::mainPage==0 && rootNav->tagInfo()==0)
8704     {
8705       Entry *root = rootNav->entry();
8706       //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8707       QCString title=root->args.stripWhiteSpace();
8708       //QCString indexName=Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8709       QCString indexName="index";
8710       Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8711                               indexName, root->brief+root->doc+root->inbodyDocs,title);
8712       //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8713       Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8714       Doxygen::mainPage->setFileName(indexName);
8715       Doxygen::mainPage->setShowToc(root->stat);
8716       addPageToContext(Doxygen::mainPage,rootNav);
8717
8718       SectionInfo *si = Doxygen::sectionDict->find(Doxygen::mainPage->name());
8719       if (si)
8720       {
8721         if (si->lineNr != -1)
8722         {
8723           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);
8724         }
8725         else
8726         {
8727           warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s)",Doxygen::mainPage->name().data(),si->fileName.data());
8728         }
8729       }
8730       else
8731       {
8732         // a page name is a label as well! but should no be double either
8733         si=new SectionInfo(
8734           indexName, root->startLine,
8735           Doxygen::mainPage->name(),
8736           Doxygen::mainPage->title(),
8737           SectionInfo::Page,
8738           0); // level 0
8739         Doxygen::sectionDict->append(indexName,si);
8740         Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8741       }
8742     }
8743     else if (rootNav->tagInfo()==0)
8744     {
8745       Entry *root = rootNav->entry();
8746       warn(root->fileName,root->startLine,
8747            "found more than one \\mainpage comment block! (first occurrence: %s, line %d), Skipping current block!",
8748            Doxygen::mainPage->docFile().data(),Doxygen::mainPage->docLine());
8749     }
8750
8751     rootNav->releaseEntry();
8752   }
8753   RECURSE_ENTRYTREE(findMainPage,rootNav);
8754 }
8755
8756 // search for the main page imported via tag files and add only the section labels
8757 static void findMainPageTagFiles(EntryNav *rootNav)
8758 {
8759   if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8760   {
8761     rootNav->loadEntry(g_storage);
8762
8763     if (Doxygen::mainPage && rootNav->tagInfo())
8764     {
8765       Entry *root = rootNav->entry();
8766       Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8767     }
8768   }
8769   RECURSE_ENTRYTREE(findMainPageTagFiles,rootNav);
8770 }
8771
8772 static void computePageRelations(EntryNav *rootNav)
8773 {
8774   if ((rootNav->section()==Entry::PAGEDOC_SEC ||
8775        rootNav->section()==Entry::MAINPAGEDOC_SEC
8776       )
8777       && !rootNav->name().isEmpty()
8778      )
8779   {
8780     rootNav->loadEntry(g_storage);
8781     Entry *root = rootNav->entry();
8782
8783     PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8784                     Doxygen::pageSDict->find(root->name) :
8785                     Doxygen::mainPage;
8786     if (pd)
8787     {
8788       QListIterator<BaseInfo> bii(*root->extends);
8789       BaseInfo *bi;
8790       for (bii.toFirst();(bi=bii.current());++bii)
8791       {
8792         PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8793         if (subPd)
8794         {
8795           pd->addInnerCompound(subPd);
8796           //printf("*** Added subpage relation: %s->%s\n",
8797           //    pd->name().data(),subPd->name().data());
8798         }
8799       }
8800     }
8801
8802     rootNav->releaseEntry();
8803   }
8804   RECURSE_ENTRYTREE(computePageRelations,rootNav);
8805 }
8806
8807 static void checkPageRelations()
8808 {
8809   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8810   PageDef *pd=0;
8811   for (pdi.toFirst();(pd=pdi.current());++pdi)
8812   {
8813     Definition *ppd = pd->getOuterScope();
8814     while (ppd)
8815     {
8816       if (ppd==pd)
8817       {
8818         err("page defined at line %d of file %s with label %s is a subpage "
8819             "of itself! Please remove this cyclic dependency.\n",
8820             pd->docLine(),pd->docFile().data(),pd->name().data());
8821         exit(1);
8822       }
8823       ppd=ppd->getOuterScope();
8824     }
8825   }
8826 }
8827
8828 //----------------------------------------------------------------------------
8829
8830 static void resolveUserReferences()
8831 {
8832   SDict<SectionInfo>::Iterator sdi(*Doxygen::sectionDict);
8833   SectionInfo *si;
8834   for (;(si=sdi.current());++sdi)
8835   {
8836     //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8837     //        si->label.data(),si->definition?si->definition->name().data():"<none>",
8838     //        si->fileName.data());
8839     PageDef *pd=0;
8840
8841     // hack: the items of a todo/test/bug/deprecated list are all fragments from
8842     // different files, so the resulting section's all have the wrong file
8843     // name (not from the todo/test/bug/deprecated list, but from the file in
8844     // which they are defined). We correct this here by looking at the
8845     // generated section labels!
8846     QDictIterator<RefList> rli(*Doxygen::xrefLists);
8847     RefList *rl;
8848     for (rli.toFirst();(rl=rli.current());++rli)
8849     {
8850       QCString label="_"+rl->listName(); // "_todo", "_test", ...
8851       if (si->label.left(label.length())==label)
8852       {
8853         si->fileName=rl->listName();
8854         si->generated=TRUE;
8855         break;
8856       }
8857     }
8858
8859     //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8860     if (!si->generated)
8861     {
8862       // if this section is in a page and the page is in a group, then we
8863       // have to adjust the link file name to point to the group.
8864       if (!si->fileName.isEmpty() &&
8865           (pd=Doxygen::pageSDict->find(si->fileName)) &&
8866           pd->getGroupDef())
8867       {
8868         si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8869       }
8870
8871       if (si->definition)
8872       {
8873         // TODO: there should be one function in Definition that returns
8874         // the file to link to, so we can avoid the following tests.
8875         GroupDef *gd=0;
8876         if (si->definition->definitionType()==Definition::TypeMember)
8877         {
8878           gd = ((MemberDef *)si->definition)->getGroupDef();
8879         }
8880
8881         if (gd)
8882         {
8883           si->fileName=gd->getOutputFileBase().copy();
8884         }
8885         else
8886         {
8887           //si->fileName=si->definition->getOutputFileBase().copy();
8888           //printf("Setting si->fileName to %s\n",si->fileName.data());
8889         }
8890       }
8891     }
8892     //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8893   }
8894 }
8895
8896
8897
8898 //----------------------------------------------------------------------------
8899 // generate all separate documentation pages
8900
8901
8902 static void generatePageDocs()
8903 {
8904   //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8905   if (documentedPages==0) return;
8906   PageSDict::Iterator pdi(*Doxygen::pageSDict);
8907   PageDef *pd=0;
8908   for (pdi.toFirst();(pd=pdi.current());++pdi)
8909   {
8910     if (!pd->getGroupDef() && !pd->isReference())
8911     {
8912       msg("Generating docs for page %s...\n",pd->name().data());
8913       Doxygen::insideMainPage=TRUE;
8914       pd->writeDocumentation(*g_outputList);
8915       Doxygen::insideMainPage=FALSE;
8916     }
8917   }
8918 }
8919
8920 //----------------------------------------------------------------------------
8921 // create a (sorted) list & dictionary of example pages
8922
8923 static void buildExampleList(EntryNav *rootNav)
8924 {
8925   if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty())
8926   {
8927     rootNav->loadEntry(g_storage);
8928     Entry *root = rootNav->entry();
8929
8930     if (Doxygen::exampleSDict->find(root->name))
8931     {
8932       warn(root->fileName,root->startLine,
8933           "Example %s was already documented. Ignoring "
8934           "documentation found here.",
8935           root->name.data()
8936           );
8937     }
8938     else
8939     {
8940       PageDef *pd=new PageDef(root->fileName,root->startLine,
8941           root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8942       pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8943       pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
8944       pd->addSectionsToDefinition(root->anchors);
8945       pd->setLanguage(root->lang);
8946       //pi->addSections(root->anchors);
8947
8948       Doxygen::exampleSDict->inSort(root->name,pd);
8949       //we don't add example to groups
8950       //addExampleToGroups(root,pd);
8951     }
8952
8953     rootNav->releaseEntry();
8954   }
8955   RECURSE_ENTRYTREE(buildExampleList,rootNav);
8956 }
8957
8958 //----------------------------------------------------------------------------
8959 // prints the Entry tree (for debugging)
8960
8961 void printNavTree(EntryNav *rootNav,int indent)
8962 {
8963   QCString indentStr;
8964   indentStr.fill(' ',indent);
8965   msg("%s%s (sec=0x%x)\n",
8966       indentStr.isEmpty()?"":indentStr.data(),
8967       rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8968       rootNav->section());
8969   if (rootNav->children())
8970   {
8971     EntryNavListIterator eli(*rootNav->children());
8972     for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8973   }
8974 }
8975
8976
8977 //----------------------------------------------------------------------------
8978 // generate the example documentation
8979
8980 static void generateExampleDocs()
8981 {
8982   g_outputList->disable(OutputGenerator::Man);
8983   PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8984   PageDef *pd=0;
8985   for (pdi.toFirst();(pd=pdi.current());++pdi)
8986   {
8987     msg("Generating docs for example %s...\n",pd->name().data());
8988     resetCCodeParserState();
8989     QCString n=pd->getOutputFileBase();
8990     startFile(*g_outputList,n,n,pd->name());
8991     startTitle(*g_outputList,n);
8992     g_outputList->docify(pd->name());
8993     endTitle(*g_outputList,n,0);
8994     g_outputList->startContents();
8995     g_outputList->generateDoc(pd->docFile(),                            // file
8996                          pd->docLine(),                            // startLine
8997                          pd,                                       // context
8998                          0,                                        // memberDef
8999                          pd->documentation()+"\n\n\\include "+pd->name(),          // docs
9000                          TRUE,                                     // index words
9001                          TRUE,                                     // is example
9002                          pd->name()
9003                         );
9004     endFile(*g_outputList); // contains g_outputList->endContents()
9005   }
9006   g_outputList->enable(OutputGenerator::Man);
9007 }
9008
9009 //----------------------------------------------------------------------------
9010 // generate module pages
9011
9012 static void generateGroupDocs()
9013 {
9014   GroupSDict::Iterator gli(*Doxygen::groupSDict);
9015   GroupDef *gd;
9016   for (gli.toFirst();(gd=gli.current());++gli)
9017   {
9018     if (!gd->isReference())
9019     {
9020       gd->writeDocumentation(*g_outputList);
9021     }
9022   }
9023 }
9024
9025 //----------------------------------------------------------------------------
9026
9027 //static void generatePackageDocs()
9028 //{
9029 //  writePackageIndex(*g_outputList);
9030 //
9031 //  if (Doxygen::packageDict.count()>0)
9032 //  {
9033 //    PackageSDict::Iterator pdi(Doxygen::packageDict);
9034 //    PackageDef *pd;
9035 //    for (pdi.toFirst();(pd=pdi.current());++pdi)
9036 //    {
9037 //      pd->writeDocumentation(*g_outputList);
9038 //    }
9039 //  }
9040 //}
9041
9042 //----------------------------------------------------------------------------
9043 // generate module pages
9044
9045 static void generateNamespaceDocs()
9046 {
9047   //writeNamespaceIndex(*g_outputList);
9048
9049   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
9050   NamespaceDef *nd;
9051   // for each namespace...
9052   for (;(nd=nli.current());++nli)
9053   {
9054
9055     if (nd->isLinkableInProject())
9056     {
9057       msg("Generating docs for namespace %s\n",nd->name().data());
9058       nd->writeDocumentation(*g_outputList);
9059     }
9060
9061     // for each class in the namespace...
9062     ClassSDict::Iterator cli(*nd->getClassSDict());
9063     ClassDef *cd;
9064     for ( ; (cd=cli.current()) ; ++cli )
9065     {
9066       if ( ( cd->isLinkableInProject() &&
9067              cd->templateMaster()==0
9068            ) // skip external references, anonymous compounds and
9069              // template instances and nested classes
9070            && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
9071          )
9072       {
9073         msg("Generating docs for compound %s...\n",cd->name().data());
9074
9075         cd->writeDocumentation(*g_outputList);
9076         cd->writeMemberList(*g_outputList);
9077       }
9078       cd->writeDocumentationForInnerClasses(*g_outputList);
9079     }
9080   }
9081 }
9082
9083 #if defined(_WIN32)
9084 static QCString fixSlashes(QCString &s)
9085 {
9086   QCString result;
9087   uint i;
9088   for (i=0;i<s.length();i++)
9089   {
9090     switch(s.at(i))
9091     {
9092       case '/':
9093       case '\\':
9094         result+="\\\\";
9095         break;
9096       default:
9097         result+=s.at(i);
9098     }
9099   }
9100   return result;
9101 }
9102 #endif
9103
9104
9105 //----------------------------------------------------------------------------
9106
9107 /*! Generate a template version of the configuration file.
9108  *  If the \a shortList parameter is TRUE a configuration file without
9109  *  comments will be generated.
9110  */
9111 static void generateConfigFile(const char *configFile,bool shortList,
9112                                bool updateOnly=FALSE)
9113 {
9114   QFile f;
9115   bool fileOpened=openOutputFile(configFile,f);
9116   bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
9117   if (fileOpened)
9118   {
9119     FTextStream t(&f);
9120     Config::writeTemplate(t,shortList,updateOnly);
9121     if (!writeToStdout)
9122     {
9123       if (!updateOnly)
9124       {
9125         msg("\n\nConfiguration file `%s' created.\n\n",configFile);
9126         msg("Now edit the configuration file and enter\n\n");
9127         if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
9128           msg("  doxygen %s\n\n",configFile);
9129         else
9130           msg("  doxygen\n\n");
9131         msg("to generate the documentation for your project\n\n");
9132       }
9133       else
9134       {
9135         msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
9136       }
9137     }
9138   }
9139   else
9140   {
9141     err("Cannot open file %s for writing\n",configFile);
9142     exit(1);
9143   }
9144 }
9145
9146 //----------------------------------------------------------------------------
9147 // read and parse a tag file
9148
9149 //static bool readLineFromFile(QFile &f,QCString &s)
9150 //{
9151 //  char c=0;
9152 //  s.resize(0);
9153 //  while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
9154 //  return f.atEnd();
9155 //}
9156
9157 //----------------------------------------------------------------------------
9158
9159 static void readTagFile(Entry *root,const char *tl)
9160 {
9161   QCString tagLine = tl;
9162   QCString fileName;
9163   QCString destName;
9164   int eqPos = tagLine.find('=');
9165   if (eqPos!=-1) // tag command contains a destination
9166   {
9167     fileName = tagLine.left(eqPos).stripWhiteSpace();
9168     destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9169     QFileInfo fi(fileName);
9170     Doxygen::tagDestinationDict.insert(fi.absFilePath().utf8(),new QCString(destName));
9171     //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
9172   }
9173   else
9174   {
9175     fileName = tagLine;
9176   }
9177
9178   QFileInfo fi(fileName);
9179   if (!fi.exists() || !fi.isFile())
9180   {
9181     err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
9182         fileName.data());
9183     return;
9184   }
9185
9186   if (!destName.isEmpty())
9187     msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
9188   else
9189     msg("Reading tag file `%s'...\n",fileName.data());
9190
9191   parseTagFile(root,fi.absFilePath().utf8());
9192 }
9193
9194 //----------------------------------------------------------------------------
9195 static void copyLatexStyleSheet()
9196 {
9197   QStrList latexExtraStyleSheet = Config_getList(LATEX_EXTRA_STYLESHEET);
9198   for (uint i=0; i<latexExtraStyleSheet.count(); ++i)
9199   {
9200     QCString fileName(latexExtraStyleSheet.at(i));
9201     if (!fileName.isEmpty())
9202     {
9203       QFileInfo fi(fileName);
9204       if (!fi.exists())
9205       {
9206         err("Style sheet '%s' specified by LATEX_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9207       }
9208       else
9209       {
9210         QCString destFileName = Config_getString(LATEX_OUTPUT)+"/"+fi.fileName().data();
9211         if (!checkExtension(fi.fileName().data(), latexStyleExtension))
9212         {
9213           destFileName += latexStyleExtension;
9214         }
9215         copyFile(fileName, destFileName);
9216       }
9217     }
9218   }
9219 }
9220
9221 //----------------------------------------------------------------------------
9222 static void copyStyleSheet()
9223 {
9224   QCString &htmlStyleSheet = Config_getString(HTML_STYLESHEET);
9225   if (!htmlStyleSheet.isEmpty())
9226   {
9227     QFileInfo fi(htmlStyleSheet);
9228     if (!fi.exists())
9229     {
9230       err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
9231       htmlStyleSheet.resize(0); // revert to the default
9232     }
9233     else
9234     {
9235       QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9236       copyFile(htmlStyleSheet,destFileName);
9237     }
9238   }
9239   QStrList htmlExtraStyleSheet = Config_getList(HTML_EXTRA_STYLESHEET);
9240   for (uint i=0; i<htmlExtraStyleSheet.count(); ++i)
9241   {
9242     QCString fileName(htmlExtraStyleSheet.at(i));
9243     if (!fileName.isEmpty())
9244     {
9245       QFileInfo fi(fileName);
9246       if (!fi.exists())
9247       {
9248         err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9249       }
9250       else if (fi.fileName()=="doxygen.css" || fi.fileName()=="tabs.css" || fi.fileName()=="navtree.css")
9251       {
9252         err("Style sheet %s specified by HTML_EXTRA_STYLESHEET is already a built-in stylesheet. Please use a different name\n",fi.fileName().data());
9253       }
9254       else
9255       {
9256         QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9257         copyFile(fileName, destFileName);
9258       }
9259     }
9260   }
9261 }
9262
9263 static void copyLogo(const QCString &outputOption)
9264 {
9265   QCString &projectLogo = Config_getString(PROJECT_LOGO);
9266   if (!projectLogo.isEmpty())
9267   {
9268     QFileInfo fi(projectLogo);
9269     if (!fi.exists())
9270     {
9271       err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
9272       projectLogo.resize(0); // revert to the default
9273     }
9274     else
9275     {
9276       QCString destFileName = outputOption+"/"+fi.fileName().data();
9277       copyFile(projectLogo,destFileName);
9278       Doxygen::indexList->addImageFile(fi.fileName().data());
9279     }
9280   }
9281 }
9282
9283 static void copyExtraFiles(QStrList files,const QString &filesOption,const QCString &outputOption)
9284 {
9285   uint i;
9286   for (i=0; i<files.count(); ++i)
9287   {
9288     QCString fileName(files.at(i));
9289
9290     if (!fileName.isEmpty())
9291     {
9292       QFileInfo fi(fileName);
9293       if (!fi.exists())
9294       {
9295         err("Extra file '%s' specified in %s does not exist!\n", fileName.data(),filesOption.data());
9296       }
9297       else
9298       {
9299         QCString destFileName = outputOption+"/"+fi.fileName().data();
9300         Doxygen::indexList->addImageFile(fi.fileName().utf8());
9301         copyFile(fileName, destFileName);
9302       }
9303     }
9304   }
9305 }
9306
9307 //----------------------------------------------------------------------------
9308
9309 static ParserInterface *getParserForFile(const char *fn)
9310 {
9311   QCString fileName=fn;
9312   QCString extension;
9313   int sep = fileName.findRev('/');
9314   int ei = fileName.findRev('.');
9315   if (ei!=-1 && (sep==-1 || ei>sep)) // matches dir/file.ext but not dir.1/file
9316   {
9317     extension=fileName.right(fileName.length()-ei);
9318   }
9319   else
9320   {
9321     extension = ".no_extension";
9322   }
9323
9324   return Doxygen::parserManager->getParser(extension);
9325 }
9326
9327 static void parseFile(ParserInterface *parser,
9328                       Entry *root,EntryNav *rootNav,FileDef *fd,const char *fn,
9329                       bool sameTu,QStrList &filesInSameTu)
9330 {
9331 #if USE_LIBCLANG
9332   static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9333 #else
9334   static bool clangAssistedParsing = FALSE;
9335 #endif
9336   QCString fileName=fn;
9337   QCString extension;
9338   int ei = fileName.findRev('.');
9339   if (ei!=-1)
9340   {
9341     extension=fileName.right(fileName.length()-ei);
9342   }
9343   else
9344   {
9345     extension = ".no_extension";
9346   }
9347
9348   QFileInfo fi(fileName);
9349   BufStr preBuf(fi.size()+4096);
9350
9351   if (Config_getBool(ENABLE_PREPROCESSING) &&
9352       parser->needsPreprocessing(extension))
9353   {
9354     BufStr inBuf(fi.size()+4096);
9355     msg("Preprocessing %s...\n",fn);
9356     readInputFile(fileName,inBuf);
9357     preprocessFile(fileName,inBuf,preBuf);
9358   }
9359   else // no preprocessing
9360   {
9361     msg("Reading %s...\n",fn);
9362     readInputFile(fileName,preBuf);
9363   }
9364   if (preBuf.data() && preBuf.curPos()>0 && *(preBuf.data()+preBuf.curPos()-1)!='\n')
9365   {
9366     preBuf.addChar('\n'); // add extra newline to help parser
9367   }
9368
9369   BufStr convBuf(preBuf.curPos()+1024);
9370
9371   // convert multi-line C++ comments to C style comments
9372   convertCppComments(&preBuf,&convBuf,fileName);
9373
9374   convBuf.addChar('\0');
9375
9376   if (clangAssistedParsing && !sameTu)
9377   {
9378     fd->getAllIncludeFilesRecursively(filesInSameTu);
9379   }
9380
9381   // use language parse to parse the file
9382   parser->parseInput(fileName,convBuf.data(),root,sameTu,filesInSameTu);
9383
9384   // store the Entry tree in a file and create an index to
9385   // navigate/load entries
9386   //printf("root->createNavigationIndex for %s\n",fd->name().data());
9387   root->createNavigationIndex(rootNav,g_storage,fd);
9388 }
9389
9390 //! parse the list of input files
9391 static void parseFiles(Entry *root,EntryNav *rootNav)
9392 {
9393 #if USE_LIBCLANG
9394   static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9395   if (clangAssistedParsing)
9396   {
9397     QDict<void> g_processedFiles(10007);
9398
9399     // create a dictionary with files to process
9400     QDict<void> g_filesToProcess(10007);
9401     StringListIterator it(g_inputFiles);
9402     QCString *s;
9403     for (;(s=it.current());++it)
9404     {
9405       g_filesToProcess.insert(*s,(void*)0x8);
9406     }
9407
9408     // process source files (and their include dependencies)
9409     for (it.toFirst();(s=it.current());++it)
9410     {
9411       bool ambig;
9412       FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9413       ASSERT(fd!=0);
9414       if (fd->isSource() && !fd->isReference()) // this is a source file
9415       {
9416         QStrList filesInSameTu;
9417         ParserInterface * parser = getParserForFile(s->data());
9418         parser->startTranslationUnit(s->data());
9419         parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9420         //printf("  got %d extra files in tu\n",filesInSameTu.count());
9421
9422         // Now process any include files in the same translation unit
9423         // first. When libclang is used this is much more efficient.
9424         char *incFile = filesInSameTu.first();
9425         while (incFile && g_filesToProcess.find(incFile))
9426         {
9427           if (qstrcmp(incFile,s->data()) && !g_processedFiles.find(incFile))
9428           {
9429             FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
9430             if (ifd && !ifd->isReference())
9431             {
9432               QStrList moreFiles;
9433               //printf("  Processing %s in same translation unit as %s\n",incFile,s->data());
9434               parseFile(parser,root,rootNav,ifd,incFile,TRUE,moreFiles);
9435               g_processedFiles.insert(incFile,(void*)0x8);
9436             }
9437           }
9438           incFile = filesInSameTu.next();
9439         }
9440         parser->finishTranslationUnit();
9441         g_processedFiles.insert(*s,(void*)0x8);
9442       }
9443     }
9444     // process remaining files
9445     for (it.toFirst();(s=it.current());++it)
9446     {
9447       if (!g_processedFiles.find(*s)) // not yet processed
9448       {
9449         bool ambig;
9450         QStrList filesInSameTu;
9451         FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9452         ASSERT(fd!=0);
9453         ParserInterface * parser = getParserForFile(s->data());
9454         parser->startTranslationUnit(s->data());
9455         parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9456         parser->finishTranslationUnit();
9457         g_processedFiles.insert(*s,(void*)0x8);
9458       }
9459     }
9460   }
9461   else // normal pocessing
9462 #endif
9463   {
9464     StringListIterator it(g_inputFiles);
9465     QCString *s;
9466     for (;(s=it.current());++it)
9467     {
9468       bool ambig;
9469       QStrList filesInSameTu;
9470       FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9471       ASSERT(fd!=0);
9472       ParserInterface * parser = getParserForFile(s->data());
9473       parser->startTranslationUnit(s->data());
9474       parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9475     }
9476   }
9477 }
9478
9479 // resolves a path that may include symlinks, if a recursive symlink is
9480 // found an empty string is returned.
9481 static QCString resolveSymlink(QCString path)
9482 {
9483   int sepPos=0;
9484   int oldPos=0;
9485   QFileInfo fi;
9486   QDict<void> nonSymlinks;
9487   QDict<void> known;
9488   QCString result = path;
9489   QCString oldPrefix = "/";
9490   do
9491   {
9492 #ifdef WIN32
9493     // UNC path, skip server and share name
9494     if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
9495       sepPos = result.find('/',2);
9496     if (sepPos!=-1)
9497       sepPos = result.find('/',sepPos+1);
9498 #else
9499     sepPos = result.find('/',sepPos+1);
9500 #endif
9501     QCString prefix = sepPos==-1 ? result : result.left(sepPos);
9502     if (nonSymlinks.find(prefix)==0)
9503     {
9504       fi.setFile(prefix);
9505       if (fi.isSymLink())
9506       {
9507         QString target = fi.readLink();
9508         bool isRelative = QFileInfo(target).isRelative();
9509         if (isRelative)
9510         {
9511           target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
9512         }
9513         if (sepPos!=-1)
9514         {
9515           if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
9516           {
9517             target+='/';
9518           }
9519           target+=result.mid(sepPos);
9520         }
9521         result = QDir::cleanDirPath(target).data();
9522         sepPos = 0;
9523         if (known.find(result)) return QCString(); // recursive symlink!
9524         known.insert(result,(void*)0x8);
9525         if (isRelative)
9526         {
9527           sepPos = oldPos;
9528         }
9529         else // link to absolute path
9530         {
9531           sepPos = 0;
9532           oldPrefix = "/";
9533         }
9534       }
9535       else
9536       {
9537         nonSymlinks.insert(prefix,(void*)0x8);
9538         oldPrefix = prefix;
9539       }
9540       oldPos = sepPos;
9541     }
9542   }
9543   while (sepPos!=-1);
9544   return QDir::cleanDirPath(result).data();
9545 }
9546
9547 static QDict<void> g_pathsVisited(1009);
9548
9549 //----------------------------------------------------------------------------
9550 // Read all files matching at least one pattern in `patList' in the
9551 // directory represented by `fi'.
9552 // The directory is read iff the recusiveFlag is set.
9553 // The contents of all files is append to the input string
9554
9555 int readDir(QFileInfo *fi,
9556             FileNameList *fnList,
9557             FileNameDict *fnDict,
9558             StringDict  *exclDict,
9559             QStrList *patList,
9560             QStrList *exclPatList,
9561             StringList *resultList,
9562             StringDict *resultDict,
9563             bool errorIfNotExist,
9564             bool recursive,
9565             QDict<void> *killDict,
9566             QDict<void> *paths
9567            )
9568 {
9569   QCString dirName = fi->absFilePath().utf8();
9570   if (paths && paths->find(dirName)==0)
9571   {
9572     paths->insert(dirName,(void*)0x8);
9573   }
9574   if (fi->isSymLink())
9575   {
9576     dirName = resolveSymlink(dirName.data());
9577     if (dirName.isEmpty()) return 0;            // recusive symlink
9578     if (g_pathsVisited.find(dirName)) return 0; // already visited path
9579     g_pathsVisited.insert(dirName,(void*)0x8);
9580   }
9581   QDir dir(dirName);
9582   dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
9583   int totalSize=0;
9584   msg("Searching for files in directory %s\n", fi->absFilePath().data());
9585   //printf("killDict=%p count=%d\n",killDict,killDict->count());
9586
9587   const QFileInfoList *list = dir.entryInfoList();
9588   if (list)
9589   {
9590     QFileInfoListIterator it( *list );
9591     QFileInfo *cfi;
9592
9593     while ((cfi=it.current()))
9594     {
9595       if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0)
9596       { // file should not be excluded
9597         //printf("killDict->find(%s)\n",cfi->absFilePath().data());
9598         if (!cfi->exists() || !cfi->isReadable())
9599         {
9600           if (errorIfNotExist)
9601           {
9602             warn_uncond("source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
9603           }
9604         }
9605         else if (cfi->isFile() &&
9606             (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9607             (patList==0 || patternMatch(*cfi,patList)) &&
9608             !patternMatch(*cfi,exclPatList) &&
9609             (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
9610             )
9611         {
9612           totalSize+=cfi->size()+cfi->absFilePath().length()+4;
9613           QCString name=cfi->fileName().utf8();
9614           //printf("New file %s\n",name.data());
9615           if (fnDict)
9616           {
9617             FileDef  *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
9618             FileName *fn=0;
9619             if (!name.isEmpty() && (fn=(*fnDict)[name]))
9620             {
9621               fn->append(fd);
9622             }
9623             else
9624             {
9625               fn = new FileName(cfi->absFilePath().utf8(),name);
9626               fn->append(fd);
9627               if (fnList) fnList->inSort(fn);
9628               fnDict->insert(name,fn);
9629             }
9630           }
9631           QCString *rs=0;
9632           if (resultList || resultDict)
9633           {
9634             rs=new QCString(cfi->absFilePath().utf8());
9635           }
9636           if (resultList) resultList->append(rs);
9637           if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
9638           if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
9639         }
9640         else if (recursive &&
9641             (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9642             cfi->isDir() &&
9643             !patternMatch(*cfi,exclPatList) &&
9644             cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
9645         {
9646           cfi->setFile(cfi->absFilePath());
9647           totalSize+=readDir(cfi,fnList,fnDict,exclDict,
9648               patList,exclPatList,resultList,resultDict,errorIfNotExist,
9649               recursive,killDict,paths);
9650         }
9651       }
9652       ++it;
9653     }
9654   }
9655   return totalSize;
9656 }
9657
9658
9659 //----------------------------------------------------------------------------
9660 // read a file or all files in a directory and append their contents to the
9661 // input string. The names of the files are appended to the `fiList' list.
9662
9663 int readFileOrDirectory(const char *s,
9664                         FileNameList *fnList,
9665                         FileNameDict *fnDict,
9666                         StringDict *exclDict,
9667                         QStrList *patList,
9668                         QStrList *exclPatList,
9669                         StringList *resultList,
9670                         StringDict *resultDict,
9671                         bool recursive,
9672                         bool errorIfNotExist,
9673                         QDict<void> *killDict,
9674                         QDict<void> *paths
9675                        )
9676 {
9677   //printf("killDict=%p count=%d\n",killDict,killDict->count());
9678   // strip trailing slashes
9679   if (s==0) return 0;
9680   QCString fs = s;
9681   char lc = fs.at(fs.length()-1);
9682   if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9683
9684   QFileInfo fi(fs);
9685   //printf("readFileOrDirectory(%s)\n",s);
9686   int totalSize=0;
9687   {
9688     if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9689     {
9690       if (!fi.exists() || !fi.isReadable())
9691       {
9692         if (errorIfNotExist)
9693         {
9694           warn_uncond("source %s is not a readable file or directory... skipping.\n",s);
9695         }
9696       }
9697       else if (!Config_getBool(EXCLUDE_SYMLINKS) || !fi.isSymLink())
9698       {
9699         if (fi.isFile())
9700         {
9701           QCString dirPath = fi.dirPath(TRUE).utf8();
9702           QCString filePath = fi.absFilePath().utf8();
9703           if (paths && paths->find(dirPath))
9704           {
9705             paths->insert(dirPath,(void*)0x8);
9706           }
9707           //printf("killDict->find(%s)\n",fi.absFilePath().data());
9708           if (killDict==0 || killDict->find(filePath)==0)
9709           {
9710             totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input);
9711             //fiList->inSort(new FileInfo(fi));
9712             QCString name=fi.fileName().utf8();
9713             //printf("New file %s\n",name.data());
9714             if (fnDict)
9715             {
9716               FileDef  *fd=new FileDef(dirPath+"/",name);
9717               FileName *fn=0;
9718               if (!name.isEmpty() && (fn=(*fnDict)[name]))
9719               {
9720                 fn->append(fd);
9721               }
9722               else
9723               {
9724                 fn = new FileName(filePath,name);
9725                 fn->append(fd);
9726                 if (fnList) fnList->inSort(fn);
9727                 fnDict->insert(name,fn);
9728               }
9729             }
9730             QCString *rs=0;
9731             if (resultList || resultDict)
9732             {
9733               rs=new QCString(filePath);
9734               if (resultList) resultList->append(rs);
9735               if (resultDict) resultDict->insert(filePath,rs);
9736             }
9737
9738             if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9739           }
9740         }
9741         else if (fi.isDir()) // readable dir
9742         {
9743           totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9744               exclPatList,resultList,resultDict,errorIfNotExist,
9745               recursive,killDict,paths);
9746         }
9747       }
9748     }
9749   }
9750   return totalSize;
9751 }
9752
9753 //----------------------------------------------------------------------------
9754
9755 void readFormulaRepository()
9756 {
9757   QFile f(Config_getString(HTML_OUTPUT)+"/formula.repository");
9758   if (f.open(IO_ReadOnly)) // open repository
9759   {
9760     msg("Reading formula repository...\n");
9761     QTextStream t(&f);
9762     QCString line;
9763     while (!t.eof())
9764     {
9765       line=t.readLine().utf8();
9766       int se=line.find(':'); // find name and text separator.
9767       if (se==-1)
9768       {
9769         warn_uncond("formula.repository is corrupted!\n");
9770         break;
9771       }
9772       else
9773       {
9774         QCString formName = line.left(se);
9775         QCString formText = line.right(line.length()-se-1);
9776         Formula *f=new Formula(formText);
9777         Doxygen::formulaList->setAutoDelete(TRUE);
9778         Doxygen::formulaList->append(f);
9779         Doxygen::formulaDict->insert(formText,f);
9780         Doxygen::formulaNameDict->insert(formName,f);
9781       }
9782     }
9783   }
9784 }
9785
9786 //----------------------------------------------------------------------------
9787
9788 static void expandAliases()
9789 {
9790   QDictIterator<QCString> adi(Doxygen::aliasDict);
9791   QCString *s;
9792   for (adi.toFirst();(s=adi.current());++adi)
9793   {
9794     *s = expandAlias(adi.currentKey(),*s);
9795   }
9796 }
9797
9798 //----------------------------------------------------------------------------
9799
9800 static void escapeAliases()
9801 {
9802   QDictIterator<QCString> adi(Doxygen::aliasDict);
9803   QCString *s;
9804   for (adi.toFirst();(s=adi.current());++adi)
9805   {
9806     QCString value=*s,newValue;
9807     int in,p=0;
9808     // for each \n in the alias command value
9809     while ((in=value.find("\\n",p))!=-1)
9810     {
9811       newValue+=value.mid(p,in-p);
9812       // expand \n's except if \n is part of a built-in command.
9813       if (value.mid(in,5)!="\\note" &&
9814           value.mid(in,5)!="\\name" &&
9815           value.mid(in,10)!="\\namespace" &&
9816           value.mid(in,14)!="\\nosubgrouping"
9817          )
9818       {
9819         newValue+="\\_linebr ";
9820       }
9821       else
9822       {
9823         newValue+="\\n";
9824       }
9825       p=in+2;
9826     }
9827     newValue+=value.mid(p,value.length()-p);
9828     *s=newValue;
9829     p = 0;
9830     newValue = "";
9831     while ((in=value.find("^^",p))!=-1)
9832     {
9833       newValue+=value.mid(p,in-p);
9834       newValue+="\n";
9835       p=in+2;
9836     }
9837     newValue+=value.mid(p,value.length()-p);
9838     *s=newValue;
9839     //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9840   }
9841 }
9842
9843 //----------------------------------------------------------------------------
9844
9845 void readAliases()
9846 {
9847   // add aliases to a dictionary
9848   Doxygen::aliasDict.setAutoDelete(TRUE);
9849   QStrList &aliasList = Config_getList(ALIASES);
9850   const char *s=aliasList.first();
9851   while (s)
9852   {
9853     if (Doxygen::aliasDict[s]==0)
9854     {
9855       QCString alias=s;
9856       int i=alias.find('=');
9857       if (i>0)
9858       {
9859         QCString name=alias.left(i).stripWhiteSpace();
9860         QCString value=alias.right(alias.length()-i-1);
9861         //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
9862         if (!name.isEmpty())
9863         {
9864           QCString *dn=Doxygen::aliasDict[name];
9865           if (dn==0) // insert new alias
9866           {
9867             Doxygen::aliasDict.insert(name,new QCString(value));
9868           }
9869           else // overwrite previous alias
9870           {
9871             *dn=value;
9872           }
9873         }
9874       }
9875     }
9876     s=aliasList.next();
9877   }
9878   expandAliases();
9879   escapeAliases();
9880 }
9881
9882 //----------------------------------------------------------------------------
9883
9884 static void dumpSymbol(FTextStream &t,Definition *d)
9885 {
9886   QCString anchor;
9887   if (d->definitionType()==Definition::TypeMember)
9888   {
9889     MemberDef *md = (MemberDef *)d;
9890     anchor=":"+md->anchor();
9891   }
9892   QCString scope;
9893   if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope)
9894   {
9895     scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
9896   }
9897   t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9898     << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9899     << scope << "','"
9900     << d->name() << "','"
9901     << d->getDefFileName() << "','"
9902     << d->getDefLine()
9903     << "');" << endl;
9904 }
9905
9906 static void dumpSymbolMap()
9907 {
9908   QFile f("symbols.sql");
9909   if (f.open(IO_WriteOnly))
9910   {
9911     FTextStream t(&f);
9912     QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9913     DefinitionIntf *intf;
9914     for (;(intf=di.current());++di)
9915     {
9916       if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9917       {
9918         DefinitionListIterator dli(*(DefinitionList*)intf);
9919         Definition *d;
9920         // for each symbol
9921         for (dli.toFirst();(d=dli.current());++dli)
9922         {
9923           dumpSymbol(t,d);
9924         }
9925       }
9926       else // single symbol
9927       {
9928         Definition *d = (Definition *)intf;
9929         if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9930       }
9931     }
9932   }
9933 }
9934
9935 // print developer options of doxygen
9936 static void devUsage()
9937 {
9938   msg("Developer parameters:\n");
9939   msg("  -m          dump symbol map\n");
9940   msg("  -b          output to wizard\n");
9941   msg("  -T          activates output generation via Django like template\n");
9942   msg("  -d <level>  enable a debug level, such as (multiple invocations of -d are possible):\n");
9943   Debug::printFlags();
9944 }
9945
9946
9947 //----------------------------------------------------------------------------
9948 // print the usage of doxygen
9949
9950 static void usage(const char *name)
9951 {
9952   msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2015\n\n",versionString);
9953   msg("You can use doxygen in a number of ways:\n\n");
9954   msg("1) Use doxygen to generate a template configuration file:\n");
9955   msg("    %s [-s] -g [configName]\n\n",name);
9956   msg("    If - is used for configName doxygen will write to standard output.\n\n");
9957   msg("2) Use doxygen to update an old configuration file:\n");
9958   msg("    %s [-s] -u [configName]\n\n",name);
9959   msg("3) Use doxygen to generate documentation using an existing ");
9960   msg("configuration file:\n");
9961   msg("    %s [configName]\n\n",name);
9962   msg("    If - is used for configName doxygen will read from standard input.\n\n");
9963   msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9964   msg("   generated documentation:\n");
9965   msg("    %s -l [layoutFileName.xml]\n\n",name);
9966   msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9967   msg("    RTF:        %s -w rtf styleSheetFile\n",name);
9968   msg("    HTML:       %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9969   msg("    LaTeX:      %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9970   msg("6) Use doxygen to generate a rtf extensions file\n");
9971   msg("    RTF:   %s -e rtf extensionsFile\n\n",name);
9972   msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
9973   msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9974   msg("-v print version string\n");
9975 }
9976
9977 //----------------------------------------------------------------------------
9978 // read the argument of option `c' from the comment argument list and
9979 // update the option index `optind'.
9980
9981 static const char *getArg(int argc,char **argv,int &optind)
9982 {
9983   char *s=0;
9984   if (qstrlen(&argv[optind][2])>0)
9985     s=&argv[optind][2];
9986   else if (optind+1<argc && argv[optind+1][0]!='-')
9987     s=argv[++optind];
9988   return s;
9989 }
9990
9991 //----------------------------------------------------------------------------
9992
9993 void initDoxygen()
9994 {
9995   initResources();
9996   const char *lang = portable_getenv("LC_ALL");
9997   if (lang) portable_setenv("LANG",lang);
9998   setlocale(LC_ALL,"");
9999   setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
10000   setlocale(LC_NUMERIC,"C");
10001
10002   portable_correct_path();
10003
10004   Doxygen::runningTime.start();
10005   initPreprocessor();
10006
10007   Doxygen::parserManager = new ParserManager;
10008   Doxygen::parserManager->registerDefaultParser(         new FileParser);
10009   Doxygen::parserManager->registerParser("c",            new CLanguageScanner);
10010   Doxygen::parserManager->registerParser("python",       new PythonLanguageScanner);
10011   Doxygen::parserManager->registerParser("fortran",      new FortranLanguageScanner);
10012   Doxygen::parserManager->registerParser("fortranfree",  new FortranLanguageScannerFree);
10013   Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed);
10014   Doxygen::parserManager->registerParser("vhdl",         new VHDLLanguageScanner);
10015   Doxygen::parserManager->registerParser("xml",          new XMLScanner);
10016   Doxygen::parserManager->registerParser("sql",          new SQLScanner);
10017   Doxygen::parserManager->registerParser("tcl",          new TclLanguageScanner);
10018   Doxygen::parserManager->registerParser("md",           new MarkdownFileParser);
10019
10020   // register any additional parsers here...
10021
10022   initDefaultExtensionMapping();
10023   initClassMemberIndices();
10024   initNamespaceMemberIndices();
10025   initFileMemberIndices();
10026
10027   Doxygen::symbolMap     = new QDict<DefinitionIntf>(50177);
10028 #ifdef USE_LIBCLANG
10029   Doxygen::clangUsrMap   = new QDict<Definition>(50177);
10030 #endif
10031   Doxygen::inputNameList = new FileNameList;
10032   Doxygen::inputNameList->setAutoDelete(TRUE);
10033   Doxygen::memberNameSDict = new MemberNameSDict(10000);
10034   Doxygen::memberNameSDict->setAutoDelete(TRUE);
10035   Doxygen::functionNameSDict = new MemberNameSDict(10000);
10036   Doxygen::functionNameSDict->setAutoDelete(TRUE);
10037   Doxygen::groupSDict = new GroupSDict(17);
10038   Doxygen::groupSDict->setAutoDelete(TRUE);
10039   Doxygen::namespaceSDict = new NamespaceSDict(20);
10040   Doxygen::namespaceSDict->setAutoDelete(TRUE);
10041   Doxygen::classSDict = new ClassSDict(1009);
10042   Doxygen::classSDict->setAutoDelete(TRUE);
10043   Doxygen::hiddenClasses = new ClassSDict(257);
10044   Doxygen::hiddenClasses->setAutoDelete(TRUE);
10045   Doxygen::directories = new DirSDict(17);
10046   Doxygen::directories->setAutoDelete(TRUE);
10047   Doxygen::pageSDict = new PageSDict(1009);          // all doc pages
10048   Doxygen::pageSDict->setAutoDelete(TRUE);
10049   Doxygen::exampleSDict = new PageSDict(1009);       // all examples
10050   Doxygen::exampleSDict->setAutoDelete(TRUE);
10051   Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
10052   Doxygen::tagDestinationDict.setAutoDelete(TRUE);
10053   Doxygen::dirRelations.setAutoDelete(TRUE);
10054   Doxygen::citeDict = new CiteDict(257);
10055   Doxygen::genericsDict = new GenericsSDict;
10056   Doxygen::indexList = new IndexList;
10057   Doxygen::formulaList = new FormulaList;
10058   Doxygen::formulaDict = new FormulaDict(1009);
10059   Doxygen::formulaNameDict = new FormulaDict(1009);
10060   Doxygen::sectionDict = new SectionDict(257);
10061   Doxygen::sectionDict->setAutoDelete(TRUE);
10062
10063   // initialisation of these globals depends on
10064   // configuration switches so we need to postpone these
10065   Doxygen::globalScope     = 0;
10066   Doxygen::inputNameDict   = 0;
10067   Doxygen::includeNameDict = 0;
10068   Doxygen::exampleNameDict = 0;
10069   Doxygen::imageNameDict   = 0;
10070   Doxygen::dotFileNameDict = 0;
10071   Doxygen::mscFileNameDict = 0;
10072   Doxygen::diaFileNameDict = 0;
10073
10074   /**************************************************************************
10075    *            Initialize some global constants
10076    **************************************************************************/
10077
10078   g_compoundKeywordDict.insert("template class",(void *)8);
10079   g_compoundKeywordDict.insert("template struct",(void *)8);
10080   g_compoundKeywordDict.insert("class",(void *)8);
10081   g_compoundKeywordDict.insert("struct",(void *)8);
10082   g_compoundKeywordDict.insert("union",(void *)8);
10083   g_compoundKeywordDict.insert("interface",(void *)8);
10084   g_compoundKeywordDict.insert("exception",(void *)8);
10085 }
10086
10087 void cleanUpDoxygen()
10088 {
10089   delete Doxygen::sectionDict;
10090   delete Doxygen::formulaNameDict;
10091   delete Doxygen::formulaDict;
10092   delete Doxygen::formulaList;
10093   delete Doxygen::indexList;
10094   delete Doxygen::genericsDict;
10095   delete Doxygen::inputNameDict;
10096   delete Doxygen::includeNameDict;
10097   delete Doxygen::exampleNameDict;
10098   delete Doxygen::imageNameDict;
10099   delete Doxygen::dotFileNameDict;
10100   delete Doxygen::mscFileNameDict;
10101   delete Doxygen::diaFileNameDict;
10102   delete Doxygen::mainPage;
10103   delete Doxygen::pageSDict;
10104   delete Doxygen::exampleSDict;
10105   delete Doxygen::globalScope;
10106   delete Doxygen::xrefLists;
10107   delete Doxygen::parserManager;
10108   cleanUpPreprocessor();
10109   delete theTranslator;
10110   delete g_outputList;
10111   Mappers::freeMappers();
10112   codeFreeScanner();
10113
10114   if (Doxygen::symbolMap)
10115   {
10116     // iterate through Doxygen::symbolMap and delete all
10117     // DefinitionList objects, since they have no owner
10118     QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
10119     DefinitionIntf *di;
10120     for (dli.toFirst();(di=dli.current());)
10121     {
10122       if (di->definitionType()==DefinitionIntf::TypeSymbolList)
10123       {
10124         DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
10125         delete (DefinitionList *)tmp;
10126       }
10127       else
10128       {
10129         ++dli;
10130       }
10131     }
10132   }
10133
10134   delete Doxygen::inputNameList;
10135   delete Doxygen::memberNameSDict;
10136   delete Doxygen::functionNameSDict;
10137   delete Doxygen::groupSDict;
10138   delete Doxygen::classSDict;
10139   delete Doxygen::hiddenClasses;
10140   delete Doxygen::namespaceSDict;
10141   delete Doxygen::directories;
10142
10143   //delete Doxygen::symbolMap; <- we cannot do this unless all static lists
10144   //                              (such as Doxygen::namespaceSDict)
10145   //                              with objects based on Definition are made
10146   //                              dynamic first
10147 }
10148
10149 static int computeIdealCacheParam(uint v)
10150 {
10151   //printf("computeIdealCacheParam(v=%u)\n",v);
10152
10153   int r=0;
10154   while (v!=0) v>>=1,r++;
10155   // r = log2(v)
10156
10157   // convert to a valid cache size value
10158   return QMAX(0,QMIN(r-16,9));
10159 }
10160
10161 void readConfiguration(int argc, char **argv)
10162 {
10163   /**************************************************************************
10164    *             Handle arguments                                           *
10165    **************************************************************************/
10166
10167   int optind=1;
10168   const char *configName=0;
10169   const char *layoutName=0;
10170   const char *debugLabel;
10171   const char *formatName;
10172   bool genConfig=FALSE;
10173   bool shortList=FALSE;
10174   bool updateConfig=FALSE;
10175   bool genLayout=FALSE;
10176   int retVal;
10177   while (optind<argc && argv[optind][0]=='-' &&
10178                (isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
10179                 argv[optind][1]=='-')
10180         )
10181   {
10182     switch(argv[optind][1])
10183     {
10184       case 'g':
10185         genConfig=TRUE;
10186         configName=getArg(argc,argv,optind);
10187         if (optind+1<argc && qstrcmp(argv[optind+1],"-")==0)
10188         { configName="-"; optind++; }
10189         if (!configName)
10190         { configName="Doxyfile"; }
10191         break;
10192       case 'l':
10193         genLayout=TRUE;
10194         layoutName=getArg(argc,argv,optind);
10195         if (!layoutName)
10196         { layoutName="DoxygenLayout.xml"; }
10197         break;
10198       case 'd':
10199         debugLabel=getArg(argc,argv,optind);
10200         if (!debugLabel)
10201         {
10202           err("option \"-d\" is missing debug specifier.\n");
10203           devUsage();
10204           cleanUpDoxygen();
10205           exit(1);
10206         }
10207         retVal = Debug::setFlag(debugLabel);
10208         if (!retVal)
10209         {
10210           err("option \"-d\" has unknown debug specifier: \"%s\".\n",debugLabel);
10211           cleanUpDoxygen();
10212           exit(1);
10213         }
10214         break;
10215       case 's':
10216         shortList=TRUE;
10217         break;
10218       case 'u':
10219         updateConfig=TRUE;
10220         break;
10221       case 'e':
10222         formatName=getArg(argc,argv,optind);
10223         if (!formatName)
10224         {
10225           err("option \"-e\" is missing format specifier rtf.\n");
10226           cleanUpDoxygen();
10227           exit(1);
10228         }
10229         if (qstricmp(formatName,"rtf")==0)
10230         {
10231           if (optind+1>=argc)
10232           {
10233             err("option \"-e rtf\" is missing an extensions file name\n");
10234             cleanUpDoxygen();
10235             exit(1);
10236           }
10237           QFile f;
10238           if (openOutputFile(argv[optind+1],f))
10239           {
10240             RTFGenerator::writeExtensionsFile(f);
10241           }
10242           cleanUpDoxygen();
10243           exit(0);
10244         }
10245         err("option \"-e\" has invalid format specifier.\n");
10246         cleanUpDoxygen();
10247         exit(1);
10248         break;
10249       case 'w':
10250         formatName=getArg(argc,argv,optind);
10251         if (!formatName)
10252         {
10253           err("option \"-w\" is missing format specifier rtf, html or latex\n");
10254           cleanUpDoxygen();
10255           exit(1);
10256         }
10257         if (qstricmp(formatName,"rtf")==0)
10258         {
10259           if (optind+1>=argc)
10260           {
10261             err("option \"-w rtf\" is missing a style sheet file name\n");
10262             cleanUpDoxygen();
10263             exit(1);
10264           }
10265           QFile f;
10266           if (openOutputFile(argv[optind+1],f))
10267           {
10268             RTFGenerator::writeStyleSheetFile(f);
10269           }
10270           cleanUpDoxygen();
10271           exit(1);
10272         }
10273         else if (qstricmp(formatName,"html")==0)
10274         {
10275           Config::init();
10276           if (optind+4<argc || QFileInfo("Doxyfile").exists())
10277              // explicit config file mentioned or default found on disk
10278           {
10279             QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10280             if (!Config::parse(df)) // parse the config file
10281             {
10282               err("error opening or reading configuration file %s!\n",argv[optind+4]);
10283               cleanUpDoxygen();
10284               exit(1);
10285             }
10286           }
10287           if (optind+3>=argc)
10288           {
10289             err("option \"-w html\" does not have enough arguments\n");
10290             cleanUpDoxygen();
10291             exit(1);
10292           }
10293           Config::postProcess(TRUE);
10294           Config::checkAndCorrect();
10295
10296           QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10297           if (!setTranslator(outputLanguage))
10298           {
10299             warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10300           }
10301
10302           QFile f;
10303           if (openOutputFile(argv[optind+1],f))
10304           {
10305             HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
10306           }
10307           f.close();
10308           if (openOutputFile(argv[optind+2],f))
10309           {
10310             HtmlGenerator::writeFooterFile(f);
10311           }
10312           f.close();
10313           if (openOutputFile(argv[optind+3],f))
10314           {
10315             HtmlGenerator::writeStyleSheetFile(f);
10316           }
10317           cleanUpDoxygen();
10318           exit(0);
10319         }
10320         else if (qstricmp(formatName,"latex")==0)
10321         {
10322           Config::init();
10323           if (optind+4<argc || QFileInfo("Doxyfile").exists())
10324           {
10325             QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10326             if (!Config::parse(df))
10327             {
10328               err("error opening or reading configuration file %s!\n",argv[optind+4]);
10329               cleanUpDoxygen();
10330               exit(1);
10331             }
10332           }
10333           if (optind+3>=argc)
10334           {
10335             err("option \"-w latex\" does not have enough arguments\n");
10336             cleanUpDoxygen();
10337             exit(1);
10338           }
10339           Config::postProcess(TRUE);
10340           Config::checkAndCorrect();
10341
10342           QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10343           if (!setTranslator(outputLanguage))
10344           {
10345             warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10346           }
10347
10348           QFile f;
10349           if (openOutputFile(argv[optind+1],f))
10350           {
10351             LatexGenerator::writeHeaderFile(f);
10352           }
10353           f.close();
10354           if (openOutputFile(argv[optind+2],f))
10355           {
10356             LatexGenerator::writeFooterFile(f);
10357           }
10358           f.close();
10359           if (openOutputFile(argv[optind+3],f))
10360           {
10361             LatexGenerator::writeStyleSheetFile(f);
10362           }
10363           cleanUpDoxygen();
10364           exit(0);
10365         }
10366         else
10367         {
10368           err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",formatName);
10369           cleanUpDoxygen();
10370           exit(1);
10371         }
10372         break;
10373       case 'm':
10374         g_dumpSymbolMap = TRUE;
10375         break;
10376       case 'v':
10377         msg("%s\n",versionString);
10378         cleanUpDoxygen();
10379         exit(0);
10380         break;
10381       case '-':
10382         if (qstrcmp(&argv[optind][2],"help")==0)
10383         {
10384           usage(argv[0]);
10385           exit(0);
10386         }
10387         else if (qstrcmp(&argv[optind][2],"version")==0)
10388         {
10389           msg("%s\n",versionString);
10390           cleanUpDoxygen();
10391           exit(0);
10392         }
10393         else
10394         {
10395           err("Unknown option \"-%s\"\n",&argv[optind][1]);
10396           usage(argv[0]);
10397           exit(1);
10398         }
10399         break;
10400       case 'b':
10401         setvbuf(stdout,NULL,_IONBF,0);
10402         Doxygen::outputToWizard=TRUE;
10403         break;
10404       case 'T':
10405         msg("Warning: this option activates output generation via Django like template files. "
10406             "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
10407             "Only use if you are a doxygen developer\n");
10408         g_useOutputTemplate=TRUE;
10409         break;
10410       case 'h':
10411       case '?':
10412         usage(argv[0]);
10413         exit(0);
10414         break;
10415       default:
10416         err("Unknown option \"-%c\"\n",argv[optind][1]);
10417         usage(argv[0]);
10418         exit(1);
10419     }
10420     optind++;
10421   }
10422
10423   /**************************************************************************
10424    *            Parse or generate the config file                           *
10425    **************************************************************************/
10426
10427   Config::init();
10428
10429   if (genConfig && g_useOutputTemplate)
10430   {
10431     generateTemplateFiles("templates");
10432     cleanUpDoxygen();
10433     exit(0);
10434   }
10435
10436   if (genConfig)
10437   {
10438     generateConfigFile(configName,shortList);
10439     cleanUpDoxygen();
10440     exit(0);
10441   }
10442   if (genLayout)
10443   {
10444     writeDefaultLayoutFile(layoutName);
10445     cleanUpDoxygen();
10446     exit(0);
10447   }
10448
10449   QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
10450   if (optind>=argc)
10451   {
10452     if (configFileInfo1.exists())
10453     {
10454       configName="Doxyfile";
10455     }
10456     else if (configFileInfo2.exists())
10457     {
10458       configName="doxyfile";
10459     }
10460     else
10461     {
10462       err("Doxyfile not found and no input file specified!\n");
10463       usage(argv[0]);
10464       exit(1);
10465     }
10466   }
10467   else
10468   {
10469     QFileInfo fi(argv[optind]);
10470     if (fi.exists() || qstrcmp(argv[optind],"-")==0)
10471     {
10472       configName=argv[optind];
10473     }
10474     else
10475     {
10476       err("configuration file %s not found!\n",argv[optind]);
10477       usage(argv[0]);
10478       exit(1);
10479     }
10480   }
10481
10482
10483   if (!Config::parse(configName,updateConfig))
10484   {
10485     err("could not open or read configuration file %s!\n",configName);
10486     cleanUpDoxygen();
10487     exit(1);
10488   }
10489
10490   if (updateConfig)
10491   {
10492     generateConfigFile(configName,shortList,TRUE);
10493     cleanUpDoxygen();
10494     exit(0);
10495   }
10496
10497   /* Perlmod wants to know the path to the config file.*/
10498   QFileInfo configFileInfo(configName);
10499   setPerlModDoxyfile(configFileInfo.absFilePath().data());
10500
10501 }
10502
10503 /** check and resolve config options */
10504 void checkConfiguration()
10505 {
10506
10507   Config::postProcess(FALSE);
10508   Config::checkAndCorrect();
10509   initWarningFormat();
10510 }
10511
10512 /** adjust globals that depend on configuration settings. */
10513 void adjustConfiguration()
10514 {
10515   Doxygen::globalScope = new NamespaceDef("<globalScope>",1,1,"<globalScope>");
10516   Doxygen::inputNameDict = new FileNameDict(10007);
10517   Doxygen::includeNameDict = new FileNameDict(10007);
10518   Doxygen::exampleNameDict = new FileNameDict(1009);
10519   Doxygen::exampleNameDict->setAutoDelete(TRUE);
10520   Doxygen::imageNameDict = new FileNameDict(257);
10521   Doxygen::imageNameDict->setAutoDelete(TRUE);
10522   Doxygen::dotFileNameDict = new FileNameDict(257);
10523   Doxygen::mscFileNameDict = new FileNameDict(257);
10524   Doxygen::diaFileNameDict = new FileNameDict(257);
10525
10526   QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10527   if (!setTranslator(outputLanguage))
10528   {
10529     warn_uncond("Output language %s not supported! Using English instead.\n",
10530        outputLanguage.data());
10531   }
10532   QStrList &includePath = Config_getList(INCLUDE_PATH);
10533   char *s=includePath.first();
10534   while (s)
10535   {
10536     QFileInfo fi(s);
10537     addSearchDir(fi.absFilePath().utf8());
10538     s=includePath.next();
10539   }
10540
10541   /* Set the global html file extension. */
10542   Doxygen::htmlFileExtension = Config_getString(HTML_FILE_EXTENSION);
10543
10544
10545   Doxygen::xrefLists->setAutoDelete(TRUE);
10546
10547   Doxygen::parseSourcesNeeded = Config_getBool(CALL_GRAPH) ||
10548                                 Config_getBool(CALLER_GRAPH) ||
10549                                 Config_getBool(REFERENCES_RELATION) ||
10550                                 Config_getBool(REFERENCED_BY_RELATION);
10551
10552   Doxygen::markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
10553
10554   /**************************************************************************
10555    *            Add custom extension mappings
10556    **************************************************************************/
10557
10558   QStrList &extMaps = Config_getList(EXTENSION_MAPPING);
10559   char *mapping = extMaps.first();
10560   while (mapping)
10561   {
10562     QCString mapStr = mapping;
10563     int i;
10564     if ((i=mapStr.find('='))!=-1)
10565     {
10566       QCString ext=mapStr.left(i).stripWhiteSpace().lower();
10567       QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
10568       if (!updateLanguageMapping(ext,language))
10569       {
10570         err("Failed to map file extension '%s' to unsupported language '%s'.\n"
10571             "Check the EXTENSION_MAPPING setting in the config file.\n",
10572             ext.data(),language.data());
10573       }
10574       else
10575       {
10576         msg("Adding custom extension mapping: .%s will be treated as language %s\n",
10577             ext.data(),language.data());
10578       }
10579     }
10580     mapping = extMaps.next();
10581   }
10582
10583
10584   // add predefined macro name to a dictionary
10585   QStrList &expandAsDefinedList =Config_getList(EXPAND_AS_DEFINED);
10586   s=expandAsDefinedList.first();
10587   while (s)
10588   {
10589     if (Doxygen::expandAsDefinedDict[s]==0)
10590     {
10591       Doxygen::expandAsDefinedDict.insert(s,(void *)666);
10592     }
10593     s=expandAsDefinedList.next();
10594   }
10595
10596   // read aliases and store them in a dictionary
10597   readAliases();
10598
10599   // store number of spaces in a tab into Doxygen::spaces
10600   int &tabSize = Config_getInt(TAB_SIZE);
10601   Doxygen::spaces.resize(tabSize+1);
10602   int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
10603   Doxygen::spaces.at(tabSize)='\0';
10604 }
10605
10606 #ifdef HAS_SIGNALS
10607 static void stopDoxygen(int)
10608 {
10609   QDir thisDir;
10610   msg("Cleaning up...\n");
10611   if (!Doxygen::entryDBFileName.isEmpty())
10612   {
10613     thisDir.remove(Doxygen::entryDBFileName);
10614   }
10615   if (!Doxygen::objDBFileName.isEmpty())
10616   {
10617     thisDir.remove(Doxygen::objDBFileName);
10618   }
10619   killpg(0,SIGINT);
10620   exit(1);
10621 }
10622 #endif
10623
10624 static void writeTagFile()
10625 {
10626   QCString &generateTagFile = Config_getString(GENERATE_TAGFILE);
10627   if (generateTagFile.isEmpty()) return;
10628
10629   QFile tag(generateTagFile);
10630   if (!tag.open(IO_WriteOnly))
10631   {
10632     err("cannot open tag file %s for writing\n",
10633         generateTagFile.data()
10634        );
10635     return;
10636   }
10637   FTextStream tagFile(&tag);
10638   tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
10639   tagFile << "<tagfile>" << endl;
10640
10641   // for each file
10642   FileNameListIterator fnli(*Doxygen::inputNameList);
10643   FileName *fn;
10644   for (fnli.toFirst();(fn=fnli.current());++fnli)
10645   {
10646     FileNameIterator fni(*fn);
10647     FileDef *fd;
10648     for (fni.toFirst();(fd=fni.current());++fni)
10649     {
10650       if (fd->isLinkableInProject()) fd->writeTagFile(tagFile);
10651     }
10652   }
10653   // for each class
10654   ClassSDict::Iterator cli(*Doxygen::classSDict);
10655   ClassDef *cd;
10656   for ( ; (cd=cli.current()) ; ++cli )
10657   {
10658     if (cd->isLinkableInProject()) cd->writeTagFile(tagFile);
10659   }
10660   // for each namespace
10661   NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
10662   NamespaceDef *nd;
10663   for ( ; (nd=nli.current()) ; ++nli )
10664   {
10665     if (nd->isLinkableInProject()) nd->writeTagFile(tagFile);
10666   }
10667   // for each group
10668   GroupSDict::Iterator gli(*Doxygen::groupSDict);
10669   GroupDef *gd;
10670   for (gli.toFirst();(gd=gli.current());++gli)
10671   {
10672     if (gd->isLinkableInProject()) gd->writeTagFile(tagFile);
10673   }
10674   // for each page
10675   PageSDict::Iterator pdi(*Doxygen::pageSDict);
10676   PageDef *pd=0;
10677   for (pdi.toFirst();(pd=pdi.current());++pdi)
10678   {
10679     if (pd->isLinkableInProject()) pd->writeTagFile(tagFile);
10680   }
10681   if (Doxygen::mainPage) Doxygen::mainPage->writeTagFile(tagFile);
10682
10683   /*
10684   if (Doxygen::mainPage && !Config_getString(GENERATE_TAGFILE).isEmpty())
10685   {
10686     tagFile << "  <compound kind=\"page\">" << endl
10687                      << "    <name>"
10688                      << convertToXML(Doxygen::mainPage->name())
10689                      << "</name>" << endl
10690                      << "    <title>"
10691                      << convertToXML(Doxygen::mainPage->title())
10692                      << "</title>" << endl
10693                      << "    <filename>"
10694                      << convertToXML(Doxygen::mainPage->getOutputFileBase())
10695                      << "</filename>" << endl;
10696
10697     mainPage->writeDocAnchorsToTagFile();
10698     tagFile << "  </compound>" << endl;
10699   }
10700   */
10701
10702   tagFile << "</tagfile>" << endl;
10703 }
10704
10705 static void exitDoxygen()
10706 {
10707   if (!g_successfulRun)  // premature exit
10708   {
10709     QDir thisDir;
10710     msg("Exiting...\n");
10711     if (!Doxygen::entryDBFileName.isEmpty())
10712     {
10713       thisDir.remove(Doxygen::entryDBFileName);
10714     }
10715     if (!Doxygen::objDBFileName.isEmpty())
10716     {
10717       thisDir.remove(Doxygen::objDBFileName);
10718     }
10719   }
10720 }
10721
10722 static QCString createOutputDirectory(const QCString &baseDirName,
10723                                   QCString &formatDirName,
10724                                   const char *defaultDirName)
10725 {
10726   // Note the & on the next line, we modify the formatDirOption!
10727   if (formatDirName.isEmpty())
10728   {
10729     formatDirName = baseDirName + defaultDirName;
10730   }
10731   else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
10732   {
10733     formatDirName.prepend(baseDirName+'/');
10734   }
10735   QDir formatDir(formatDirName);
10736   if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
10737   {
10738     err("Could not create output directory %s\n", formatDirName.data());
10739     cleanUpDoxygen();
10740     exit(1);
10741   }
10742   return formatDirName;
10743 }
10744
10745 static QCString getQchFileName()
10746 {
10747   QCString const & qchFile = Config_getString(QCH_FILE);
10748   if (!qchFile.isEmpty())
10749   {
10750     return qchFile;
10751   }
10752
10753   QCString const & projectName = Config_getString(PROJECT_NAME);
10754   QCString const & versionText = Config_getString(PROJECT_NUMBER);
10755
10756   return QCString("../qch/")
10757       + (projectName.isEmpty() ? QCString("index") : projectName)
10758       + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
10759       + QCString(".qch");
10760 }
10761
10762 void searchInputFiles()
10763 {
10764   QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
10765   bool alwaysRecursive = Config_getBool(RECURSIVE);
10766   StringDict excludeNameDict(1009);
10767   excludeNameDict.setAutoDelete(TRUE);
10768
10769   // gather names of all files in the include path
10770   g_s.begin("Searching for include files...\n");
10771   QStrList &includePathList = Config_getList(INCLUDE_PATH);
10772   char *s=includePathList.first();
10773   while (s)
10774   {
10775     QStrList &pl = Config_getList(INCLUDE_FILE_PATTERNS);
10776     if (pl.count()==0)
10777     {
10778       pl = Config_getList(FILE_PATTERNS);
10779     }
10780     readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
10781                         &exclPatterns,0,0,
10782                         alwaysRecursive);
10783     s=includePathList.next();
10784   }
10785   g_s.end();
10786
10787   g_s.begin("Searching for example files...\n");
10788   QStrList &examplePathList = Config_getList(EXAMPLE_PATH);
10789   s=examplePathList.first();
10790   while (s)
10791   {
10792     readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
10793                         &Config_getList(EXAMPLE_PATTERNS),
10794                         0,0,0,
10795                         (alwaysRecursive || Config_getBool(EXAMPLE_RECURSIVE)));
10796     s=examplePathList.next();
10797   }
10798   g_s.end();
10799
10800   g_s.begin("Searching for images...\n");
10801   QStrList &imagePathList=Config_getList(IMAGE_PATH);
10802   s=imagePathList.first();
10803   while (s)
10804   {
10805     readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
10806                         0,0,0,
10807                         alwaysRecursive);
10808     s=imagePathList.next();
10809   }
10810   g_s.end();
10811
10812   g_s.begin("Searching for dot files...\n");
10813   QStrList &dotFileList=Config_getList(DOTFILE_DIRS);
10814   s=dotFileList.first();
10815   while (s)
10816   {
10817     readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
10818                         0,0,0,
10819                         alwaysRecursive);
10820     s=dotFileList.next();
10821   }
10822   g_s.end();
10823
10824   g_s.begin("Searching for msc files...\n");
10825   QStrList &mscFileList=Config_getList(MSCFILE_DIRS);
10826   s=mscFileList.first();
10827   while (s)
10828   {
10829     readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
10830                         0,0,0,
10831                         alwaysRecursive);
10832     s=mscFileList.next();
10833   }
10834   g_s.end();
10835
10836   g_s.begin("Searching for dia files...\n");
10837   QStrList &diaFileList=Config_getList(DIAFILE_DIRS);
10838   s=diaFileList.first();
10839   while (s)
10840   {
10841     readFileOrDirectory(s,0,Doxygen::diaFileNameDict,0,0,
10842                         0,0,0,
10843                         alwaysRecursive);
10844     s=diaFileList.next();
10845   }
10846   g_s.end();
10847
10848   g_s.begin("Searching for files to exclude\n");
10849   QStrList &excludeList = Config_getList(EXCLUDE);
10850   s=excludeList.first();
10851   while (s)
10852   {
10853     readFileOrDirectory(s,0,0,0,&Config_getList(FILE_PATTERNS),
10854                         0,0,&excludeNameDict,
10855                         alwaysRecursive,
10856                         FALSE);
10857     s=excludeList.next();
10858   }
10859   g_s.end();
10860
10861   /**************************************************************************
10862    *             Determine Input Files                                      *
10863    **************************************************************************/
10864
10865   g_s.begin("Searching INPUT for files to process...\n");
10866   QDict<void> *killDict = new QDict<void>(10007);
10867   QStrList &inputList=Config_getList(INPUT);
10868   g_inputFiles.setAutoDelete(TRUE);
10869   s=inputList.first();
10870   while (s)
10871   {
10872     QCString path=s;
10873     uint l = path.length();
10874     if (l>0)
10875     {
10876       // strip trailing slashes
10877       if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
10878
10879       readFileOrDirectory(
10880           path,
10881           Doxygen::inputNameList,
10882           Doxygen::inputNameDict,
10883           &excludeNameDict,
10884           &Config_getList(FILE_PATTERNS),
10885           &exclPatterns,
10886           &g_inputFiles,0,
10887           alwaysRecursive,
10888           TRUE,
10889           killDict,
10890           &Doxygen::inputPaths);
10891     }
10892     s=inputList.next();
10893   }
10894   delete killDict;
10895   g_s.end();
10896 }
10897
10898
10899 void parseInput()
10900 {
10901   atexit(exitDoxygen);
10902
10903
10904   /**************************************************************************
10905    *            Make sure the output directory exists
10906    **************************************************************************/
10907   QCString &outputDirectory = Config_getString(OUTPUT_DIRECTORY);
10908   if (outputDirectory.isEmpty())
10909   {
10910     outputDirectory=QDir::currentDirPath().utf8();
10911   }
10912   else
10913   {
10914     QDir dir(outputDirectory);
10915     if (!dir.exists())
10916     {
10917       dir.setPath(QDir::currentDirPath());
10918       if (!dir.mkdir(outputDirectory))
10919       {
10920         err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
10921             "exist and cannot be created\n",outputDirectory.data());
10922         cleanUpDoxygen();
10923         exit(1);
10924       }
10925       else
10926       {
10927         msg("Notice: Output directory `%s' does not exist. "
10928             "I have created it for you.\n", outputDirectory.data());
10929       }
10930       dir.cd(outputDirectory);
10931     }
10932     outputDirectory=dir.absPath().utf8();
10933   }
10934
10935   /**************************************************************************
10936    *            Initialize global lists and dictionaries
10937    **************************************************************************/
10938
10939   Doxygen::symbolStorage = new Store;
10940
10941   // also scale lookup cache with SYMBOL_CACHE_SIZE
10942   int cacheSize = Config_getInt(LOOKUP_CACHE_SIZE);
10943   if (cacheSize<0) cacheSize=0;
10944   if (cacheSize>9) cacheSize=9;
10945   uint lookupSize = 65536 << cacheSize;
10946   Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
10947   Doxygen::lookupCache->setAutoDelete(TRUE);
10948
10949 #ifdef HAS_SIGNALS
10950   signal(SIGINT, stopDoxygen);
10951 #endif
10952
10953   uint pid = portable_pid();
10954   Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10955   Doxygen::objDBFileName.prepend(outputDirectory+"/");
10956   Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10957   Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10958
10959   if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10960   {
10961     err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10962     exit(1);
10963   }
10964
10965
10966
10967   /**************************************************************************
10968    *            Check/create output directorties                            *
10969    **************************************************************************/
10970
10971   QCString htmlOutput;
10972   bool &generateHtml = Config_getBool(GENERATE_HTML);
10973   if (generateHtml || g_useOutputTemplate /* TODO: temp hack */)
10974     htmlOutput = createOutputDirectory(outputDirectory,Config_getString(HTML_OUTPUT),"/html");
10975
10976   QCString docbookOutput;
10977   bool &generateDocbook = Config_getBool(GENERATE_DOCBOOK);
10978   if (generateDocbook)
10979     docbookOutput = createOutputDirectory(outputDirectory,Config_getString(DOCBOOK_OUTPUT),"/docbook");
10980
10981   QCString xmlOutput;
10982   bool &generateXml = Config_getBool(GENERATE_XML);
10983   if (generateXml)
10984     xmlOutput = createOutputDirectory(outputDirectory,Config_getString(XML_OUTPUT),"/xml");
10985
10986   QCString latexOutput;
10987   bool &generateLatex = Config_getBool(GENERATE_LATEX);
10988   if (generateLatex)
10989     latexOutput = createOutputDirectory(outputDirectory,Config_getString(LATEX_OUTPUT),"/latex");
10990
10991   QCString rtfOutput;
10992   bool &generateRtf = Config_getBool(GENERATE_RTF);
10993   if (generateRtf)
10994     rtfOutput = createOutputDirectory(outputDirectory,Config_getString(RTF_OUTPUT),"/rtf");
10995
10996   QCString manOutput;
10997   bool &generateMan = Config_getBool(GENERATE_MAN);
10998   if (generateMan)
10999     manOutput = createOutputDirectory(outputDirectory,Config_getString(MAN_OUTPUT),"/man");
11000
11001   //QCString sqlOutput;
11002   //bool &generateSql = Config_getBool(GENERATE_SQLITE3);
11003   //if (generateSql)
11004   //  sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3");
11005
11006   if (Config_getBool(HAVE_DOT))
11007   {
11008     QCString curFontPath = Config_getString(DOT_FONTPATH);
11009     if (curFontPath.isEmpty())
11010     {
11011       portable_getenv("DOTFONTPATH");
11012       QCString newFontPath = ".";
11013       if (!curFontPath.isEmpty())
11014       {
11015         newFontPath+=portable_pathListSeparator();
11016         newFontPath+=curFontPath;
11017       }
11018       portable_setenv("DOTFONTPATH",newFontPath);
11019     }
11020     else
11021     {
11022       portable_setenv("DOTFONTPATH",curFontPath);
11023     }
11024   }
11025
11026
11027
11028   /**************************************************************************
11029    *             Handle layout file                                         *
11030    **************************************************************************/
11031
11032   LayoutDocManager::instance().init();
11033   QCString &layoutFileName = Config_getString(LAYOUT_FILE);
11034   bool defaultLayoutUsed = FALSE;
11035   if (layoutFileName.isEmpty())
11036   {
11037     layoutFileName = "DoxygenLayout.xml";
11038     defaultLayoutUsed = TRUE;
11039   }
11040
11041   QFile layoutFile(layoutFileName);
11042   if (layoutFile.open(IO_ReadOnly))
11043   {
11044     msg("Parsing layout file %s...\n",layoutFileName.data());
11045     QTextStream t(&layoutFile);
11046     t.setEncoding(QTextStream::Latin1);
11047     LayoutDocManager::instance().parse(t,layoutFileName);
11048   }
11049   else if (!defaultLayoutUsed)
11050   {
11051     warn_uncond("failed to open layout file '%s' for reading!\n",layoutFileName.data());
11052   }
11053
11054   /**************************************************************************
11055    *             Read and preprocess input                                  *
11056    **************************************************************************/
11057
11058   // prevent search in the output directories
11059   QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
11060   if (generateHtml)    exclPatterns.append(htmlOutput);
11061   if (generateDocbook) exclPatterns.append(docbookOutput);
11062   if (generateXml)     exclPatterns.append(xmlOutput);
11063   if (generateLatex)   exclPatterns.append(latexOutput);
11064   if (generateRtf)     exclPatterns.append(rtfOutput);
11065   if (generateMan)     exclPatterns.append(manOutput);
11066
11067   searchInputFiles();
11068
11069   // Notice: the order of the function calls below is very important!
11070
11071   if (Config_getBool(GENERATE_HTML))
11072   {
11073     readFormulaRepository();
11074   }
11075
11076   /**************************************************************************
11077    *             Handle Tag Files                                           *
11078    **************************************************************************/
11079
11080   g_storage = new FileStorage;
11081   g_storage->setName(Doxygen::entryDBFileName);
11082   if (!g_storage->open(IO_WriteOnly))
11083   {
11084     err("Failed to create temporary storage file %s\n",
11085         Doxygen::entryDBFileName.data());
11086     exit(1);
11087   }
11088   Entry *root=new Entry;
11089   EntryNav *rootNav = new EntryNav(0,root);
11090   rootNav->setEntry(root);
11091   msg("Reading and parsing tag files\n");
11092
11093   QStrList &tagFileList = Config_getList(TAGFILES);
11094   char *s=tagFileList.first();
11095   while (s)
11096   {
11097     readTagFile(root,s);
11098     root->createNavigationIndex(rootNav,g_storage,0);
11099     s=tagFileList.next();
11100   }
11101
11102   /**************************************************************************
11103    *             Parse source files                                         *
11104    **************************************************************************/
11105
11106   if (Config_getBool(BUILTIN_STL_SUPPORT))
11107   {
11108     addSTLClasses(rootNav);
11109   }
11110
11111   g_s.begin("Parsing files\n");
11112   parseFiles(root,rootNav);
11113   g_storage->close();
11114   g_s.end();
11115
11116   // we are done with input scanning now, so free up the buffers used by flex
11117   // (can be around 4MB)
11118   preFreeScanner();
11119   scanFreeScanner();
11120   pyscanFreeScanner();
11121
11122   if (!g_storage->open(IO_ReadOnly))
11123   {
11124     err("Failed to open temporary storage file %s for reading",
11125         Doxygen::entryDBFileName.data());
11126     exit(1);
11127   }
11128
11129   /**************************************************************************
11130    *             Gather information                                         *
11131    **************************************************************************/
11132
11133   g_s.begin("Building group list...\n");
11134   buildGroupList(rootNav);
11135   organizeSubGroups(rootNav);
11136   g_s.end();
11137
11138   g_s.begin("Building directory list...\n");
11139   buildDirectories();
11140   findDirDocumentation(rootNav);
11141   g_s.end();
11142
11143   g_s.begin("Building namespace list...\n");
11144   buildNamespaceList(rootNav);
11145   findUsingDirectives(rootNav);
11146   g_s.end();
11147
11148   g_s.begin("Building file list...\n");
11149   buildFileList(rootNav);
11150   g_s.end();
11151   //generateFileTree();
11152
11153   g_s.begin("Building class list...\n");
11154   buildClassList(rootNav);
11155   g_s.end();
11156
11157   g_s.begin("Associating documentation with classes...\n");
11158   buildClassDocList(rootNav);
11159
11160   // build list of using declarations here (global list)
11161   buildListOfUsingDecls(rootNav);
11162   g_s.end();
11163
11164   g_s.begin("Computing nesting relations for classes...\n");
11165   resolveClassNestingRelations();
11166   g_s.end();
11167   // 1.8.2-20121111: no longer add nested classes to the group as well
11168   //distributeClassGroupRelations();
11169
11170   // calling buildClassList may result in cached relations that
11171   // become invalid after resolveClassNestingRelations(), that's why
11172   // we need to clear the cache here
11173   Doxygen::lookupCache->clear();
11174   // we don't need the list of using declaration anymore
11175   g_usingDeclarations.clear();
11176
11177   g_s.begin("Building example list...\n");
11178   buildExampleList(rootNav);
11179   g_s.end();
11180
11181   g_s.begin("Searching for enumerations...\n");
11182   findEnums(rootNav);
11183   g_s.end();
11184
11185   // Since buildVarList calls isVarWithConstructor
11186   // and this calls getResolvedClass we need to process
11187   // typedefs first so the relations between classes via typedefs
11188   // are properly resolved. See bug 536385 for an example.
11189   g_s.begin("Searching for documented typedefs...\n");
11190   buildTypedefList(rootNav);
11191   g_s.end();
11192
11193   g_s.begin("Searching for members imported via using declarations...\n");
11194   // this should be after buildTypedefList in order to properly import
11195   // used typedefs
11196   findUsingDeclarations(rootNav);
11197   g_s.end();
11198
11199   g_s.begin("Searching for included using directives...\n");
11200   findIncludedUsingDirectives();
11201   g_s.end();
11202
11203   g_s.begin("Searching for documented variables...\n");
11204   buildVarList(rootNav);
11205   g_s.end();
11206
11207   g_s.begin("Building interface member list...\n");
11208   buildInterfaceAndServiceList(rootNav); // UNO IDL
11209
11210   g_s.begin("Building member list...\n"); // using class info only !
11211   buildFunctionList(rootNav);
11212   g_s.end();
11213
11214   g_s.begin("Searching for friends...\n");
11215   findFriends();
11216   g_s.end();
11217
11218   g_s.begin("Searching for documented defines...\n");
11219   findDefineDocumentation(rootNav);
11220   g_s.end();
11221
11222   g_s.begin("Computing class inheritance relations...\n");
11223   findClassEntries(rootNav);
11224   findInheritedTemplateInstances();
11225   g_s.end();
11226
11227   g_s.begin("Computing class usage relations...\n");
11228   findUsedTemplateInstances();
11229   g_s.end();
11230
11231   if (Config_getBool(INLINE_SIMPLE_STRUCTS))
11232   {
11233     g_s.begin("Searching for tag less structs...\n");
11234     findTagLessClasses();
11235     g_s.end();
11236   }
11237
11238   g_s.begin("Flushing cached template relations that have become invalid...\n");
11239   flushCachedTemplateRelations();
11240   g_s.end();
11241
11242   g_s.begin("Computing class relations...\n");
11243   computeTemplateClassRelations();
11244   flushUnresolvedRelations();
11245   if (Config_getBool(OPTIMIZE_OUTPUT_VHDL))
11246   {
11247     VhdlDocGen::computeVhdlComponentRelations();
11248   }
11249   computeClassRelations();
11250   g_classEntries.clear();
11251   g_s.end();
11252
11253   g_s.begin("Add enum values to enums...\n");
11254   addEnumValuesToEnums(rootNav);
11255   findEnumDocumentation(rootNav);
11256   g_s.end();
11257
11258   g_s.begin("Searching for member function documentation...\n");
11259   findObjCMethodDefinitions(rootNav);
11260   findMemberDocumentation(rootNav); // may introduce new members !
11261   findUsingDeclImports(rootNav); // may introduce new members !
11262
11263   transferRelatedFunctionDocumentation();
11264   transferFunctionDocumentation();
11265   g_s.end();
11266
11267   // moved to after finding and copying documentation,
11268   // as this introduces new members see bug 722654
11269   g_s.begin("Creating members for template instances...\n");
11270   createTemplateInstanceMembers();
11271   g_s.end();
11272
11273   g_s.begin("Building page list...\n");
11274   buildPageList(rootNav);
11275   g_s.end();
11276
11277   g_s.begin("Search for main page...\n");
11278   findMainPage(rootNav);
11279   findMainPageTagFiles(rootNav);
11280   g_s.end();
11281
11282   g_s.begin("Computing page relations...\n");
11283   computePageRelations(rootNav);
11284   checkPageRelations();
11285   g_s.end();
11286
11287   g_s.begin("Determining the scope of groups...\n");
11288   findGroupScope(rootNav);
11289   g_s.end();
11290
11291   g_s.begin("Sorting lists...\n");
11292   Doxygen::memberNameSDict->sort();
11293   Doxygen::functionNameSDict->sort();
11294   Doxygen::hiddenClasses->sort();
11295   Doxygen::classSDict->sort();
11296   g_s.end();
11297
11298   msg("Freeing entry tree\n");
11299   delete rootNav;
11300   g_storage->close();
11301   delete g_storage;
11302   g_storage=0;
11303
11304   QDir thisDir;
11305   thisDir.remove(Doxygen::entryDBFileName);
11306
11307   g_s.begin("Determining which enums are documented\n");
11308   findDocumentedEnumValues();
11309   g_s.end();
11310
11311   g_s.begin("Computing member relations...\n");
11312   mergeCategories();
11313   computeMemberRelations();
11314   g_s.end();
11315
11316   g_s.begin("Building full member lists recursively...\n");
11317   buildCompleteMemberLists();
11318   g_s.end();
11319
11320   g_s.begin("Adding members to member groups.\n");
11321   addMembersToMemberGroup();
11322   g_s.end();
11323
11324   if (Config_getBool(DISTRIBUTE_GROUP_DOC))
11325   {
11326     g_s.begin("Distributing member group documentation.\n");
11327     distributeMemberGroupDocumentation();
11328     g_s.end();
11329   }
11330
11331   g_s.begin("Computing member references...\n");
11332   computeMemberReferences();
11333   g_s.end();
11334
11335   if (Config_getBool(INHERIT_DOCS))
11336   {
11337     g_s.begin("Inheriting documentation...\n");
11338     inheritDocumentation();
11339     g_s.end();
11340   }
11341
11342   // compute the shortest possible names of all files
11343   // without losing the uniqueness of the file names.
11344   g_s.begin("Generating disk names...\n");
11345   Doxygen::inputNameList->generateDiskNames();
11346   g_s.end();
11347
11348   g_s.begin("Adding source references...\n");
11349   addSourceReferences();
11350   g_s.end();
11351
11352   g_s.begin("Adding xrefitems...\n");
11353   addListReferences();
11354   generateXRefPages();
11355   g_s.end();
11356
11357   g_s.begin("Sorting member lists...\n");
11358   sortMemberLists();
11359   g_s.end();
11360
11361   if (Config_getBool(DIRECTORY_GRAPH))
11362   {
11363     g_s.begin("Computing dependencies between directories...\n");
11364     computeDirDependencies();
11365     g_s.end();
11366   }
11367
11368   //g_s.begin("Resolving citations...\n");
11369   //Doxygen::citeDict->resolve();
11370
11371   g_s.begin("Generating citations page...\n");
11372   Doxygen::citeDict->generatePage();
11373   g_s.end();
11374
11375   g_s.begin("Counting data structures...\n");
11376   countDataStructures();
11377   g_s.end();
11378
11379   g_s.begin("Resolving user defined references...\n");
11380   resolveUserReferences();
11381   g_s.end();
11382
11383   g_s.begin("Finding anchors and sections in the documentation...\n");
11384   findSectionsInDocumentation();
11385   g_s.end();
11386
11387   g_s.begin("Transferring function references...\n");
11388   transferFunctionReferences();
11389   g_s.end();
11390
11391   g_s.begin("Combining using relations...\n");
11392   combineUsingRelations();
11393   g_s.end();
11394
11395   g_s.begin("Adding members to index pages...\n");
11396   addMembersToIndex();
11397   g_s.end();
11398 }
11399
11400 void generateOutput()
11401 {
11402   /**************************************************************************
11403    *            Initialize output generators                                *
11404    **************************************************************************/
11405
11406   /// add extra languages for which we can only produce syntax highlighted code
11407   addCodeOnlyMappings();
11408
11409   //// dump all symbols
11410   if (g_dumpSymbolMap)
11411   {
11412     dumpSymbolMap();
11413     exit(0);
11414   }
11415
11416   initSearchIndexer();
11417
11418   bool generateHtml  = Config_getBool(GENERATE_HTML);
11419   bool generateLatex = Config_getBool(GENERATE_LATEX);
11420   bool generateMan   = Config_getBool(GENERATE_MAN);
11421   bool generateRtf   = Config_getBool(GENERATE_RTF);
11422
11423
11424   g_outputList = new OutputList(TRUE);
11425   if (generateHtml)
11426   {
11427     g_outputList->add(new HtmlGenerator);
11428     HtmlGenerator::init();
11429
11430     // add HTML indexers that are enabled
11431     bool generateHtmlHelp    = Config_getBool(GENERATE_HTMLHELP);
11432     bool generateEclipseHelp = Config_getBool(GENERATE_ECLIPSEHELP);
11433     bool generateQhp         = Config_getBool(GENERATE_QHP);
11434     bool generateTreeView    = Config_getBool(GENERATE_TREEVIEW);
11435     bool generateDocSet      = Config_getBool(GENERATE_DOCSET);
11436     if (generateEclipseHelp) Doxygen::indexList->addIndex(new EclipseHelp);
11437     if (generateHtmlHelp)    Doxygen::indexList->addIndex(new HtmlHelp);
11438     if (generateQhp)         Doxygen::indexList->addIndex(new Qhp);
11439     if (generateTreeView)    Doxygen::indexList->addIndex(new FTVHelp(TRUE));
11440     if (generateDocSet)      Doxygen::indexList->addIndex(new DocSets);
11441     Doxygen::indexList->initialize();
11442     HtmlGenerator::writeTabData();
11443   }
11444   if (generateLatex)
11445   {
11446     g_outputList->add(new LatexGenerator);
11447     LatexGenerator::init();
11448   }
11449   if (generateMan)
11450   {
11451     g_outputList->add(new ManGenerator);
11452     ManGenerator::init();
11453   }
11454   if (generateRtf)
11455   {
11456     g_outputList->add(new RTFGenerator);
11457     RTFGenerator::init();
11458   }
11459   if (Config_getBool(USE_HTAGS))
11460   {
11461     Htags::useHtags = TRUE;
11462     QCString htmldir = Config_getString(HTML_OUTPUT);
11463     if (!Htags::execute(htmldir))
11464        err("USE_HTAGS is YES but htags(1) failed. \n");
11465     if (!Htags::loadFilemap(htmldir))
11466        err("htags(1) ended normally but failed to load the filemap. \n");
11467   }
11468
11469   /**************************************************************************
11470    *                        Generate documentation                          *
11471    **************************************************************************/
11472
11473   if (generateHtml)  writeDoxFont(Config_getString(HTML_OUTPUT));
11474   if (generateLatex) writeDoxFont(Config_getString(LATEX_OUTPUT));
11475   if (generateRtf)   writeDoxFont(Config_getString(RTF_OUTPUT));
11476
11477   g_s.begin("Generating style sheet...\n");
11478   //printf("writing style info\n");
11479   g_outputList->writeStyleInfo(0); // write first part
11480   g_s.end();
11481
11482   static bool searchEngine      = Config_getBool(SEARCHENGINE);
11483   static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
11484
11485   g_s.begin("Generating search indices...\n");
11486   if (searchEngine && !serverBasedSearch && (generateHtml || g_useOutputTemplate))
11487   {
11488     createJavascriptSearchIndex();
11489   }
11490
11491   // generate search indices (need to do this before writing other HTML
11492   // pages as these contain a drop down menu with options depending on
11493   // what categories we find in this function.
11494   if (generateHtml && searchEngine)
11495   {
11496     QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search";
11497     QDir searchDir(searchDirName);
11498     if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
11499     {
11500       err("Could not create search results directory '%s' $PWD='%s'\n",
11501           searchDirName.data(),QDir::currentDirPath().data());
11502       exit(1);
11503     }
11504     HtmlGenerator::writeSearchData(searchDirName);
11505     if (!serverBasedSearch) // client side search index
11506     {
11507       writeJavascriptSearchIndex();
11508     }
11509   }
11510   g_s.end();
11511
11512   g_s.begin("Generating example documentation...\n");
11513   generateExampleDocs();
11514   g_s.end();
11515
11516   if (!Htags::useHtags)
11517   {
11518     g_s.begin("Generating file sources...\n");
11519     generateFileSources();
11520     g_s.end();
11521   }
11522
11523   g_s.begin("Generating file documentation...\n");
11524   generateFileDocs();
11525   g_s.end();
11526
11527   g_s.begin("Generating page documentation...\n");
11528   generatePageDocs();
11529   g_s.end();
11530
11531   g_s.begin("Generating group documentation...\n");
11532   generateGroupDocs();
11533   g_s.end();
11534
11535   g_s.begin("Generating class documentation...\n");
11536   generateClassDocs();
11537   g_s.end();
11538
11539   g_s.begin("Generating namespace index...\n");
11540   generateNamespaceDocs();
11541   g_s.end();
11542
11543   if (Config_getBool(GENERATE_LEGEND))
11544   {
11545     g_s.begin("Generating graph info page...\n");
11546     writeGraphInfo(*g_outputList);
11547     g_s.end();
11548   }
11549
11550   g_s.begin("Generating directory documentation...\n");
11551   generateDirDocs(*g_outputList);
11552   g_s.end();
11553
11554   if (Doxygen::formulaList->count()>0 && generateHtml
11555       && !Config_getBool(USE_MATHJAX))
11556   {
11557     g_s.begin("Generating bitmaps for formulas in HTML...\n");
11558     Doxygen::formulaList->generateBitmaps(Config_getString(HTML_OUTPUT));
11559     g_s.end();
11560   }
11561
11562   if (Config_getBool(SORT_GROUP_NAMES))
11563   {
11564     Doxygen::groupSDict->sort();
11565     GroupSDict::Iterator gli(*Doxygen::groupSDict);
11566     GroupDef *gd;
11567     for (gli.toFirst();(gd=gli.current());++gli)
11568     {
11569       gd->sortSubGroups();
11570     }
11571   }
11572
11573   if (g_outputList->count()>0)
11574   {
11575     writeIndexHierarchy(*g_outputList);
11576   }
11577
11578   g_s.begin("finalizing index lists...\n");
11579   Doxygen::indexList->finalize();
11580   g_s.end();
11581
11582   g_s.begin("writing tag file...\n");
11583   writeTagFile();
11584   g_s.end();
11585
11586   if (Config_getBool(DOT_CLEANUP))
11587   {
11588     if (generateHtml)
11589       removeDoxFont(Config_getString(HTML_OUTPUT));
11590     if (generateRtf)
11591       removeDoxFont(Config_getString(RTF_OUTPUT));
11592     if (generateLatex)
11593       removeDoxFont(Config_getString(LATEX_OUTPUT));
11594   }
11595
11596   if (Config_getBool(GENERATE_XML))
11597   {
11598     g_s.begin("Generating XML output...\n");
11599     Doxygen::generatingXmlOutput=TRUE;
11600     generateXML();
11601     Doxygen::generatingXmlOutput=FALSE;
11602     g_s.end();
11603   }
11604   if (USE_SQLITE3)
11605   {
11606     g_s.begin("Generating SQLITE3 output...\n");
11607     generateSqlite3();
11608     g_s.end();
11609   }
11610
11611   if (Config_getBool(GENERATE_DOCBOOK))
11612   {
11613     g_s.begin("Generating Docbook output...\n");
11614     generateDocbook();
11615     g_s.end();
11616   }
11617
11618   if (Config_getBool(GENERATE_AUTOGEN_DEF))
11619   {
11620     g_s.begin("Generating AutoGen DEF output...\n");
11621     generateDEF();
11622     g_s.end();
11623   }
11624   if (Config_getBool(GENERATE_PERLMOD))
11625   {
11626     g_s.begin("Generating Perl module output...\n");
11627     generatePerlMod();
11628     g_s.end();
11629   }
11630   if (generateHtml && searchEngine && serverBasedSearch)
11631   {
11632     g_s.begin("Generating search index\n");
11633     if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
11634     {
11635       HtmlGenerator::writeSearchPage();
11636       Doxygen::searchIndex->write(Config_getString(HTML_OUTPUT)+"/search/search.idx");
11637     }
11638     else // write data for external search index
11639     {
11640       HtmlGenerator::writeExternalSearchPage();
11641       QCString searchDataFile = Config_getString(SEARCHDATA_FILE);
11642       if (searchDataFile.isEmpty())
11643       {
11644         searchDataFile="searchdata.xml";
11645       }
11646       if (!portable_isAbsolutePath(searchDataFile))
11647       {
11648         searchDataFile.prepend(Config_getString(OUTPUT_DIRECTORY)+"/");
11649       }
11650       Doxygen::searchIndex->write(searchDataFile);
11651     }
11652     g_s.end();
11653   }
11654
11655   if (g_useOutputTemplate) generateOutputViaTemplate();
11656
11657   if (generateRtf)
11658   {
11659     g_s.begin("Combining RTF output...\n");
11660     if (!RTFGenerator::preProcessFileInplace(Config_getString(RTF_OUTPUT),"refman.rtf"))
11661     {
11662       err("An error occurred during post-processing the RTF files!\n");
11663     }
11664     g_s.end();
11665   }
11666
11667   if (Config_getBool(HAVE_DOT))
11668   {
11669     g_s.begin("Running dot...\n");
11670     DotManager::instance()->run();
11671     g_s.end();
11672   }
11673
11674   // copy static stuff
11675   if (generateHtml)
11676   {
11677     FTVHelp::generateTreeViewImages();
11678     copyStyleSheet();
11679     copyLogo(Config_getString(HTML_OUTPUT));
11680     copyExtraFiles(Config_getList(HTML_EXTRA_FILES),"HTML_EXTRA_FILES",Config_getString(HTML_OUTPUT));
11681   }
11682   if (generateLatex)
11683   {
11684     copyLatexStyleSheet();
11685     copyLogo(Config_getString(LATEX_OUTPUT));
11686     copyExtraFiles(Config_getList(LATEX_EXTRA_FILES),"LATEX_EXTRA_FILES",Config_getString(LATEX_OUTPUT));
11687   }
11688   if (generateRtf)
11689   {
11690     copyLogo(Config_getString(RTF_OUTPUT));
11691   }
11692
11693   if (generateHtml &&
11694       Config_getBool(GENERATE_HTMLHELP) &&
11695       !Config_getString(HHC_LOCATION).isEmpty())
11696   {
11697     g_s.begin("Running html help compiler...\n");
11698     QString oldDir = QDir::currentDirPath();
11699     QDir::setCurrent(Config_getString(HTML_OUTPUT));
11700     portable_sysTimerStart();
11701     if (portable_system(Config_getString(HHC_LOCATION), "index.hhp", Debug::isFlagSet(Debug::ExtCmd))!=1)
11702     {
11703       err("failed to run html help compiler on index.hhp\n");
11704     }
11705     portable_sysTimerStop();
11706     QDir::setCurrent(oldDir);
11707     g_s.end();
11708   }
11709   if ( generateHtml &&
11710        Config_getBool(GENERATE_QHP) &&
11711       !Config_getString(QHG_LOCATION).isEmpty())
11712   {
11713     g_s.begin("Running qhelpgenerator...\n");
11714     QCString const qhpFileName = Qhp::getQhpFileName();
11715     QCString const qchFileName = getQchFileName();
11716
11717     QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
11718     QString const oldDir = QDir::currentDirPath();
11719     QDir::setCurrent(Config_getString(HTML_OUTPUT));
11720     portable_sysTimerStart();
11721     if (portable_system(Config_getString(QHG_LOCATION), args.data(), FALSE))
11722     {
11723       err("failed to run qhelpgenerator on index.qhp\n");
11724     }
11725     portable_sysTimerStop();
11726     QDir::setCurrent(oldDir);
11727     g_s.end();
11728   }
11729
11730   int cacheParam;
11731   msg("lookup cache used %d/%d hits=%d misses=%d\n",
11732       Doxygen::lookupCache->count(),
11733       Doxygen::lookupCache->size(),
11734       Doxygen::lookupCache->hits(),
11735       Doxygen::lookupCache->misses());
11736   cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
11737   if (cacheParam>Config_getInt(LOOKUP_CACHE_SIZE))
11738   {
11739     msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
11740   }
11741
11742   if (Debug::isFlagSet(Debug::Time))
11743   {
11744     msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
11745          ((double)Doxygen::runningTime.elapsed())/1000.0,
11746          portable_getSysElapsedTime()
11747         );
11748     g_s.print();
11749   }
11750   else
11751   {
11752     msg("finished...\n");
11753   }
11754
11755
11756   /**************************************************************************
11757    *                        Start cleaning up                               *
11758    **************************************************************************/
11759
11760   cleanUpDoxygen();
11761
11762   finializeSearchIndexer();
11763   Doxygen::symbolStorage->close();
11764   QDir thisDir;
11765   thisDir.remove(Doxygen::objDBFileName);
11766   Config::deinit();
11767   QTextCodec::deleteAllCodecs();
11768   delete Doxygen::symbolMap;
11769   delete Doxygen::clangUsrMap;
11770   delete Doxygen::symbolStorage;
11771   g_successfulRun=TRUE;
11772 }
11773