1 /******************************************************************************
3 * Copyright (C) 1997-2014 by Dimitri van Heesch.
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.
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
18 #include <qfileinfo.h>
27 #include <qtextcodec.h>
31 #include <qtextstream.h>
43 #include "tagreader.h"
46 #include "docparser.h"
48 #include "outputlist.h"
60 #include "sqlite3gen.h"
62 #include "docbookgen.h"
64 #include "perlmodgen.h"
68 #include "commentcnv.h"
69 #include "cmdmapper.h"
70 #include "searchindex.h"
71 #include "parserintf.h"
73 #include "pyscanner.h"
74 #include "fortranscanner.h"
75 #include "dbusxmlscanner.h"
76 #include "tclscanner.h"
82 #include "vhdljjparser.h"
83 #include "vhdldocgen.h"
84 #include "eclipsehelp.h"
86 #include "filestorage.h"
88 #include "arguments.h"
89 #include "memberlist.h"
92 #include "classlist.h"
93 #include "namespacedef.h"
95 #include "membername.h"
96 #include "membergroup.h"
101 #include "fileparser.h"
103 #define RECURSE_ENTRYTREE(func,var) \
104 do { if (var->children()) { \
105 EntryNavListIterator eli(*var->children()); \
106 for (;eli.current();++eli) func(eli.current()); \
110 #if !defined(_WIN32) || defined(__CYGWIN__)
115 // globally accessible variables
116 ClassSDict *Doxygen::classSDict = 0;
117 ClassSDict *Doxygen::hiddenClasses = 0;
118 NamespaceSDict *Doxygen::namespaceSDict = 0;
119 MemberNameSDict *Doxygen::memberNameSDict = 0;
120 MemberNameSDict *Doxygen::functionNameSDict = 0;
121 FileNameList *Doxygen::inputNameList = 0; // all input files
122 FileNameDict *Doxygen::inputNameDict = 0;
123 GroupSDict *Doxygen::groupSDict = 0;
124 FormulaList *Doxygen::formulaList = 0; // all formulas
125 FormulaDict *Doxygen::formulaDict = 0; // all formulas
126 FormulaDict *Doxygen::formulaNameDict = 0; // the label name of all formulas
127 PageSDict *Doxygen::pageSDict = 0;
128 PageSDict *Doxygen::exampleSDict = 0;
129 SectionDict *Doxygen::sectionDict = 0; // all page sections
130 CiteDict *Doxygen::citeDict=0; // database of bibliographic references
131 StringDict Doxygen::aliasDict(257); // aliases
132 QDict<void> Doxygen::inputPaths(1009);
133 FileNameDict *Doxygen::includeNameDict = 0; // include names
134 FileNameDict *Doxygen::exampleNameDict = 0; // examples
135 FileNameDict *Doxygen::imageNameDict = 0; // images
136 FileNameDict *Doxygen::dotFileNameDict = 0; // dot files
137 FileNameDict *Doxygen::mscFileNameDict = 0; // msc files
138 FileNameDict *Doxygen::diaFileNameDict = 0; // dia files
139 StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases
140 StringDict Doxygen::tagDestinationDict(257); // all tag locations
141 QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
142 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
143 PageDef *Doxygen::mainPage = 0;
144 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
145 FTextStream Doxygen::tagFile;
146 NamespaceDef *Doxygen::globalScope = 0;
147 QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
148 bool Doxygen::parseSourcesNeeded = FALSE;
149 QTime Doxygen::runningTime;
150 SearchIndexIntf *Doxygen::searchIndex=0;
151 QDict<DefinitionIntf> *Doxygen::symbolMap = 0;
152 QDict<Definition> *Doxygen::clangUsrMap = 0;
153 bool Doxygen::outputToWizard=FALSE;
154 QDict<int> * Doxygen::htmlDirMap = 0;
155 QCache<LookupInfo> *Doxygen::lookupCache;
156 DirSDict *Doxygen::directories;
157 SDict<DirRelation> Doxygen::dirRelations(257);
158 ParserManager *Doxygen::parserManager = 0;
159 QCString Doxygen::htmlFileExtension;
160 bool Doxygen::suppressDocWarnings = FALSE;
161 Store *Doxygen::symbolStorage;
162 QCString Doxygen::objDBFileName;
163 QCString Doxygen::entryDBFileName;
164 bool Doxygen::gatherDefines = TRUE;
165 IndexList *Doxygen::indexList;
166 int Doxygen::subpageNestingLevel = 0;
167 bool Doxygen::userComments = FALSE;
168 QCString Doxygen::spaces;
169 bool Doxygen::generatingXmlOutput = FALSE;
170 bool Doxygen::markdownSupport = TRUE;
171 GenericsSDict *Doxygen::genericsDict;
173 // locally accessible globals
174 static QDict<EntryNav> g_classEntries(1009);
175 static StringList g_inputFiles;
176 static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds
177 static OutputList *g_outputList = 0; // list of output generating objects
178 static QDict<FileDef> g_usingDeclarations(1009); // used classes
179 static FileStorage *g_storage = 0;
180 static bool g_successfulRun = FALSE;
181 static bool g_dumpSymbolMap = FALSE;
182 static bool g_useOutputTemplate = FALSE;
186 g_inputFiles.clear();
187 //g_excludeNameDict.clear();
188 //delete g_outputList; g_outputList=0;
190 Doxygen::classSDict->clear();
191 Doxygen::namespaceSDict->clear();
192 Doxygen::pageSDict->clear();
193 Doxygen::exampleSDict->clear();
194 Doxygen::inputNameList->clear();
195 Doxygen::formulaList->clear();
196 Doxygen::sectionDict->clear();
197 Doxygen::inputNameDict->clear();
198 Doxygen::includeNameDict->clear();
199 Doxygen::exampleNameDict->clear();
200 Doxygen::imageNameDict->clear();
201 Doxygen::dotFileNameDict->clear();
202 Doxygen::mscFileNameDict->clear();
203 Doxygen::diaFileNameDict->clear();
204 Doxygen::formulaDict->clear();
205 Doxygen::formulaNameDict->clear();
206 Doxygen::tagDestinationDict.clear();
207 delete Doxygen::citeDict;
208 delete Doxygen::mainPage; Doxygen::mainPage=0;
214 Statistics() { stats.setAutoDelete(TRUE); }
215 void begin(const char *name)
218 stat *entry= new stat(name,0);
224 stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
229 if (Debug::isFlagSet(Debug::Time))
231 Debug::clearFlag("time");
234 msg("----------------------\n");
235 QListIterator<stat> sli(stats);
237 for ( sli.toFirst(); (s=sli.current()); ++sli )
239 msg("Spent %.3f seconds in %s",s->elapsed,s->name);
241 if (restore) Debug::setFlag("time");
248 stat() : name(NULL),elapsed(0) {}
249 stat(const char *n, double el) : name(n),elapsed(el) {}
258 fprintf(stderr,"--- inputNameDict stats ----\n");
259 Doxygen::inputNameDict->statistics();
260 fprintf(stderr,"--- includeNameDict stats ----\n");
261 Doxygen::includeNameDict->statistics();
262 fprintf(stderr,"--- exampleNameDict stats ----\n");
263 Doxygen::exampleNameDict->statistics();
264 fprintf(stderr,"--- imageNameDict stats ----\n");
265 Doxygen::imageNameDict->statistics();
266 fprintf(stderr,"--- dotFileNameDict stats ----\n");
267 Doxygen::dotFileNameDict->statistics();
268 fprintf(stderr,"--- mscFileNameDict stats ----\n");
269 Doxygen::mscFileNameDict->statistics();
270 fprintf(stderr,"--- diaFileNameDict stats ----\n");
271 Doxygen::diaFileNameDict->statistics();
272 //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
273 //g_excludeNameDict.statistics();
274 fprintf(stderr,"--- aliasDict stats ----\n");
275 Doxygen::aliasDict.statistics();
276 fprintf(stderr,"--- typedefDict stats ----\n");
277 fprintf(stderr,"--- namespaceAliasDict stats ----\n");
278 Doxygen::namespaceAliasDict.statistics();
279 fprintf(stderr,"--- formulaDict stats ----\n");
280 Doxygen::formulaDict->statistics();
281 fprintf(stderr,"--- formulaNameDict stats ----\n");
282 Doxygen::formulaNameDict->statistics();
283 fprintf(stderr,"--- tagDestinationDict stats ----\n");
284 Doxygen::tagDestinationDict.statistics();
285 fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
286 g_compoundKeywordDict.statistics();
287 fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
288 Doxygen::expandAsDefinedDict.statistics();
289 fprintf(stderr,"--- memGrpInfoDict stats ----\n");
290 Doxygen::memGrpInfoDict.statistics();
295 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
296 ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
297 static void findMember(EntryNav *rootNav,
303 enum FindBaseClassRelation_Mode
310 static bool findClassRelation(
315 QDict<int> *templateNames,
316 /*bool insertUndocumented*/
317 FindBaseClassRelation_Mode mode,
321 /** A struct contained the data for an STL class */
324 const char *className;
325 const char *baseClass1;
326 const char *baseClass2;
327 const char *templType1;
328 const char *templName1;
329 const char *templType2;
330 const char *templName2;
331 bool virtualInheritance;
335 static STLInfo g_stlinfo[] =
337 // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators
338 { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
339 { "array", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, // C++11
340 { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // deprecated
341 { "smart_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
342 { "unique_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
343 { "weak_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
344 { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
345 { "error_code", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
346 { "error_category", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
347 { "system_error", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
348 { "error_condition", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
349 { "thread", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
350 { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE },
351 { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
352 { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
353 { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE },
354 { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
355 { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
356 { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
357 { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
358 { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
359 { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
360 { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
361 { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
362 { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
363 { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
364 { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
365 { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
366 { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
367 { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
368 { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
369 { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
370 { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
371 { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
372 { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
373 { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
374 { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
375 { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
376 { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
377 { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
378 { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE },
379 { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE },
380 { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE },
381 { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
382 { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE },
383 { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
384 { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
385 { "forward_list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, // C++11
386 { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
387 { "unordered_map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
388 { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
389 { "unordered_multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
390 { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
391 { "unordered_set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
392 { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
393 { "unordered_multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
394 { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
395 { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
396 { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
397 { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
398 { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
399 { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
400 { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
401 { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
402 { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
403 { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
404 { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
405 { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
406 { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
407 { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
408 { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
409 { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
410 { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
411 { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
412 { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
413 { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
414 { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE }
417 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
419 Entry *memEntry = new Entry;
420 memEntry->name = name;
421 memEntry->type = type;
422 memEntry->protection = Public;
423 memEntry->section = Entry::VARIABLE_SEC;
424 memEntry->brief = "STL member";
425 memEntry->hidden = FALSE;
426 memEntry->artificial = TRUE;
427 //memEntry->parent = root;
428 //root->addSubEntry(memEntry);
429 EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
430 memEntryNav->setEntry(memEntry);
431 rootNav->addChild(memEntryNav);
434 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
436 Entry *iteratorClassEntry = new Entry;
437 iteratorClassEntry->fileName = "[STL]";
438 iteratorClassEntry->startLine = 1;
439 iteratorClassEntry->name = name;
440 iteratorClassEntry->section = Entry::CLASS_SEC;
441 iteratorClassEntry->brief = "STL iterator class";
442 iteratorClassEntry->hidden = FALSE;
443 iteratorClassEntry->artificial= TRUE;
444 EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
445 iteratorClassEntryNav->setEntry(iteratorClassEntry);
446 classEntryNav->addChild(iteratorClassEntryNav);
450 static void addSTLClasses(EntryNav *rootNav)
452 Entry *namespaceEntry = new Entry;
453 namespaceEntry->fileName = "[STL]";
454 namespaceEntry->startLine = 1;
455 //namespaceEntry->parent = rootNav->entry();
456 namespaceEntry->name = "std";
457 namespaceEntry->section = Entry::NAMESPACE_SEC;
458 namespaceEntry->brief = "STL namespace";
459 namespaceEntry->hidden = FALSE;
460 namespaceEntry->artificial= TRUE;
461 //root->addSubEntry(namespaceEntry);
462 EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
463 namespaceEntryNav->setEntry(namespaceEntry);
464 rootNav->addChild(namespaceEntryNav);
466 STLInfo *info = g_stlinfo;
467 while (info->className)
469 //printf("Adding STL class %s\n",info->className);
470 QCString fullName = info->className;
471 fullName.prepend("std::");
473 // add fake Entry for the class
474 Entry *classEntry = new Entry;
475 classEntry->fileName = "[STL]";
476 classEntry->startLine = 1;
477 classEntry->name = fullName;
478 //classEntry->parent = namespaceEntry;
479 classEntry->section = Entry::CLASS_SEC;
480 classEntry->brief = "STL class";
481 classEntry->hidden = FALSE;
482 classEntry->artificial= TRUE;
483 //namespaceEntry->addSubEntry(classEntry);
484 EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
485 classEntryNav->setEntry(classEntry);
486 namespaceEntryNav->addChild(classEntryNav);
488 // add template arguments to class
489 if (info->templType1)
491 ArgumentList *al = new ArgumentList;
492 Argument *a=new Argument;
494 a->name=info->templType1;
496 if (info->templType2) // another template argument
500 a->name=info->templType2;
503 classEntry->tArgLists = new QList<ArgumentList>;
504 classEntry->tArgLists->setAutoDelete(TRUE);
505 classEntry->tArgLists->append(al);
507 // add member variables
508 if (info->templName1)
510 addSTLMember(classEntryNav,info->templType1,info->templName1);
512 if (info->templName2)
514 addSTLMember(classEntryNav,info->templType2,info->templName2);
516 if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
517 fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
519 Entry *memEntry = new Entry;
520 memEntry->name = "operator->";
521 memEntry->args = "()";
522 memEntry->type = "T*";
523 memEntry->protection = Public;
524 memEntry->section = Entry::FUNCTION_SEC;
525 memEntry->brief = "STL member";
526 memEntry->hidden = FALSE;
527 memEntry->artificial = FALSE;
528 EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
529 memEntryNav->setEntry(memEntry);
530 classEntryNav->addChild(memEntryNav);
532 if (info->baseClass1)
534 classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
536 if (info->baseClass2)
538 classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
542 // add iterator class
543 addSTLIterator(classEntryNav,fullName+"::iterator");
544 addSTLIterator(classEntryNav,fullName+"::const_iterator");
545 addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
546 addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
552 //----------------------------------------------------------------------------
554 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
555 FileDef *fileScope,TagInfo *tagInfo);
557 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
559 if (rootNav->parent()) // add the page to it's scope
561 QCString scope = rootNav->parent()->name();
562 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
564 scope=substitute(scope,".","::");
566 scope = stripAnonymousNamespaceScope(scope);
567 scope+="::"+pd->name();
568 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
576 static void addRelatedPage(EntryNav *rootNav)
578 Entry *root = rootNav->entry();
580 QListIterator<Grouping> gli(*root->groups);
582 for (;(g=gli.current());++gli)
584 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
586 //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
588 if (root->brief.isEmpty())
590 doc=root->doc+root->inbodyDocs;
594 doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
596 PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
597 root->docFile,root->docLine,
599 gd,rootNav->tagInfo(),
604 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
605 pd->addSectionsToDefinition(root->anchors);
606 pd->setShowToc(root->stat);
607 addPageToContext(pd,rootNav);
611 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
613 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
614 ((!includeExternal && rootNav->tagInfo()==0) ||
615 ( includeExternal && rootNav->tagInfo()!=0))
618 rootNav->loadEntry(g_storage);
619 Entry *root = rootNav->entry();
621 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
622 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
624 GroupDef *gd = Doxygen::groupSDict->find(root->name);
625 //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
626 // root->type.data(),root->name.data(),additional,includeExternal,gd);
630 if ( !gd->hasGroupTitle() )
632 gd->setGroupTitle( root->type );
634 else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
636 warn( root->fileName,root->startLine,
637 "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
638 qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
640 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
641 gd->setDocumentation( root->doc, root->docFile, root->docLine );
642 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
643 gd->addSectionsToDefinition(root->anchors);
644 gd->setRefItems(root->sli);
645 gd->setLanguage(root->lang);
649 if (rootNav->tagInfo())
651 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
652 gd->setReference(rootNav->tagInfo()->tagName);
656 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
658 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
659 // allow empty docs for group
660 gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
661 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
662 gd->addSectionsToDefinition(root->anchors);
663 Doxygen::groupSDict->append(root->name,gd);
664 gd->setRefItems(root->sli);
665 gd->setLanguage(root->lang);
669 rootNav->releaseEntry();
671 if (rootNav->children())
673 EntryNavListIterator eli(*rootNav->children());
675 for (;(e=eli.current());++eli)
677 buildGroupListFiltered(e,additional,includeExternal);
682 static void buildGroupList(EntryNav *rootNav)
684 // --- first process only local groups
685 // first process the @defgroups blocks
686 buildGroupListFiltered(rootNav,FALSE,FALSE);
687 // then process the @addtogroup, @weakgroup blocks
688 buildGroupListFiltered(rootNav,TRUE,FALSE);
690 // --- then also process external groups
691 // first process the @defgroups blocks
692 buildGroupListFiltered(rootNav,FALSE,TRUE);
693 // then process the @addtogroup, @weakgroup blocks
694 buildGroupListFiltered(rootNav,TRUE,TRUE);
697 static void findGroupScope(EntryNav *rootNav)
699 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
700 rootNav->parent() && !rootNav->parent()->name().isEmpty())
703 if ((gd=Doxygen::groupSDict->find(rootNav->name())))
705 QCString scope = rootNav->parent()->name();
706 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
708 scope=substitute(scope,".","::");
710 scope = stripAnonymousNamespaceScope(scope);
711 scope+="::"+gd->name();
712 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
715 gd->setGroupScope(d);
719 RECURSE_ENTRYTREE(findGroupScope,rootNav);
722 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
724 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
726 rootNav->loadEntry(g_storage);
727 Entry *root = rootNav->entry();
729 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
730 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
733 if ((gd=Doxygen::groupSDict->find(root->name)))
735 //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
736 addGroupToGroups(root,gd);
740 rootNav->releaseEntry();
742 if (rootNav->children())
744 EntryNavListIterator eli(*rootNav->children());
746 for (;(e=eli.current());++eli)
748 organizeSubGroupsFiltered(e,additional);
753 static void organizeSubGroups(EntryNav *rootNav)
755 //printf("Defining groups\n");
756 // first process the @defgroups blocks
757 organizeSubGroupsFiltered(rootNav,FALSE);
758 //printf("Additional groups\n");
759 // then process the @addtogroup, @weakgroup blocks
760 organizeSubGroupsFiltered(rootNav,TRUE);
763 //----------------------------------------------------------------------
765 static void buildFileList(EntryNav *rootNav)
767 if (((rootNav->section()==Entry::FILEDOC_SEC) ||
768 ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
769 !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
772 rootNav->loadEntry(g_storage);
773 Entry *root = rootNav->entry();
776 FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
777 //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
781 if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
782 (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
785 root->fileName,root->startLine,
786 "file %s already documented. "
787 "Skipping documentation.",
794 //printf("Adding documentation!\n");
795 // using FALSE in setDocumentation is small hack to make sure a file
796 // is documented even if a \file command is used without further
798 fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
799 fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
800 fd->addSectionsToDefinition(root->anchors);
801 fd->setRefItems(root->sli);
802 QListIterator<Grouping> gli(*root->groups);
804 for (;(g=gli.current());++gli)
807 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
810 fd->makePartOfGroup(gd);
811 //printf("File %s: in group %s\n",fd->name().data(),s->data());
818 const char *fn = root->fileName.data();
820 text.sprintf("the name `%s' supplied as "
821 "the second argument in the \\file statement ",
823 if (ambig) // name is ambiguous
825 text+="matches the following input files:\n";
826 text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
827 text+="Please use a more specific name by "
828 "including a (larger) part of the path!";
830 else // name is not an input file
832 text+="is not an input file";
834 warn(fn,root->startLine,text);
837 rootNav->releaseEntry();
839 RECURSE_ENTRYTREE(buildFileList,rootNav);
842 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
845 (!root->doc.stripWhiteSpace().isEmpty() ||
846 !root->brief.stripWhiteSpace().isEmpty() ||
847 Config_getBool("EXTRACT_ALL")
848 ) && root->protection!=Private
851 //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
853 bool local=Config_getBool("FORCE_LOCAL_INCLUDES");
854 QCString includeFile = root->includeFile;
855 if (!includeFile.isEmpty() && includeFile.at(0)=='"')
858 includeFile=includeFile.mid(1,includeFile.length()-2);
860 else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
863 includeFile=includeFile.mid(1,includeFile.length()-2);
868 // see if we need to include a verbatim copy of the header file
869 //printf("root->includeFile=%s\n",root->includeFile.data());
870 if (!includeFile.isEmpty() &&
871 (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
873 { // explicit request
875 text.sprintf("the name `%s' supplied as "
876 "the argument of the \\class, \\struct, \\union, or \\include command ",
879 if (ambig) // name is ambiguous
881 text+="matches the following input files:\n";
882 text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
883 text+="Please use a more specific name by "
884 "including a (larger) part of the path!";
886 else // name is not an input file
888 text+="is not an input file";
890 warn(root->fileName,root->startLine,text);
892 else if (includeFile.isEmpty() && ifd &&
893 // see if the file extension makes sense
894 guessSection(ifd->name())==Entry::HEADER_SEC)
895 { // implicit assumption
899 // if a file is found, we mark it as a source file.
902 QCString iName = !root->includeName.isEmpty() ?
903 root->includeName : includeFile;
904 if (!iName.isEmpty()) // user specified include file
906 if (iName.at(0)=='<') local=FALSE; // explicit override
907 else if (iName.at(0)=='"') local=TRUE;
908 if (iName.at(0)=='"' || iName.at(0)=='<')
910 iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
917 else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty())
919 iName=stripFromIncludePath(fd->absFilePath());
921 else // use name of the file containing the class definition
925 if (fd->generateSourceFile()) // generate code for header
927 cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
929 else // put #include in the class documentation without link
931 cd->setIncludeFile(0,iName,local,TRUE);
938 static bool addNamespace(Entry *root,ClassDef *cd)
940 // see if this class is defined inside a namespace
941 if (root->section & Entry::COMPOUND_MASK)
943 Entry *e = root->parent;
946 if (e->section==Entry::NAMESPACE_SEC)
949 QCString nsName = stripAnonymousNamespaceScope(e->name);
950 //printf("addNameSpace() trying: %s\n",nsName.data());
951 if (!nsName.isEmpty() && nsName.at(0)!='@' &&
952 (nd=getResolvedNamespace(nsName))
955 cd->setNamespace(nd);
956 cd->setOuterScope(nd);
969 static Definition *findScope(Entry *root,int level=0)
971 if (root==0) return 0;
972 //printf("start findScope name=%s\n",root->name.data());
973 Definition *result=0;
974 if (root->section&Entry::SCOPE_MASK)
976 result = findScope(root->parent,level+1); // traverse to the root of the tree
979 //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
980 // TODO: look at template arguments
981 result = result->findInnerCompound(root->name);
983 else // reached the global scope
985 // TODO: look at template arguments
986 result = Doxygen::globalScope->findInnerCompound(root->name);
987 //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
990 //printf("end findScope(%s,%d)=%s\n",root->name.data(),
991 // level,result==0 ? "<none>" : result->name().data());
996 /*! returns the Definition object belonging to the first \a level levels of
997 * full qualified name \a name. Creates an artificial scope if the scope is
998 * not found and set the parent/child scope relation if the scope is found.
1000 static Definition *buildScopeFromQualifiedName(const QCString name,
1001 int level,SrcLangExt lang,TagInfo *tagInfo)
1003 //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
1006 Definition *prevScope=Doxygen::globalScope;
1010 int idx=getScopeFragment(name,p,&l);
1011 QCString nsName = name.mid(idx,l);
1012 if (nsName.isEmpty()) return prevScope;
1013 if (!fullScope.isEmpty()) fullScope+="::";
1015 NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
1016 Definition *innerScope = nd;
1018 if (nd==0) cd = getClass(fullScope);
1019 if (nd==0 && cd) // scope is a class
1023 else if (nd==0 && cd==0 && fullScope.find('<')==-1) // scope is not known and could be a namespace!
1025 // introduce bogus namespace
1026 //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
1027 nd=new NamespaceDef(
1028 "[generated]",1,1,fullScope,
1029 tagInfo?tagInfo->tagName:QCString(),
1030 tagInfo?tagInfo->fileName:QCString());
1031 nd->setLanguage(lang);
1033 // add namespace to the list
1034 Doxygen::namespaceSDict->inSort(fullScope,nd);
1037 else // scope is a namespace
1040 // make the parent/child scope relation
1041 prevScope->addInnerCompound(innerScope);
1042 innerScope->setOuterScope(prevScope);
1043 // proceed to the next scope fragment
1045 prevScope=innerScope;
1051 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
1052 FileDef *fileScope,TagInfo *tagInfo)
1054 //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
1055 Definition *resultScope=startScope;
1056 if (resultScope==0) resultScope=Doxygen::globalScope;
1057 QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
1059 i1=getScopeFragment(scope,0,&l1);
1062 //printf(">no fragments!\n");
1065 int p=i1+l1,l2=0,i2;
1066 while ((i2=getScopeFragment(scope,p,&l2))!=-1)
1068 QCString nestedNameSpecifier = scope.mid(i1,l1);
1069 Definition *orgScope = resultScope;
1070 //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
1071 resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
1072 //printf(" resultScope=%p\n",resultScope);
1075 NamespaceSDict *usedNamespaces;
1076 if (orgScope==Doxygen::globalScope && fileScope &&
1077 (usedNamespaces = fileScope->getUsedNamespaces()))
1078 // also search for used namespaces
1080 NamespaceSDict::Iterator ni(*usedNamespaces);
1082 for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
1084 // restart search within the used namespace
1085 resultScope = findScopeFromQualifiedName(nd,n,fileScope,tagInfo);
1089 // for a nested class A::I in used namespace N, we get
1090 // N::A::I while looking for A, so we should compare
1091 // resultScope->name() against scope.left(i2+l2)
1092 //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1093 if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1101 // also search for used classes. Complication: we haven't been able
1102 // to put them in the right scope yet, because we are still resolving
1103 // the scope relations!
1104 // Therefore loop through all used classes and see if there is a right
1105 // scope match between the used class and nestedNameSpecifier.
1106 QDictIterator<FileDef> ui(g_usingDeclarations);
1108 for (ui.toFirst();(usedFd=ui.current());++ui)
1110 //printf("Checking using class %s\n",ui.currentKey());
1111 if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1113 // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1114 // so use this instead.
1115 QCString fqn = QCString(ui.currentKey())+
1116 scope.right(scope.length()-p);
1117 resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),
1118 startScope->getLanguage(),0);
1119 //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1122 //printf("> Match! resultScope=%s\n",resultScope->name().data());
1128 //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1136 //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1140 ArgumentList *getTemplateArgumentsFromName(
1141 const QCString &name,
1142 const QList<ArgumentList> *tArgLists)
1144 if (tArgLists==0) return 0;
1146 QListIterator<ArgumentList> ali(*tArgLists);
1147 // for each scope fragment, check if it is a template and advance through
1150 while ((i=name.find("::",p))!=-1)
1152 NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1155 ClassDef *cd = getClass(name.left(i));
1158 if (cd->templateArguments())
1166 return ali.current();
1170 ClassDef::CompoundType convertToCompoundType(int section,uint64 specifier)
1172 ClassDef::CompoundType sec=ClassDef::Class;
1173 if (specifier&Entry::Struct)
1174 sec=ClassDef::Struct;
1175 else if (specifier&Entry::Union)
1176 sec=ClassDef::Union;
1177 else if (specifier&Entry::Category)
1178 sec=ClassDef::Category;
1179 else if (specifier&Entry::Interface)
1180 sec=ClassDef::Interface;
1181 else if (specifier&Entry::Protocol)
1182 sec=ClassDef::Protocol;
1183 else if (specifier&Entry::Exception)
1184 sec=ClassDef::Exception;
1185 else if (specifier&Entry::Service)
1186 sec=ClassDef::Service;
1187 else if (specifier&Entry::Singleton)
1188 sec=ClassDef::Singleton;
1192 //case Entry::UNION_SEC:
1193 case Entry::UNIONDOC_SEC:
1194 sec=ClassDef::Union;
1196 //case Entry::STRUCT_SEC:
1197 case Entry::STRUCTDOC_SEC:
1198 sec=ClassDef::Struct;
1200 //case Entry::INTERFACE_SEC:
1201 case Entry::INTERFACEDOC_SEC:
1202 sec=ClassDef::Interface;
1204 //case Entry::PROTOCOL_SEC:
1205 case Entry::PROTOCOLDOC_SEC:
1206 sec=ClassDef::Protocol;
1208 //case Entry::CATEGORY_SEC:
1209 case Entry::CATEGORYDOC_SEC:
1210 sec=ClassDef::Category;
1212 //case Entry::EXCEPTION_SEC:
1213 case Entry::EXCEPTIONDOC_SEC:
1214 sec=ClassDef::Exception;
1216 case Entry::SERVICEDOC_SEC:
1217 sec=ClassDef::Service;
1219 case Entry::SINGLETONDOC_SEC:
1220 sec=ClassDef::Singleton;
1227 static void addClassToContext(EntryNav *rootNav)
1229 //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1230 rootNav->loadEntry(g_storage);
1231 Entry *root = rootNav->entry();
1233 //NamespaceDef *nd = 0;
1234 FileDef *fd = rootNav->fileDef();
1237 if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1239 scName=rootNav->parent()->name();
1241 // name without parent's scope
1242 QCString fullName = root->name;
1244 // strip off any template parameters (but not those for specializations)
1245 fullName=stripTemplateSpecifiersFromScope(fullName);
1247 // name with scope (if not present already)
1248 QCString qualifiedName = fullName;
1249 if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1251 qualifiedName.prepend(scName+"::");
1254 // see if we already found the class before
1255 ClassDef *cd = getClass(qualifiedName);
1257 Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1258 cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);
1262 fullName=cd->name();
1263 Debug::print(Debug::Classes,0," Existing class %s!\n",cd->name().data());
1264 //if (cd->templateArguments()==0)
1266 // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1267 // cd->setTemplateArguments(tArgList);
1270 cd->setDocumentation(root->doc,root->docFile,root->docLine);
1271 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1273 if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1275 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1278 //cd->setName(fullName); // change name to match docs
1280 if (cd->templateArguments()==0 || (cd->isForwardDeclared() && (root->spec&Entry::ForwardDecl)==0))
1282 // this happens if a template class declared with @class is found
1283 // before the actual definition or if a forward declaration has different template
1285 ArgumentList *tArgList =
1286 getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1287 cd->setTemplateArguments(tArgList);
1290 cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1294 ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1297 QCString namespaceName;
1298 extractNamespaceName(fullName,className,namespaceName);
1300 //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1301 // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1304 QCString refFileName;
1305 TagInfo *tagInfo = rootNav->tagInfo();
1308 tagName = tagInfo->tagName;
1309 refFileName = tagInfo->fileName;
1311 if ((i=fullName.find("::"))!=-1)
1312 // symbols imported via tag files may come without the parent scope,
1313 // so we artificially create it here
1315 buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1318 cd=new ClassDef(root->fileName,root->startLine,root->startColumn,
1319 fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1320 Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1321 fullName.data(),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
1322 cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1323 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1324 cd->setLanguage(root->lang);
1325 cd->setId(root->id);
1326 cd->setHidden(root->hidden);
1327 cd->setArtificial(root->artificial);
1328 cd->setClassSpecifier(root->spec);
1329 cd->setTypeConstraints(root->typeConstr);
1330 //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1332 ArgumentList *tArgList =
1333 getTemplateArgumentsFromName(fullName,root->tArgLists);
1334 //printf("class %s template args=%s\n",fullName.data(),
1335 // tArgList ? tempArgListToString(tArgList).data() : "<none>");
1336 cd->setTemplateArguments(tArgList);
1337 cd->setProtection(root->protection);
1338 cd->setIsStatic(root->stat);
1340 // file definition containing the class cd
1341 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1344 // see if the class is found inside a namespace
1345 //bool found=addNamespace(root,cd);
1347 cd->insertUsedFile(fd);
1349 // add class to the list
1350 //printf("ClassDict.insert(%s)\n",fullName.data());
1351 Doxygen::classSDict->append(fullName,cd);
1353 if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1355 //printf("inserting generic '%s' cd=%p\n",fullName.data(),cd);
1356 Doxygen::genericsDict->insert(fullName,cd);
1360 cd->addSectionsToDefinition(root->anchors);
1361 if (!root->subGrouping) cd->setSubGrouping(FALSE);
1362 if (cd->hasDocumentation())
1364 addIncludeFile(cd,fd,root);
1366 if (fd && (root->section & Entry::COMPOUND_MASK))
1368 //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1369 // cd->name().data(),
1370 // fd->name().data(),
1371 // root->fileName.data()
1374 fd->insertClass(cd);
1376 addClassToGroups(root,cd);
1377 cd->setRefItems(root->sli);
1379 rootNav->releaseEntry();
1382 //----------------------------------------------------------------------
1383 // build a list of all classes mentioned in the documentation
1384 // and all classes that have a documentation block before their definition.
1385 static void buildClassList(EntryNav *rootNav)
1388 ((rootNav->section() & Entry::COMPOUND_MASK) ||
1389 rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1392 addClassToContext(rootNav);
1394 RECURSE_ENTRYTREE(buildClassList,rootNav);
1397 static void buildClassDocList(EntryNav *rootNav)
1400 (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1403 addClassToContext(rootNav);
1405 RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1408 static void resolveClassNestingRelations()
1410 ClassSDict::Iterator cli(*Doxygen::classSDict);
1411 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1420 for (cli.toFirst();(cd=cli.current());++cli)
1424 QCString name = stripAnonymousNamespaceScope(cd->name());
1425 //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1426 // also add class to the correct structural context
1427 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1428 name,cd->getFileDef(),0);
1431 //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1432 d->addInnerCompound(cd);
1433 cd->setOuterScope(d);
1439 // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1445 //give warnings for unresolved compounds
1447 for (cli.toFirst();(cd=cli.current());++cli)
1451 QCString name = stripAnonymousNamespaceScope(cd->name());
1452 //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1453 /// create the scope artificially
1454 // anyway, so we can at least relate scopes properly.
1455 Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1456 if (d!=cd && !cd->getDefFileName().isEmpty())
1457 // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1458 // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1459 // also avoid warning for stuff imported via a tagfile.
1461 d->addInnerCompound(cd);
1462 cd->setOuterScope(d);
1463 warn(cd->getDefFileName(),cd->getDefLine(),
1464 "Internal inconsistency: scope for class %s not "
1465 "found!",name.data()
1472 void distributeClassGroupRelations()
1474 //static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES");
1475 //if (!inlineGroupedClasses) return;
1476 //printf("** distributeClassGroupRelations()\n");
1478 ClassSDict::Iterator cli(*Doxygen::classSDict);
1479 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1482 for (cli.toFirst();(cd=cli.current());++cli)
1484 //printf("Checking %s\n",cd->name().data());
1485 // distribute the group to nested classes as well
1486 if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1488 //printf(" Candidate for merging\n");
1489 ClassSDict::Iterator ncli(*cd->getClassSDict());
1491 GroupDef *gd = cd->partOfGroups()->at(0);
1492 for (ncli.toFirst();(ncd=ncli.current());++ncli)
1494 if (ncd->partOfGroups()==0)
1496 //printf(" Adding %s to group '%s'\n",ncd->name().data(),
1497 // gd->groupTitle());
1498 ncd->makePartOfGroup(gd);
1502 cd->visited=TRUE; // only visit every class once
1507 //----------------------------
1509 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1511 QCString fullName = removeAnonymousScopes(templ->name());
1512 if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1513 fullName+="."+fieldName;
1514 ClassDef *cd = new ClassDef(templ->getDefFileName(),
1515 templ->getDefLine(),
1516 templ->getDefColumn(),
1518 templ->compoundType());
1519 cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1520 cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1521 cd->setLanguage(templ->getLanguage());
1522 cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1523 cd->setBodyDef(templ->getBodyDef());
1525 cd->setOuterScope(rootCd->getOuterScope());
1526 if (rootCd->getOuterScope()!=Doxygen::globalScope)
1528 rootCd->getOuterScope()->addInnerCompound(cd);
1531 FileDef *fd = templ->getFileDef();
1535 fd->insertClass(cd);
1537 GroupList *groups = rootCd->partOfGroups();
1540 GroupListIterator gli(*groups);
1542 for (gli.toFirst();(gd=gli.current());++gli)
1544 cd->makePartOfGroup(gd);
1548 //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1549 Doxygen::classSDict->append(fullName,cd);
1551 MemberList *ml = templ->getMemberList(MemberListType_pubAttribs);
1554 MemberListIterator li(*ml);
1556 for (li.toFirst();(md=li.current());++li)
1558 //printf(" Member %s type=%s\n",md->name().data(),md->typeString());
1559 MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1560 md->typeString(),md->name(),md->argsString(),md->excpString(),
1561 md->protection(),md->virtualness(),md->isStatic(),Member,
1564 imd->setMemberClass(cd);
1565 imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1566 imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1567 imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1568 imd->setMemberSpecifiers(md->getMemberSpecifiers());
1569 imd->setMemberGroupId(md->getMemberGroupId());
1570 imd->setInitializer(md->initializer());
1571 imd->setMaxInitLines(md->initializerLines());
1572 imd->setBitfields(md->bitfieldString());
1573 imd->setLanguage(md->getLanguage());
1574 cd->insertMember(imd);
1580 /** Look through the members of class \a cd and its public members.
1581 * If there is a member m of a tag less struct/union,
1582 * then we create a duplicate of the struct/union with the name of the
1583 * member to identify it.
1584 * So if cd has name S, then the tag less struct/union will get name S.m
1585 * Since tag less structs can be nested we need to call this function
1586 * recursively. Later on we need to patch the member types so we keep
1587 * track of the hierarchy of classes we create.
1589 static void processTagLessClasses(ClassDef *rootCd,
1591 ClassDef *tagParentCd,
1592 const QCString &prefix,int count)
1594 //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1595 //printf("checking members for %s\n",cd->name().data());
1596 if (cd->getClassSDict())
1598 MemberList *ml = cd->getMemberList(MemberListType_pubAttribs);
1601 MemberListIterator li(*ml);
1603 for (li.toFirst();(md=li.current());++li)
1605 QCString type = md->typeString();
1606 if (type.find("::@")!=-1) // member of tag less struct/union
1608 ClassSDict::Iterator it(*cd->getClassSDict());
1610 for (it.toFirst();(icd=it.current());++it)
1612 //printf(" member %s: type='%s'\n",md->name().data(),type.data());
1613 //printf(" comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1614 if (type.find(icd->name())!=-1) // matching tag less struct/union
1616 QCString name = md->name();
1617 if (name.at(0)=='@') name = "__unnamed__";
1618 if (!prefix.isEmpty()) name.prepend(prefix+".");
1619 //printf(" found %s for class %s\n",name.data(),cd->name().data());
1620 ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1621 processTagLessClasses(rootCd,icd,ncd,name,count+1);
1622 //printf(" addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1623 tagParentCd->addTaggedInnerClass(ncd);
1624 ncd->setTagLessReference(icd);
1626 // replace tag-less type for generated/original member
1627 // by newly created class name.
1628 // note the difference between changing cd and tagParentCd.
1629 // for the initial call this is the same pointer, but for
1630 // recursive calls cd is the original tag-less struct (of which
1631 // there is only one instance) and tagParentCd is the newly
1632 // generated tagged struct of which there can be multiple instances!
1633 MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1636 MemberListIterator pli(*pml);
1638 for (pli.toFirst();(pmd=pli.current());++pli)
1640 if (pmd->name()==md->name())
1642 pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1643 //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1655 static void writeMainPageTagFileData()
1657 if (Doxygen::mainPage && !Config_getString("GENERATE_TAGFILE").isEmpty())
1659 Doxygen::tagFile << " <compound kind=\"page\">" << endl
1661 << convertToXML(Doxygen::mainPage->name())
1662 << "</name>" << endl
1664 << convertToXML(Doxygen::mainPage->title())
1665 << "</title>" << endl
1667 << convertToXML(Doxygen::mainPage->getOutputFileBase())
1668 << "</filename>" << endl;
1670 Doxygen::mainPage->writeDocAnchorsToTagFile();
1671 Doxygen::tagFile << " </compound>" << endl;
1675 static void findTagLessClasses(ClassDef *cd)
1677 if (cd->getClassSDict())
1679 ClassSDict::Iterator it(*cd->getClassSDict());
1681 for (it.toFirst();(icd=it.current());++it)
1683 if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1685 findTagLessClasses(icd);
1690 processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1693 static void findTagLessClasses()
1695 ClassSDict::Iterator cli(*Doxygen::classSDict);
1697 for (cli.toFirst();(cd=cli.current());++cli) // for each class
1699 Definition *scope = cd->getOuterScope();
1700 if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1702 findTagLessClasses(cd);
1708 //----------------------------------------------------------------------
1709 // build a list of all namespaces mentioned in the documentation
1710 // and all namespaces that have a documentation block before their definition.
1711 static void buildNamespaceList(EntryNav *rootNav)
1714 (rootNav->section()==Entry::NAMESPACE_SEC ||
1715 rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1716 rootNav->section()==Entry::PACKAGEDOC_SEC
1718 !rootNav->name().isEmpty()
1721 rootNav->loadEntry(g_storage);
1722 Entry *root = rootNav->entry();
1724 //printf("** buildNamespaceList(%s)\n",root->name.data());
1726 QCString fName = root->name;
1727 if (root->section==Entry::PACKAGEDOC_SEC)
1729 fName=substitute(fName,".","::");
1732 QCString fullName = stripAnonymousNamespaceScope(fName);
1733 if (!fullName.isEmpty())
1735 //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1736 // root->fileName.data(), root->startLine);
1738 if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1740 nd->setDocumentation(root->doc,root->docFile,root->docLine);
1741 nd->setName(fullName); // change name to match docs
1742 nd->addSectionsToDefinition(root->anchors);
1743 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1744 if (nd->getLanguage()==SrcLangExt_Unknown)
1746 nd->setLanguage(root->lang);
1749 // file definition containing the namespace nd
1750 FileDef *fd=rootNav->fileDef();
1751 // insert the namespace in the file definition
1752 if (fd) fd->insertNamespace(nd);
1753 addNamespaceToGroups(root,nd);
1754 nd->setRefItems(root->sli);
1756 else // fresh namespace
1759 QCString tagFileName;
1760 TagInfo *tagInfo = rootNav->tagInfo();
1763 tagName = tagInfo->tagName;
1764 tagFileName = tagInfo->fileName;
1766 //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1767 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,
1768 root->startColumn,fullName,tagName,tagFileName,
1769 root->type,root->spec&Entry::Published);
1770 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1771 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1772 nd->addSectionsToDefinition(root->anchors);
1773 nd->setHidden(root->hidden);
1774 nd->setArtificial(root->artificial);
1775 nd->setLanguage(root->lang);
1776 nd->setId(root->id);
1778 //printf("Adding namespace to group\n");
1779 addNamespaceToGroups(root,nd);
1780 nd->setRefItems(root->sli);
1782 // file definition containing the namespace nd
1783 FileDef *fd=rootNav->fileDef();
1784 // insert the namespace in the file definition
1785 if (fd) fd->insertNamespace(nd);
1787 // the empty string test is needed for extract all case
1788 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1789 nd->insertUsedFile(fd);
1790 nd->setBodySegment(root->bodyLine,root->endBodyLine);
1792 // add class to the list
1793 Doxygen::namespaceSDict->inSort(fullName,nd);
1795 // also add namespace to the correct structural context
1796 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName,0,tagInfo);
1797 //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1798 if (d==0) // we didn't find anything, create the scope artificially
1799 // anyway, so we can at least relate scopes properly.
1801 Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1802 d->addInnerCompound(nd);
1803 nd->setOuterScope(d);
1804 // TODO: Due to the order in which the tag file is written
1805 // a nested class can be found before its parent!
1809 d->addInnerCompound(nd);
1810 nd->setOuterScope(d);
1815 rootNav->releaseEntry();
1817 RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1820 //----------------------------------------------------------------------
1822 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1823 const QCString &name)
1825 NamespaceDef *usingNd =0;
1828 //printf("Found namespace dict %d\n",unl->count());
1829 NamespaceSDict::Iterator unli(*unl);
1831 for (unli.toFirst();(und=unli.current());++unli)
1833 QCString uScope=und->name()+"::";
1834 usingNd = getResolvedNamespace(uScope+name);
1835 //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1841 static void findUsingDirectives(EntryNav *rootNav)
1843 if (rootNav->section()==Entry::USINGDIR_SEC)
1845 rootNav->loadEntry(g_storage);
1846 Entry *root = rootNav->entry();
1848 //printf("Found using directive %s at line %d of %s\n",
1849 // root->name.data(),root->startLine,root->fileName.data());
1850 QCString name=substitute(root->name,".","::");
1851 if (name.right(2)=="::")
1853 name=name.left(name.length()-2);
1855 if (!name.isEmpty())
1857 NamespaceDef *usingNd = 0;
1858 NamespaceDef *nd = 0;
1859 FileDef *fd = rootNav->fileDef();
1862 // see if the using statement was found inside a namespace or inside
1863 // the global file scope.
1864 if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1865 (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1868 nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1869 if (!nsName.isEmpty())
1871 nd = getResolvedNamespace(nsName);
1875 // find the scope in which the `using' namespace is defined by prepending
1876 // the possible scopes in which the using statement was found, starting
1877 // with the most inner scope and going to the most outer scope (i.e.
1879 int scopeOffset = nsName.length();
1882 QCString scope=scopeOffset>0 ?
1883 nsName.left(scopeOffset)+"::" : QCString();
1884 usingNd = getResolvedNamespace(scope+name);
1885 //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1890 else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1894 } while (scopeOffset>=0 && usingNd==0);
1896 if (usingNd==0 && nd) // not found, try used namespaces in this scope
1897 // or in one of the parent namespace scopes
1899 NamespaceDef *pnd = nd;
1900 while (pnd && usingNd==0)
1902 // also try with one of the used namespaces found earlier
1903 usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1906 Definition *s = pnd->getOuterScope();
1907 if (s && s->definitionType()==Definition::TypeNamespace)
1909 pnd = (NamespaceDef*)s;
1917 if (usingNd==0 && fd) // still nothing, also try used namespace in the
1920 usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1923 //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1925 // add the namespace the correct scope
1928 //printf("using fd=%p nd=%p\n",fd,nd);
1931 //printf("Inside namespace %s\n",nd->name().data());
1932 nd->addUsingDirective(usingNd);
1936 //printf("Inside file %s\n",fd->name().data());
1937 fd->addUsingDirective(usingNd);
1940 else // unknown namespace, but add it anyway.
1942 //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1943 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1944 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1945 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1946 nd->addSectionsToDefinition(root->anchors);
1947 //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1948 nd->setHidden(root->hidden);
1949 nd->setArtificial(TRUE);
1950 nd->setLanguage(root->lang);
1951 nd->setId(root->id);
1953 QListIterator<Grouping> gli(*root->groups);
1955 for (;(g=gli.current());++gli)
1958 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1959 gd->addNamespace(nd);
1962 // insert the namespace in the file definition
1965 fd->insertNamespace(nd);
1966 fd->addUsingDirective(nd);
1969 // the empty string test is needed for extract all case
1970 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1971 nd->insertUsedFile(fd);
1972 // add class to the list
1973 Doxygen::namespaceSDict->inSort(name,nd);
1974 nd->setRefItems(root->sli);
1978 rootNav->releaseEntry();
1980 RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
1983 //----------------------------------------------------------------------
1985 static void buildListOfUsingDecls(EntryNav *rootNav)
1987 if (rootNav->section()==Entry::USINGDECL_SEC &&
1988 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1991 rootNav->loadEntry(g_storage);
1992 Entry *root = rootNav->entry();
1994 QCString name = substitute(root->name,".","::");
1996 if (g_usingDeclarations.find(name)==0)
1998 FileDef *fd = rootNav->fileDef();
2001 g_usingDeclarations.insert(name,fd);
2005 rootNav->releaseEntry();
2007 RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
2011 static void findUsingDeclarations(EntryNav *rootNav)
2013 if (rootNav->section()==Entry::USINGDECL_SEC &&
2014 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2017 rootNav->loadEntry(g_storage);
2018 Entry *root = rootNav->entry();
2020 //printf("Found using declaration %s at line %d of %s inside section %x\n",
2021 // root->name.data(),root->startLine,root->fileName.data(),
2022 // rootNav->parent()->section());
2023 if (!root->name.isEmpty())
2025 ClassDef *usingCd = 0;
2026 NamespaceDef *nd = 0;
2027 FileDef *fd = rootNav->fileDef();
2030 // see if the using statement was found inside a namespace or inside
2031 // the global file scope.
2032 if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
2034 scName=rootNav->parent()->name();
2035 if (!scName.isEmpty())
2037 nd = getResolvedNamespace(scName);
2041 // Assume the using statement was used to import a class.
2042 // Find the scope in which the `using' namespace is defined by prepending
2043 // the possible scopes in which the using statement was found, starting
2044 // with the most inner scope and going to the most outer scope (i.e.
2047 QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2048 usingCd = getClass(name);
2051 usingCd = Doxygen::hiddenClasses->find(name);
2054 //printf("%s -> %p\n",root->name.data(),usingCd);
2055 if (usingCd==0) // definition not in the input => add an artificial class
2057 Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
2058 name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
2059 usingCd = new ClassDef(
2063 Doxygen::hiddenClasses->append(root->name,usingCd);
2064 usingCd->setArtificial(TRUE);
2065 usingCd->setLanguage(root->lang);
2069 Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",
2070 usingCd->name().data(),nd?nd->name().data():fd->name().data());
2073 if (usingCd) // add the class to the correct scope
2077 //printf("Inside namespace %s\n",nd->name().data());
2078 nd->addUsingDeclaration(usingCd);
2082 //printf("Inside file %s\n",fd->name().data());
2083 fd->addUsingDeclaration(usingCd);
2088 rootNav->releaseEntry();
2090 RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
2093 //----------------------------------------------------------------------
2095 static void findUsingDeclImports(EntryNav *rootNav)
2097 if (rootNav->section()==Entry::USINGDECL_SEC &&
2098 (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
2101 //printf("Found using declaration %s at line %d of %s inside section %x\n",
2102 // root->name.data(),root->startLine,root->fileName.data(),
2103 // root->parent->section);
2104 QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
2105 fullName=stripAnonymousNamespaceScope(fullName);
2106 fullName=stripTemplateSpecifiersFromScope(fullName);
2107 ClassDef *cd = getClass(fullName);
2110 //printf("found class %s\n",cd->name().data());
2111 int i=rootNav->name().find("::");
2114 QCString scope=rootNav->name().left(i);
2115 QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
2116 ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2119 //printf("found class %s\n",bcd->name().data());
2120 MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2123 MemberNameInfo *mni = mndict->find(memName);
2126 MemberNameInfoIterator mnii(*mni);
2128 for ( ; (mi=mnii.current()) ; ++mnii )
2130 MemberDef *md = mi->memberDef;
2131 if (md && md->protection()!=Private)
2134 rootNav->loadEntry(g_storage);
2135 Entry *root = rootNav->entry();
2137 //printf("found member %s\n",mni->memberName());
2138 MemberDef *newMd = 0;
2140 ArgumentList *templAl = md->templateArguments();
2141 ArgumentList *al = md->templateArguments();
2142 newMd = new MemberDef(
2143 root->fileName,root->startLine,root->startColumn,
2144 md->typeString(),memName,md->argsString(),
2145 md->excpString(),root->protection,root->virt,
2146 md->isStatic(),Member,md->memberType(),
2150 newMd->setMemberClass(cd);
2151 cd->insertMember(newMd);
2152 if (!root->doc.isEmpty() || !root->brief.isEmpty())
2154 newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2155 newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2156 newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2160 newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2161 newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2162 newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2164 newMd->setDefinition(md->definition());
2165 newMd->enableCallGraph(root->callGraph);
2166 newMd->enableCallerGraph(root->callerGraph);
2167 newMd->setBitfields(md->bitfieldString());
2168 newMd->addSectionsToDefinition(root->anchors);
2169 newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2170 newMd->setBodyDef(md->getBodyDef());
2171 newMd->setInitializer(md->initializer());
2172 newMd->setMaxInitLines(md->initializerLines());
2173 newMd->setMemberGroupId(root->mGrpId);
2174 newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2175 newMd->setLanguage(root->lang);
2176 newMd->setId(root->id);
2178 rootNav->releaseEntry();
2188 RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2191 //----------------------------------------------------------------------
2193 static void findIncludedUsingDirectives()
2195 // first mark all files as not visited
2196 FileNameListIterator fnli(*Doxygen::inputNameList);
2198 for (fnli.toFirst();(fn=fnli.current());++fnli)
2200 FileNameIterator fni(*fn);
2202 for (;(fd=fni.current());++fni)
2207 // then recursively add using directives found in #include files
2208 // to files that have not been visited.
2209 for (fnli.toFirst();(fn=fnli.current());++fnli)
2211 FileNameIterator fni(*fn);
2213 for (fni.toFirst();(fd=fni.current());++fni)
2217 //printf("----- adding using directives for file %s\n",fd->name().data());
2218 fd->addIncludedUsingDirectives();
2224 //----------------------------------------------------------------------
2226 static MemberDef *addVariableToClass(
2230 const QCString &name,
2232 MemberDef *fromAnnMemb,
2234 Relationship related)
2236 Entry *root = rootNav->entry();
2238 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2239 QCString scopeSeparator="::";
2240 SrcLangExt lang = cd->getLanguage();
2241 if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2243 qualScope = substitute(qualScope,"::",".");
2246 Debug::print(Debug::Variables,0,
2247 " class variable:\n"
2248 " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2255 root->initializer.data()
2259 if (!root->type.isEmpty())
2261 if (related || mtype==MemberType_Friend || Config_getBool("HIDE_SCOPE_NAMES"))
2263 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2265 def="using "+name+" = "+root->type.mid(7);
2269 def=root->type+" "+name+root->args;
2274 if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2276 def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2280 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2286 if (Config_getBool("HIDE_SCOPE_NAMES"))
2288 def=name+root->args;
2292 def=qualScope+scopeSeparator+name+root->args;
2295 def.stripPrefix("static ");
2297 // see if the member is already found in the same scope
2298 // (this may be the case for a static member that is initialized
2299 // outside the class)
2300 MemberName *mn=Doxygen::memberNameSDict->find(name);
2303 MemberNameIterator mni(*mn);
2305 for (mni.toFirst();(md=mni.current());++mni)
2307 //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2308 // md->getClassDef(),cd,root->type.data(),md->typeString());
2309 if (md->getClassDef()==cd &&
2310 removeRedundantWhiteSpace(root->type)==md->typeString())
2311 // member already in the scope
2314 if (root->lang==SrcLangExt_ObjC &&
2315 root->mtype==Property &&
2316 md->memberType()==MemberType_Variable)
2317 { // Objective-C 2.0 property
2318 // turn variable into a property
2319 md->setProtection(root->protection);
2320 cd->reclassifyMember(md,MemberType_Property);
2322 addMemberDocs(rootNav,md,def,0,FALSE);
2323 //printf(" Member already found!\n");
2329 // new member variable, typedef or enum value
2330 MemberDef *md=new MemberDef(
2331 root->fileName,root->startLine,root->startColumn,
2332 root->type,name,root->args,root->exception,
2333 prot,Normal,root->stat,related,
2334 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2335 md->setTagInfo(rootNav->tagInfo());
2336 md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2337 //md->setDefFile(root->fileName);
2338 //md->setDefLine(root->startLine);
2339 md->setDocumentation(root->doc,root->docFile,root->docLine);
2340 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2341 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2342 md->setDefinition(def);
2343 md->setBitfields(root->bitfields);
2344 md->addSectionsToDefinition(root->anchors);
2345 md->setFromAnonymousScope(fromAnnScope);
2346 md->setFromAnonymousMember(fromAnnMemb);
2347 //md->setIndentDepth(indentDepth);
2348 md->setBodySegment(root->bodyLine,root->endBodyLine);
2349 md->setInitializer(root->initializer);
2350 md->setMaxInitLines(root->initLines);
2351 md->setMemberGroupId(root->mGrpId);
2352 md->setMemberSpecifiers(root->spec);
2353 md->setReadAccessor(root->read);
2354 md->setWriteAccessor(root->write);
2355 md->enableCallGraph(root->callGraph);
2356 md->enableCallerGraph(root->callerGraph);
2357 md->setHidden(root->hidden);
2358 md->setArtificial(root->artificial);
2359 md->setLanguage(root->lang);
2360 md->setId(root->id);
2361 addMemberToGroups(root,md);
2362 //if (root->mGrpId!=-1)
2364 // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2365 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
2367 md->setBodyDef(rootNav->fileDef());
2369 //printf(" Adding member=%s\n",md->name().data());
2370 // add the member to the global list
2375 else // new variable name
2377 mn = new MemberName(name);
2379 //printf("Adding memberName=%s\n",mn->memberName());
2380 //Doxygen::memberNameDict.insert(name,mn);
2381 //Doxygen::memberNameList.append(mn);
2382 Doxygen::memberNameSDict->append(name,mn);
2383 // add the member to the class
2385 //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd);
2386 cd->insertMember(md);
2387 md->setRefItems(root->sli);
2389 //TODO: insert FileDef instead of filename strings.
2390 cd->insertUsedFile(rootNav->fileDef());
2391 rootNav->changeSection(Entry::EMPTY_SEC);
2395 //----------------------------------------------------------------------
2397 static MemberDef *addVariableToFile(
2400 const QCString &scope,
2401 const QCString &name,
2403 /*int indentDepth,*/
2404 MemberDef *fromAnnMemb)
2406 Entry *root = rootNav->entry();
2407 Debug::print(Debug::Variables,0,
2408 " global variable:\n"
2409 " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2419 FileDef *fd = rootNav->fileDef();
2421 // see if we have a typedef that should hide a struct or union
2422 if (mtype==MemberType_Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))
2424 QCString type = root->type;
2425 type.stripPrefix("typedef ");
2426 if (type.left(7)=="struct " || type.left(6)=="union ")
2428 type.stripPrefix("struct ");
2429 type.stripPrefix("union ");
2430 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2432 s = re.match(type,0,&l);
2435 QCString typeValue = type.mid(s,l);
2436 ClassDef *cd = getClass(typeValue);
2439 // this typedef should hide compound name cd, so we
2440 // change the name that is displayed from cd.
2441 cd->setClassName(name);
2442 cd->setDocumentation(root->doc,root->docFile,root->docLine);
2443 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2450 // see if the function is inside a namespace
2451 NamespaceDef *nd = 0;
2453 if (!scope.isEmpty())
2455 if (scope.find('@')!=-1) return 0; // anonymous scope!
2456 //nscope=removeAnonymousScopes(scope);
2457 //if (!nscope.isEmpty())
2459 nd = getResolvedNamespace(scope);
2464 // determine the definition of the global variable
2465 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' &&
2466 !Config_getBool("HIDE_SCOPE_NAMES")
2468 // variable is inside a namespace, so put the scope before the name
2470 SrcLangExt lang = nd->getLanguage();
2471 QCString sep=getLanguageSpecificSeparator(lang);
2473 if (!root->type.isEmpty())
2475 if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2477 def="using "+nd->name()+sep+name+" = "+root->type;
2479 else // normal member
2481 def=root->type+" "+nd->name()+sep+name+root->args;
2486 def=nd->name()+sep+name+root->args;
2491 if (!root->type.isEmpty() && !root->name.isEmpty())
2493 if (name.at(0)=='@') // dummy variable representing anonymous union
2499 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2501 def="using "+root->name+" = "+root->type.mid(7);
2503 else // normal member
2505 def=root->type+" "+name+root->args;
2511 def=name+root->args;
2514 def.stripPrefix("static ");
2516 MemberName *mn=Doxygen::functionNameSDict->find(name);
2519 //QCString nscope=removeAnonymousScopes(scope);
2520 //NamespaceDef *nd=0;
2521 //if (!nscope.isEmpty())
2522 if (!scope.isEmpty())
2524 nd = getResolvedNamespace(scope);
2526 MemberNameIterator mni(*mn);
2528 for (mni.toFirst();(md=mni.current());++mni)
2531 ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2532 root->fileName==md->getFileDef()->absFilePath()
2533 ) // both variable names in the same file
2534 || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2536 && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2537 && !md->isEnumerate() // in C# an enum value and enum can have the same name
2539 // variable already in the scope
2541 bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2542 md->argsString()!=root->args &&
2543 root->args.find('[')!=-1;
2544 bool staticsInDifferentFiles =
2545 root->stat && md->isStatic() &&
2546 root->fileName!=md->getDefFileName();
2548 if (md->getFileDef() &&
2549 !isPHPArray && // not a php array
2550 !staticsInDifferentFiles
2552 // not a php array variable
2555 Debug::print(Debug::Variables,0,
2556 " variable already found: scope=%s\n",md->getOuterScope()->name().data());
2557 addMemberDocs(rootNav,md,def,0,FALSE);
2558 md->setRefItems(root->sli);
2564 Debug::print(Debug::Variables,0,
2565 " new variable, nd=%s!\n",nd?nd->name().data():"<global>");
2566 // new global variable, enum value or typedef
2567 MemberDef *md=new MemberDef(
2568 root->fileName,root->startLine,root->startColumn,
2569 root->type,name,root->args,0,
2570 Public, Normal,root->stat,Member,
2571 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2572 md->setTagInfo(rootNav->tagInfo());
2573 md->setMemberSpecifiers(root->spec);
2574 md->setDocumentation(root->doc,root->docFile,root->docLine);
2575 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2576 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2577 md->addSectionsToDefinition(root->anchors);
2578 md->setFromAnonymousScope(fromAnnScope);
2579 md->setFromAnonymousMember(fromAnnMemb);
2580 md->setInitializer(root->initializer);
2581 md->setMaxInitLines(root->initLines);
2582 md->setMemberGroupId(root->mGrpId);
2583 md->setDefinition(def);
2584 md->setLanguage(root->lang);
2585 md->setId(root->id);
2586 md->enableCallGraph(root->callGraph);
2587 md->enableCallerGraph(root->callerGraph);
2588 md->setExplicitExternal(root->explicitExternal);
2589 //md->setOuterScope(fd);
2590 if (!root->explicitExternal)
2592 md->setBodySegment(root->bodyLine,root->endBodyLine);
2595 addMemberToGroups(root,md);
2597 md->setRefItems(root->sli);
2598 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2600 md->setNamespace(nd);
2601 nd->insertMember(md);
2604 // add member to the file (we do this even if we have already inserted
2605 // it into the namespace.
2609 fd->insertMember(md);
2612 // add member definition to the list of globals
2619 mn = new MemberName(name);
2621 Doxygen::functionNameSDict->append(name,mn);
2623 rootNav->changeSection(Entry::EMPTY_SEC);
2627 /*! See if the return type string \a type is that of a function pointer
2628 * \returns -1 if this is not a function pointer variable or
2629 * the index at which the closing brace of (...*name) was found.
2631 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2633 if (lang == SrcLangExt_Fortran) return -1; // Fortran does not have function pointers
2634 static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2636 int bb=type.find('<');
2637 int be=type.findRev('>');
2638 if (!type.isEmpty() && // return type is non-empty
2639 (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2640 type.find("operator")==-1 && // not an operator
2641 (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2642 // not a function pointer return type
2643 !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2646 if (pLength) *pLength=l;
2647 //printf("findFunctionPtr=%d\n",i);
2652 //printf("findFunctionPtr=%d\n",-1);
2658 /*! Returns TRUE iff \a type is a class within scope \a context.
2659 * Used to detect variable declarations that look like function prototypes.
2661 static bool isVarWithConstructor(EntryNav *rootNav)
2663 static QRegExp initChars("[0-9\"'&*!^]+");
2664 static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2668 Definition *ctx = 0;
2672 //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2673 rootNav->loadEntry(g_storage);
2674 Entry *root = rootNav->entry();
2676 if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2681 else if ((fd = rootNav->fileDef()) &&
2682 (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2684 { // inside a .c file
2688 if (root->type.isEmpty())
2693 if (!rootNav->parent()->name().isEmpty())
2695 ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2698 // remove qualifiers
2699 findAndRemoveWord(type,"const");
2700 findAndRemoveWord(type,"static");
2701 findAndRemoveWord(type,"volatile");
2702 //if (type.left(6)=="const ") type=type.right(type.length()-6);
2703 typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2704 if (!typeIsClass && (ti=type.find('<'))!=-1)
2706 typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2708 if (typeIsClass) // now we still have to check if the arguments are
2709 // types or values. Since we do not have complete type info
2710 // we need to rely on heuristics :-(
2712 //printf("typeIsClass\n");
2713 ArgumentList *al = root->argList;
2714 if (al==0 || al->isEmpty())
2716 result=FALSE; // empty arg list -> function prototype.
2719 ArgumentListIterator ali(*al);
2721 for (ali.toFirst();(a=ali.current());++ali)
2723 if (!a->name.isEmpty() || !a->defval.isEmpty())
2725 if (a->name.find(initChars)==0)
2731 result=FALSE; // arg has (type,name) pair -> function prototype
2735 if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0)
2737 result=FALSE; // arg type is a known type
2740 if (checkIfTypedef(ctx,fd,a->type))
2742 //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2743 result=FALSE; // argument is a typedef
2746 if (a->type.at(a->type.length()-1)=='*' ||
2747 a->type.at(a->type.length()-1)=='&')
2748 // type ends with * or & => pointer or reference
2753 if (a->type.find(initChars)==0)
2755 result=TRUE; // argument type starts with typical initializer char
2758 QCString resType=resolveTypeDef(ctx,a->type);
2759 if (resType.isEmpty()) resType=a->type;
2761 if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2763 resType=resType.left(len);
2764 //printf("resType=%s\n",resType.data());
2765 if (resType=="int" || resType=="long" || resType=="float" ||
2766 resType=="double" || resType=="char" || resType=="signed" ||
2767 resType=="const" || resType=="unsigned" || resType=="void")
2769 result=FALSE; // type keyword -> function prototype
2778 //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2779 // root->type.data(),result);
2780 rootNav->releaseEntry();
2784 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2786 rootNav->loadEntry(g_storage);
2787 Entry *root = rootNav->entry();
2789 Debug::print(Debug::Variables,0,
2791 " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2797 root->relates.data()
2799 //printf("root->parent->name=%s\n",root->parent->name.data());
2801 if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2802 (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2804 // recover from parse error caused by redundant braces
2805 // like in "int *(var[10]);", which is parsed as
2806 // type="" name="int *" args="(var[10])"
2808 root->type=root->name;
2809 static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2811 int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2814 root->name=root->args.mid(i,l);
2815 root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2817 //printf("new: type=`%s' name=`%s' args=`%s'\n",
2818 // root->type.data(),root->name.data(),root->args.data());
2823 if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2824 Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no");
2825 if (i!=-1) // function pointer
2827 int ai = root->type.find('[',i);
2828 if (ai>i) // function pointer array
2830 root->args.prepend(root->type.right(root->type.length()-ai));
2831 root->type=root->type.left(ai);
2833 else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2835 root->type=root->type.left(root->type.length()-1);
2836 root->args.prepend(")");
2837 //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2840 else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
2842 root->type=root->type.left(root->type.length()-1);
2843 root->args.prepend(")");
2847 QCString scope,name=removeRedundantWhiteSpace(root->name);
2849 // find the scope of this variable
2850 EntryNav *p = rootNav->parent();
2851 while ((p->section() & Entry::SCOPE_MASK))
2853 QCString scopeName = p->name();
2854 if (!scopeName.isEmpty())
2856 scope.prepend(scopeName);
2863 QCString type=root->type.stripWhiteSpace();
2865 bool isRelated=FALSE;
2866 bool isMemberOf=FALSE;
2868 QCString classScope=stripAnonymousNamespaceScope(scope);
2869 classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2870 QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2872 if (root->name.findRev("::")!=-1)
2874 if (root->type=="friend class" || root->type=="friend struct" ||
2875 root->type=="friend union")
2880 addVariableToClass(rootNav, // entry
2881 cd, // class to add member to
2882 MemberType_Friend, // type of member
2883 name, // name of the member
2884 FALSE, // from Anonymous scope
2885 0, // anonymous member
2886 Public, // protection
2887 Member // related to a class
2892 /* skip this member, because it is a
2893 * static variable definition (always?), which will be
2894 * found in a class scope as well, but then we know the
2895 * correct protection level, so only then it will be
2896 * inserted in the correct list!
2901 mtype=MemberType_EnumValue;
2902 else if (type.left(8)=="typedef ")
2903 mtype=MemberType_Typedef;
2904 else if (type.left(7)=="friend ")
2905 mtype=MemberType_Friend;
2906 else if (root->mtype==Property)
2907 mtype=MemberType_Property;
2908 else if (root->mtype==Event)
2909 mtype=MemberType_Event;
2911 mtype=MemberType_Variable;
2913 if (!root->relates.isEmpty()) // related variable
2916 isMemberOf=(root->relatesType == MemberOf);
2917 if (getClass(root->relates)==0 && !scope.isEmpty())
2918 scope=mergeScopes(scope,root->relates);
2920 scope=root->relates;
2924 if (cd==0 && classScope!=scope) cd=getClass(classScope);
2929 // if cd is an anonymous (=tag less) scope we insert the member
2930 // into a non-anonymous parent scope as well. This is needed to
2931 // be able to refer to it using \var or \fn
2933 //int indentDepth=0;
2934 int si=scope.find('@');
2935 //int anonyScopes = 0;
2938 static bool inlineSimpleStructs = Config_getBool("INLINE_SIMPLE_STRUCTS");
2939 if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2943 pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2944 if (!pScope.isEmpty())
2945 pScope.prepend(annScopePrefix);
2946 else if (annScopePrefix.length()>2)
2947 pScope=annScopePrefix.left(annScopePrefix.length()-2);
2948 if (name.at(0)!='@')
2950 if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2952 md=addVariableToClass(rootNav, // entry
2953 pcd, // class to add member to
2954 mtype, // member type
2955 name, // member name
2956 TRUE, // from anonymous scope
2957 0, // from anonymous member
2959 isMemberOf ? Foreign : isRelated ? Related : Member
2963 else // anonymous scope inside namespace or file => put variable in the global scope
2965 if (mtype==MemberType_Variable)
2967 md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0);
2974 //printf("name=`%s' scope=%s scope.right=%s\n",
2975 // name.data(),scope.data(),
2976 // scope.right(scope.length()-si).data());
2977 addVariableToClass(rootNav, // entry
2978 cd, // class to add member to
2979 mtype, // member type
2980 name, // name of the member
2981 FALSE, // from anonymous scope
2982 md, // from anonymous member
2984 isMemberOf ? Foreign : isRelated ? Related : Member);
2986 else if (!name.isEmpty()) // global variable
2988 //printf("Inserting member in global scope %s!\n",scope.data());
2989 addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
2993 rootNav->releaseEntry();
2996 //----------------------------------------------------------------------
2997 // Searches the Entry tree for typedef documentation sections.
2998 // If found they are stored in their class or in the global list.
2999 static void buildTypedefList(EntryNav *rootNav)
3001 //printf("buildVarList(%s)\n",rootNav->name().data());
3002 if (!rootNav->name().isEmpty() &&
3003 rootNav->section()==Entry::VARIABLE_SEC &&
3004 rootNav->type().find("typedef ")!=-1 // its a typedef
3007 addVariable(rootNav);
3009 if (rootNav->children())
3011 EntryNavListIterator eli(*rootNav->children());
3013 for (;(e=eli.current());++eli)
3015 if (e->section()!=Entry::ENUM_SEC)
3017 buildTypedefList(e);
3023 //----------------------------------------------------------------------
3024 // Searches the Entry tree for Variable documentation sections.
3025 // If found they are stored in their class or in the global list.
3027 static void buildVarList(EntryNav *rootNav)
3029 //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
3031 if (!rootNav->name().isEmpty() &&
3032 (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
3034 (rootNav->section()==Entry::VARIABLE_SEC // it's a variable
3036 (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable
3037 (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
3039 (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
3040 isVarWithConstructor(rootNav)
3043 ) // documented variable
3045 addVariable(rootNav,isFuncPtr);
3047 if (rootNav->children())
3049 EntryNavListIterator eli(*rootNav->children());
3051 for (;(e=eli.current());++eli)
3053 if (e->section()!=Entry::ENUM_SEC)
3061 //----------------------------------------------------------------------
3062 // Searches the Entry tree for Interface sections (UNO IDL only).
3063 // If found they are stored in their service or in the global list.
3066 static void addInterfaceOrServiceToServiceOrSingleton(
3067 EntryNav *const rootNav,
3069 QCString const& rname)
3071 Entry *const root = rootNav->entry();
3072 FileDef *const fd = rootNav->fileDef();
3073 enum MemberType const type = (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC)
3074 ? MemberType_Interface
3075 : MemberType_Service;
3076 MemberDef *const md = new MemberDef(
3077 root->fileName, root->startLine, root->startColumn, root->type, rname,
3078 "", "", root->protection, root->virt, root->stat, Member,
3079 type, 0, root->argList);
3080 md->setTagInfo(rootNav->tagInfo());
3081 md->setMemberClass(cd);
3082 md->setDocumentation(root->doc,root->docFile,root->docLine);
3083 md->setDocsForDefinition(false);
3084 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3085 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3086 md->setBodySegment(root->bodyLine,root->endBodyLine);
3087 md->setMemberSpecifiers(root->spec);
3088 md->setMemberGroupId(root->mGrpId);
3089 md->setTypeConstraints(root->typeConstr);
3090 md->setLanguage(root->lang);
3093 md->addSectionsToDefinition(root->anchors);
3094 QCString const def = root->type + " " + rname;
3095 md->setDefinition(def);
3096 md->enableCallGraph(root->callGraph);
3097 md->enableCallerGraph(root->callerGraph);
3099 Debug::print(Debug::Functions,0,
3100 " Interface Member:\n"
3101 " `%s' `%s' proto=%d\n"
3109 // add member to the global list of all members
3111 if ((mn=Doxygen::memberNameSDict->find(rname)))
3117 mn = new MemberName(rname);
3119 Doxygen::memberNameSDict->append(rname,mn);
3122 // add member to the class cd
3123 cd->insertMember(md);
3124 // also add the member as a "base" (to get nicer diagrams)
3125 // "optional" interface/service get Protected which turns into dashed line
3126 BaseInfo base(rname,
3127 (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3128 findClassRelation(rootNav,cd,cd,&base,0,DocumentedOnly,true)
3129 || findClassRelation(rootNav,cd,cd,&base,0,Undocumented,true);
3130 // add file to list of used files
3131 cd->insertUsedFile(fd);
3133 addMemberToGroups(root,md);
3134 rootNav->changeSection(Entry::EMPTY_SEC);
3135 md->setRefItems(root->sli);
3138 static void buildInterfaceAndServiceList(EntryNav *const rootNav)
3140 if (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
3141 rootNav->section()==Entry::INCLUDED_SERVICE_SEC)
3143 rootNav->loadEntry(g_storage);
3144 Entry *const root = rootNav->entry();
3146 Debug::print(Debug::Functions,0,
3147 "EXPORTED_INTERFACE_SEC:\n"
3148 " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3150 rootNav->parent()->name().data(),
3153 root->relates.data(),
3155 root->fileName.data(),
3158 root->tArgLists ? (int)root->tArgLists->count() : -1,
3162 root->docFile.data()
3165 QCString const rname = removeRedundantWhiteSpace(root->name);
3167 if (!rname.isEmpty())
3169 QCString const scope = rootNav->parent()->name();
3170 ClassDef *const cd = getClass(scope);
3172 if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3173 (ClassDef::Service == cd->compoundType()) ||
3174 (ClassDef::Singleton == cd->compoundType())))
3176 addInterfaceOrServiceToServiceOrSingleton(rootNav,cd,rname);
3180 assert(false); // was checked by scanner.l
3183 else if (rname.isEmpty())
3185 warn(root->fileName,root->startLine,
3186 "Illegal member name found.");
3189 rootNav->releaseEntry();
3191 // can only have these in IDL anyway
3192 switch (rootNav->lang())
3194 case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3195 case SrcLangExt_IDL:
3196 RECURSE_ENTRYTREE(buildInterfaceAndServiceList,rootNav);
3199 return; // nothing to do here
3204 //----------------------------------------------------------------------
3205 // Searches the Entry tree for Function sections.
3206 // If found they are stored in their class or in the global list.
3208 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
3209 const QCString &rname,bool isFriend)
3211 Entry *root = rootNav->entry();
3212 FileDef *fd=rootNav->fileDef();
3215 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3216 int ts=root->type.find('<');
3217 int te=root->type.findRev('>');
3218 int i=re.match(root->type,0,&l);
3219 if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
3224 if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3225 !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3227 root->args+=root->type.right(root->type.length()-i-l);
3228 root->type=root->type.left(i+l);
3231 QCString name=removeRedundantWhiteSpace(rname);
3232 if (name.left(2)=="::") name=name.right(name.length()-2);
3235 if (isFriend) mtype=MemberType_Friend;
3236 else if (root->mtype==Signal) mtype=MemberType_Signal;
3237 else if (root->mtype==Slot) mtype=MemberType_Slot;
3238 else if (root->mtype==DCOP) mtype=MemberType_DCOP;
3239 else mtype=MemberType_Function;
3241 // strip redundant template specifier for constructors
3242 if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3243 name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3248 //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
3249 // root->name.data(),root->args.data(),argListToString(root->argList).data()
3252 // adding class member
3253 MemberDef *md=new MemberDef(
3254 root->fileName,root->startLine,root->startColumn,
3255 root->type,name,root->args,root->exception,
3256 root->protection,root->virt,
3257 root->stat && root->relatesType != MemberOf,
3258 root->relates.isEmpty() ? Member :
3259 root->relatesType == MemberOf ? Foreign : Related,
3260 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,root->argList);
3261 md->setTagInfo(rootNav->tagInfo());
3262 md->setMemberClass(cd);
3263 md->setDocumentation(root->doc,root->docFile,root->docLine);
3264 md->setDocsForDefinition(!root->proto);
3265 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3266 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3267 md->setBodySegment(root->bodyLine,root->endBodyLine);
3268 md->setMemberSpecifiers(root->spec);
3269 md->setMemberGroupId(root->mGrpId);
3270 md->setTypeConstraints(root->typeConstr);
3271 md->setLanguage(root->lang);
3272 md->setId(root->id);
3275 //md->setScopeTemplateArguments(root->tArgList);
3276 md->addSectionsToDefinition(root->anchors);
3278 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3279 SrcLangExt lang = cd->getLanguage();
3280 QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3281 if (scopeSeparator!="::")
3283 qualScope = substitute(qualScope,"::",scopeSeparator);
3285 if (lang==SrcLangExt_PHP)
3287 // for PHP we use Class::method and Namespace\method
3288 scopeSeparator="::";
3290 if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
3292 if (!root->type.isEmpty())
3296 def=root->type+" "+name;
3300 def=root->type+" "+name+root->args;
3311 def=name+root->args;
3317 if (!root->type.isEmpty())
3321 def=root->type+" "+qualScope+scopeSeparator+name;
3325 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3332 def=qualScope+scopeSeparator+name;
3336 def=qualScope+scopeSeparator+name+root->args;
3340 if (def.left(7)=="friend ") def=def.right(def.length()-7);
3341 md->setDefinition(def);
3342 md->enableCallGraph(root->callGraph);
3343 md->enableCallerGraph(root->callerGraph);
3345 Debug::print(Debug::Functions,0,
3347 " `%s' `%s'::`%s' `%s' proto=%d\n"
3357 // add member to the global list of all members
3358 //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3360 if ((mn=Doxygen::memberNameSDict->find(name)))
3366 mn = new MemberName(name);
3368 Doxygen::memberNameSDict->append(name,mn);
3371 // add member to the class cd
3372 cd->insertMember(md);
3373 // add file to list of used files
3374 cd->insertUsedFile(fd);
3376 addMemberToGroups(root,md);
3377 rootNav->changeSection(Entry::EMPTY_SEC);
3378 md->setRefItems(root->sli);
3382 static void buildFunctionList(EntryNav *rootNav)
3384 if (rootNav->section()==Entry::FUNCTION_SEC)
3386 rootNav->loadEntry(g_storage);
3387 Entry *root = rootNav->entry();
3389 Debug::print(Debug::Functions,0,
3391 " `%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",
3393 rootNav->parent()->name().data(),
3396 root->relates.data(),
3398 root->fileName.data(),
3401 root->tArgLists ? (int)root->tArgLists->count() : -1,
3405 root->docFile.data()
3408 bool isFriend=root->type.find("friend ")!=-1;
3409 QCString rname = removeRedundantWhiteSpace(root->name);
3410 //printf("rname=%s\n",rname.data());
3412 QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3413 if (!rname.isEmpty() && scope.find('@')==-1)
3416 // check if this function's parent is a class
3417 scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3419 FileDef *rfd=rootNav->fileDef();
3421 int memIndex=rname.findRev("::");
3424 if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3426 // strip scope from name
3427 rname=rname.right(rname.length()-rootNav->parent()->name().length()-2);
3430 NamespaceDef *nd = 0;
3431 bool isMember=FALSE;
3434 int ts=rname.find('<');
3435 int te=rname.find('>');
3436 if (memIndex>0 && (ts==-1 || te==-1))
3438 // note: the following code was replaced by inMember=TRUE to deal with a
3439 // function rname='X::foo' of class X inside a namespace also called X...
3441 //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3445 // // strip namespace scope from name
3446 // scope=rname.left(memIndex);
3447 // rname=rname.right(rname.length()-memIndex-2);
3453 isMember=memIndex<ts || memIndex>te;
3457 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3458 int ts=root->type.find('<');
3459 int te=root->type.findRev('>');
3461 if (!rootNav->parent()->name().isEmpty() &&
3462 (rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
3464 // do some fuzzy things to exclude function pointers
3465 (root->type.isEmpty() ||
3466 ((ti=root->type.find(re,0))==-1 || // type does not contain ..(..*
3467 (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3468 root->args.find(")[")!=-1) || // and args not )[.. -> function pointer
3469 root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3470 cd->getLanguage()!=SrcLangExt_Cpp // language other than C
3474 Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
3475 rname.data(),cd->name().data());
3476 addMethodToClass(rootNav,cd,rname,isFriend);
3478 else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK)
3479 || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3482 (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3483 root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3485 // no member => unrelated function
3487 /* check the uniqueness of the function name in the file.
3488 * A file could contain a function prototype and a function definition
3489 * or even multiple function prototypes.
3494 if ((mn=Doxygen::functionNameSDict->find(rname)))
3496 Debug::print(Debug::Functions,0," --> function %s already found!\n",rname.data());
3497 MemberNameIterator mni(*mn);
3498 for (mni.toFirst();(!found && (md=mni.current()));++mni)
3500 NamespaceDef *mnd = md->getNamespaceDef();
3501 NamespaceDef *rnd = 0;
3502 //printf("root namespace=%s\n",rootNav->parent()->name().data());
3503 QCString fullScope = scope;
3504 QCString parentScope = rootNav->parent()->name();
3505 if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3507 if (!scope.isEmpty()) fullScope.prepend("::");
3508 fullScope.prepend(parentScope);
3510 //printf("fullScope=%s\n",fullScope.data());
3511 rnd = getResolvedNamespace(fullScope);
3512 FileDef *mfd = md->getFileDef();
3513 QCString nsName,rnsName;
3514 if (mnd) nsName = mnd->name().copy();
3515 if (rnd) rnsName = rnd->name().copy();
3516 //printf("matching arguments for %s%s %s%s\n",
3517 // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3518 ArgumentList *mdAl = md->argumentList();
3519 ArgumentList *mdTempl = md->templateArguments();
3521 // in case of template functions, we need to check if the
3522 // functions have the same number of template parameters
3523 bool sameNumTemplateArgs = TRUE;
3524 bool matchingReturnTypes = TRUE;
3525 if (mdTempl!=0 && root->tArgLists)
3527 if (mdTempl->count()!=root->tArgLists->getLast()->count())
3529 sameNumTemplateArgs = FALSE;
3531 if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3533 matchingReturnTypes = FALSE;
3537 bool staticsInDifferentFiles =
3538 root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3541 matchArguments2(md->getOuterScope(),mfd,mdAl,
3542 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3544 sameNumTemplateArgs &&
3545 matchingReturnTypes &&
3546 !staticsInDifferentFiles
3550 if (root->groups->getFirst()!=0)
3552 gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
3554 //printf("match!\n");
3555 //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3556 // see if we need to create a new member
3557 found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace
3558 ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and
3559 mfd->absFilePath()==root->fileName // prototype in the same file
3562 // otherwise, allow a duplicate global member with the same argument list
3563 if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3565 // member is already in the group, so we don't want to add it again.
3569 //printf("combining function with prototype found=%d in namespace %s\n",
3570 // found,nsName.data());
3574 // merge argument lists
3575 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
3576 // merge documentation
3577 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3579 ArgumentList *argList = new ArgumentList;
3580 stringToArgumentList(root->args,argList);
3583 //printf("setDeclArgumentList to %p\n",argList);
3584 md->setDeclArgumentList(argList);
3588 md->setArgumentList(argList);
3592 md->setDocumentation(root->doc,root->docFile,root->docLine);
3593 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3594 md->setDocsForDefinition(!root->proto);
3595 if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3597 md->setBodySegment(root->bodyLine,root->endBodyLine);
3598 md->setBodyDef(rfd);
3601 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3603 md->setArgsString(root->args);
3605 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3607 md->addSectionsToDefinition(root->anchors);
3609 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3610 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3612 // merge ingroup specifiers
3613 if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
3615 addMemberToGroups(root,md);
3617 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3619 //printf("existing member is grouped, new member not\n");
3620 root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3622 else if (md->getGroupDef()!=0 && root->groups->getFirst()!=0)
3624 //printf("both members are grouped\n");
3627 // if md is a declaration and root is the corresponding
3628 // definition, then turn md into a definition.
3629 if (md->isPrototype() && !root->proto)
3631 md->setPrototype(FALSE);
3637 if (!found) /* global function is unique with respect to the file */
3639 Debug::print(Debug::Functions,0," --> new function %s found!\n",rname.data());
3640 //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3641 // root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3643 // new global function
3644 ArgumentList *tArgList = root->tArgLists ? root->tArgLists->getLast() : 0;
3645 QCString name=removeRedundantWhiteSpace(rname);
3647 root->fileName,root->startLine,root->startColumn,
3648 root->type,name,root->args,root->exception,
3649 root->protection,root->virt,root->stat,Member,
3650 MemberType_Function,tArgList,root->argList);
3652 md->setTagInfo(rootNav->tagInfo());
3653 md->setLanguage(root->lang);
3654 md->setId(root->id);
3655 //md->setDefFile(root->fileName);
3656 //md->setDefLine(root->startLine);
3657 md->setDocumentation(root->doc,root->docFile,root->docLine);
3658 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3659 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3660 md->setPrototype(root->proto);
3661 md->setDocsForDefinition(!root->proto);
3662 md->setTypeConstraints(root->typeConstr);
3663 //md->setBody(root->body);
3664 md->setBodySegment(root->bodyLine,root->endBodyLine);
3665 FileDef *fd=rootNav->fileDef();
3667 md->addSectionsToDefinition(root->anchors);
3668 md->setMemberSpecifiers(root->spec);
3669 md->setMemberGroupId(root->mGrpId);
3671 // see if the function is inside a namespace that was not part of
3672 // the name already (in that case nd should be non-zero already)
3673 if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3675 //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3676 QCString nscope=rootNav->parent()->name();
3677 if (!nscope.isEmpty())
3679 nd = getResolvedNamespace(nscope);
3683 if (!scope.isEmpty())
3685 QCString sep = getLanguageSpecificSeparator(root->lang);
3688 scope = substitute(scope,"::",sep);
3694 if (!root->type.isEmpty())
3698 def=root->type+" "+scope+name;
3702 def=root->type+" "+scope+name+root->args;
3709 def=scope+name.copy();
3713 def=scope+name+root->args;
3716 Debug::print(Debug::Functions,0,
3717 " Global Function:\n"
3718 " `%s' `%s'::`%s' `%s' proto=%d\n"
3721 rootNav->parent()->name().data(),
3727 md->setDefinition(def);
3728 md->enableCallGraph(root->callGraph);
3729 md->enableCallerGraph(root->callerGraph);
3730 //if (root->mGrpId!=-1)
3732 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
3735 md->setRefItems(root->sli);
3736 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3738 // add member to namespace
3739 md->setNamespace(nd);
3740 nd->insertMember(md);
3744 // add member to the file (we do this even if we have already
3745 // inserted it into the namespace)
3747 fd->insertMember(md);
3750 // add member to the list of file members
3751 //printf("Adding member=%s\n",md->name().data());
3753 if ((mn=Doxygen::functionNameSDict->find(name)))
3759 mn = new MemberName(name);
3761 Doxygen::functionNameSDict->append(name,mn);
3763 addMemberToGroups(root,md);
3764 if (root->relatesType == Simple) // if this is a relatesalso command,
3765 // allow find Member to pick it up
3767 rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished
3774 FileDef *fd=rootNav->fileDef();
3777 // add member to the file (we do this even if we have already
3778 // inserted it into the namespace)
3779 fd->insertMember(md);
3783 //printf("unrelated function %d `%s' `%s' `%s'\n",
3784 // root->parent->section,root->type.data(),rname.data(),root->args.data());
3788 Debug::print(Debug::Functions,0," --> %s not processed!\n",rname.data());
3791 else if (rname.isEmpty())
3793 warn(root->fileName,root->startLine,
3794 "Illegal member name found."
3798 rootNav->releaseEntry();
3800 RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3803 //----------------------------------------------------------------------
3805 static void findFriends()
3807 //printf("findFriends()\n");
3808 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3810 for (;(fn=fnli.current());++fnli) // for each global function name
3812 //printf("Function name=`%s'\n",fn->memberName());
3814 if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3815 { // there are members with the same name
3816 //printf("Function name is also a member name\n");
3817 MemberNameIterator fni(*fn);
3819 for (;(fmd=fni.current());++fni) // for each function with that name
3821 MemberNameIterator mni(*mn);
3823 for (;(mmd=mni.current());++mni) // for each member with that name
3825 //printf("Checking for matching arguments
3826 // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3827 // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3828 ArgumentList *mmdAl = mmd->argumentList();
3829 ArgumentList *fmdAl = fmd->argumentList();
3830 if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3831 matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl,
3832 fmd->getOuterScope(), fmd->getFileDef(), fmdAl,
3836 ) // if the member is related and the arguments match then the
3837 // function is actually a friend.
3839 mergeArguments(mmdAl,fmdAl);
3840 if (!fmd->documentation().isEmpty())
3842 mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3844 else if (!mmd->documentation().isEmpty())
3846 fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3848 if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3850 mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3852 else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3854 fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3856 if (!fmd->inbodyDocumentation().isEmpty())
3858 mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3860 else if (!mmd->inbodyDocumentation().isEmpty())
3862 fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3864 //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3865 if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3867 mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3868 mmd->setBodyDef(fmd->getBodyDef());
3869 //mmd->setBodyMember(fmd);
3871 else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3873 fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3874 fmd->setBodyDef(mmd->getBodyDef());
3875 //fmd->setBodyMember(mmd);
3877 mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3879 mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3880 mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3881 fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3882 fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3890 //----------------------------------------------------------------------
3892 static void transferFunctionDocumentation()
3894 //printf("---- transferFunctionDocumentation()\n");
3896 // find matching function declaration and definitions.
3897 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3899 for (;(mn=mnli.current());++mnli)
3901 //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3902 MemberDef *mdef=0,*mdec=0;
3903 MemberNameIterator mni1(*mn);
3904 /* find a matching function declaration and definition for this function */
3905 for (;(mdec=mni1.current());++mni1)
3907 if (mdec->isPrototype() ||
3908 (mdec->isVariable() && mdec->isExternal())
3911 MemberNameIterator mni2(*mn);
3912 for (;(mdef=mni2.current());++mni2)
3914 combineDeclarationAndDefinition(mdec,mdef);
3921 //----------------------------------------------------------------------
3923 static void transferFunctionReferences()
3925 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3927 for (;(mn=mnli.current());++mnli)
3929 MemberDef *md,*mdef=0,*mdec=0;
3930 MemberNameIterator mni(*mn);
3931 /* find a matching function declaration and definition for this function */
3932 for (;(md=mni.current());++mni)
3934 if (md->isPrototype())
3936 else if (md->isVariable() && md->isExternal())
3939 if (md->isFunction() && !md->isStatic() && !md->isPrototype())
3941 else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3946 ArgumentList *mdefAl = mdef->argumentList();
3947 ArgumentList *mdecAl = mdec->argumentList();
3949 matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
3950 mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
3955 MemberSDict *defDict = mdef->getReferencesMembers();
3956 MemberSDict *decDict = mdec->getReferencesMembers();
3959 MemberSDict::IteratorDict msdi(*defDict);
3961 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3963 if (decDict==0 || decDict->find(rmd->name())==0)
3965 mdec->addSourceReferences(rmd);
3971 MemberSDict::IteratorDict msdi(*decDict);
3973 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3975 if (defDict==0 || defDict->find(rmd->name())==0)
3977 mdef->addSourceReferences(rmd);
3982 defDict = mdef->getReferencedByMembers();
3983 decDict = mdec->getReferencedByMembers();
3986 MemberSDict::IteratorDict msdi(*defDict);
3988 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3990 if (decDict==0 || decDict->find(rmd->name())==0)
3992 mdec->addSourceReferencedBy(rmd);
3998 MemberSDict::IteratorDict msdi(*decDict);
4000 for (msdi.toFirst();(rmd=msdi.current());++msdi)
4002 if (defDict==0 || defDict->find(rmd->name())==0)
4004 mdef->addSourceReferencedBy(rmd);
4013 //----------------------------------------------------------------------
4015 static void transferRelatedFunctionDocumentation()
4017 // find match between function declaration and definition for
4018 // related functions
4019 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4021 for (mnli.toFirst();(mn=mnli.current());++mnli)
4024 MemberNameIterator mni(*mn);
4025 /* find a matching function declaration and definition for this function */
4026 for (mni.toFirst();(md=mni.current());++mni) // for each global function
4028 //printf(" Function `%s'\n",md->name().data());
4030 if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
4032 //printf(" Member name found\n");
4034 MemberNameIterator rmni(*rmn);
4035 for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
4037 ArgumentList *mdAl = md->argumentList();
4038 ArgumentList *rmdAl = rmd->argumentList();
4039 //printf(" Member found: related=`%d'\n",rmd->isRelated());
4040 if ((rmd->isRelated() || rmd->isForeign()) && // related function
4041 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4042 rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
4047 //printf(" Found related member `%s'\n",md->name().data());
4048 if (rmd->relatedAlso())
4049 md->setRelatedAlso(rmd->relatedAlso());
4050 else if (rmd->isForeign())
4061 //----------------------------------------------------------------------
4063 /*! make a dictionary of all template arguments of class cd
4064 * that are part of the base class name.
4065 * Example: A template class A with template arguments <R,S,T>
4066 * that inherits from B<T,T,S> will have T and S in the dictionary.
4068 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
4070 QDict<int> *templateNames = new QDict<int>(17);
4071 templateNames->setAutoDelete(TRUE);
4072 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
4073 if (templateArguments)
4075 ArgumentListIterator ali(*templateArguments);
4078 for (ali.toFirst();(arg=ali.current());++ali,count++)
4081 while ((i=re.match(name,p,&l))!=-1)
4083 QCString n = name.mid(i,l);
4086 if (templateNames->find(n)==0)
4088 templateNames->insert(n,new int(count));
4095 return templateNames;
4098 /*! Searches a class from within \a context and \a cd and returns its
4099 * definition if found (otherwise 0 is returned).
4101 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
4103 FileDef *fd=cd->getFileDef();
4105 if (context && cd!=context)
4107 result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
4111 result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
4113 if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4115 result = getClass(name);
4117 if (result==0 && cd &&
4118 (cd->getLanguage()==SrcLangExt_CSharp || cd->getLanguage()==SrcLangExt_Java) &&
4121 result = Doxygen::genericsDict->find(name);
4123 //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4125 // context ? context->name().data() : "<none>",
4126 // cd ? cd->name().data() : "<none>",
4127 // result ? result->name().data() : "<none>",
4128 // Doxygen::classSDict->find(name)
4134 static void findUsedClassesForClass(EntryNav *rootNav,
4135 Definition *context,
4137 ClassDef *instanceCd,
4139 ArgumentList *actualArgs=0,
4140 QDict<int> *templateNames=0
4143 masterCd->visited=TRUE;
4144 ArgumentList *formalArgs = masterCd->templateArguments();
4145 if (masterCd->memberNameInfoSDict())
4147 MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
4148 MemberNameInfo *mni;
4149 for (;(mni=mnili.current());++mnili)
4151 MemberNameInfoIterator mnii(*mni);
4153 for (mnii.toFirst();(mi=mnii.current());++mnii)
4155 MemberDef *md=mi->memberDef;
4156 if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4158 //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
4159 QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4160 QCString typedefValue = resolveTypeDef(masterCd,type);
4161 if (!typedefValue.isEmpty())
4163 type = typedefValue;
4166 QCString usedClassName;
4169 // the type can contain template variables, replace them if present
4172 type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4175 //printf(" template substitution gives=%s\n",type.data());
4176 while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
4178 // find the type (if any) that matches usedClassName
4179 ClassDef *typeCd = getResolvedClass(masterCd,
4180 masterCd->getFileDef(),
4185 //printf("====> usedClassName=%s -> typeCd=%s\n",
4186 // usedClassName.data(),typeCd?typeCd->name().data():"<none>");
4189 usedClassName = typeCd->name();
4192 int sp=usedClassName.find('<');
4194 int si=usedClassName.findRev("::",sp);
4197 // replace any namespace aliases
4198 replaceNamespaceAliases(usedClassName,si);
4200 // add any template arguments to the class
4201 QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4202 //printf(" usedName=%s\n",usedName.data());
4204 bool delTempNames=FALSE;
4205 if (templateNames==0)
4207 templateNames = getTemplateArgumentsInName(formalArgs,usedName);
4210 BaseInfo bi(usedName,Public,Normal);
4211 findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
4213 if (masterCd->templateArguments())
4215 ArgumentListIterator ali(*masterCd->templateArguments());
4218 for (ali.toFirst();(arg=ali.current());++ali,++count)
4220 if (arg->name==usedName) // type is a template argument
4223 Debug::print(Debug::Classes,0," New used class `%s'\n", usedName.data());
4225 ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
4228 usedCd = new ClassDef(
4229 masterCd->getDefFileName(),masterCd->getDefLine(),
4230 masterCd->getDefColumn(),
4233 //printf("making %s a template argument!!!\n",usedCd->name().data());
4234 usedCd->makeTemplateArgument();
4235 usedCd->setUsedOnly(TRUE);
4236 usedCd->setLanguage(masterCd->getLanguage());
4237 Doxygen::hiddenClasses->append(usedName,usedCd);
4241 if (isArtificial) usedCd->setArtificial(TRUE);
4242 Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", usedCd->name().data());
4243 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4244 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4252 ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4253 //printf("Looking for used class %s: result=%s master=%s\n",
4254 // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
4259 Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", usedCd->name().data());
4260 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
4261 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4266 delete templateNames;
4270 if (!found && !type.isEmpty()) // used class is not documented in any scope
4272 ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4273 if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
4275 if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4277 type+=md->argsString();
4279 Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", type.data());
4280 usedCd = new ClassDef(
4281 masterCd->getDefFileName(),masterCd->getDefLine(),
4282 masterCd->getDefColumn(),
4283 type,ClassDef::Class);
4284 usedCd->setUsedOnly(TRUE);
4285 usedCd->setLanguage(masterCd->getLanguage());
4286 Doxygen::hiddenClasses->append(type,usedCd);
4290 if (isArtificial) usedCd->setArtificial(TRUE);
4291 Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", usedCd->name().data());
4292 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4293 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4302 //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4306 static void findBaseClassesForClass(
4308 Definition *context,
4310 ClassDef *instanceCd,
4311 FindBaseClassRelation_Mode mode,
4313 ArgumentList *actualArgs=0,
4314 QDict<int> *templateNames=0
4317 Entry *root = rootNav->entry();
4318 //if (masterCd->visited) return;
4319 masterCd->visited=TRUE;
4320 // The base class could ofcouse also be a non-nested class
4321 ArgumentList *formalArgs = masterCd->templateArguments();
4322 QListIterator<BaseInfo> bii(*root->extends);
4324 for (bii.toFirst();(bi=bii.current());++bii)
4326 //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4327 // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4328 bool delTempNames=FALSE;
4329 if (templateNames==0)
4331 templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4334 BaseInfo tbi(bi->name,bi->prot,bi->virt);
4335 if (actualArgs) // substitute the formal template arguments of the base class
4337 tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4339 //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4341 if (mode==DocumentedOnly)
4343 // find a documented base class in the correct scope
4344 if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4346 // 1.8.2: decided to show inheritance relations even if not documented,
4347 // we do make them artificial, so they do not appear in the index
4348 //if (!Config_getBool("HIDE_UNDOC_RELATIONS"))
4349 bool b = Config_getBool("HIDE_UNDOC_RELATIONS") ? TRUE : isArtificial;
4351 // no documented base class -> try to find an undocumented one
4352 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4356 else if (mode==TemplateInstances)
4358 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4362 delete templateNames;
4368 //----------------------------------------------------------------------
4370 static bool findTemplateInstanceRelation(Entry *root,
4371 Definition *context,
4372 ClassDef *templateClass,const QCString &templSpec,
4373 QDict<int> *templateNames,
4376 Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n",
4377 templateClass->name().data(),templSpec.data());
4378 //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4379 // templateClass->name().data(),templSpec.data());
4380 //if (templateNames)
4382 // QDictIterator<int> qdi(*templateNames);
4383 // int *tempArgIndex;
4384 // for (;(tempArgIndex=qdi.current());++qdi)
4386 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4391 bool existingClass = (templSpec ==
4392 tempArgListToString(templateClass->templateArguments())
4394 if (existingClass) return TRUE;
4396 bool freshInstance=FALSE;
4397 ClassDef *instanceClass = templateClass->insertTemplateInstance(
4398 root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4399 if (isArtificial) instanceClass->setArtificial(TRUE);
4400 instanceClass->setLanguage(root->lang);
4404 Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",instanceClass->name().data());
4405 Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4406 instanceClass->setTemplateBaseClassNames(templateNames);
4408 // search for new template instances caused by base classes of
4410 EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4411 if (templateRootNav)
4413 bool unloadNeeded=FALSE;
4414 Entry *templateRoot = templateRootNav->entry();
4415 if (templateRoot==0) // not yet loaded
4417 templateRootNav->loadEntry(g_storage);
4418 templateRoot = templateRootNav->entry();
4419 ASSERT(templateRoot!=0); // now it should really be loaded
4423 Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",
4424 templateRoot->name.data(),templSpec.data());
4425 ArgumentList *templArgs = new ArgumentList;
4426 stringToArgumentList(templSpec,templArgs);
4427 findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4428 TemplateInstances,isArtificial,templArgs,templateNames);
4430 findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4431 isArtificial,templArgs,templateNames);
4434 if (unloadNeeded) // still cleanup to do
4436 templateRootNav->releaseEntry();
4441 Debug::print(Debug::Classes,0," no template root entry found!\n");
4442 // TODO: what happened if we get here?
4445 //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data());
4446 //ArgumentList *tl = templateClass->templateArguments();
4450 Debug::print(Debug::Classes,0," instance already exists!\n");
4455 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4458 int index=n.find('<');
4463 bool result = rightScopeMatch(scope,n);
4467 /*! Searches for the end of a template in prototype \a s starting from
4468 * character position \a startPos. If the end was found the position
4469 * of the closing \> is returned, otherwise -1 is returned.
4471 * Handles exotic cases such as
4480 static int findEndOfTemplate(const QCString &s,int startPos)
4482 // locate end of template
4486 int len = s.length();
4487 bool insideString=FALSE;
4488 bool insideChar=FALSE;
4490 while (e<len && brCount!=0)
4496 if (!insideString && !insideChar)
4498 if (e<len-1 && s.at(e+1)=='<')
4500 else if (roundCount==0)
4505 if (!insideString && !insideChar)
4507 if (e<len-1 && s.at(e+1)=='>')
4509 else if (roundCount==0)
4514 if (!insideString && !insideChar)
4518 if (!insideString && !insideChar)
4524 if (insideString && pc!='\\')
4533 if (insideChar && pc!='\\')
4543 return brCount==0 ? e : -1;
4546 static bool findClassRelation(
4548 Definition *context,
4551 QDict<int> *templateNames,
4552 FindBaseClassRelation_Mode mode,
4556 //printf("findClassRelation(class=%s base=%s templateNames=",
4557 // cd->name().data(),bi->name.data());
4558 //if (templateNames)
4560 // QDictIterator<int> qdi(*templateNames);
4561 // int *tempArgIndex;
4562 // for (;(tempArgIndex=qdi.current());++qdi)
4564 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4569 Entry *root = rootNav->entry();
4571 QCString biName=bi->name;
4572 bool explicitGlobalScope=FALSE;
4573 //printf("findClassRelation: biName=`%s'\n",biName.data());
4574 if (biName.left(2)=="::") // explicit global scope
4576 biName=biName.right(biName.length()-2);
4577 explicitGlobalScope=TRUE;
4580 EntryNav *parentNode=rootNav->parent();
4581 bool lastParent=FALSE;
4582 do // for each parent scope, starting with the largest scope
4583 // (in case of nested classes)
4585 QCString scopeName= parentNode ? parentNode->name().data() : "";
4586 int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4587 do // try all parent scope prefixes, starting with the largest scope
4589 //printf("scopePrefix=`%s' biName=`%s'\n",
4590 // scopeName.left(scopeOffset).data(),biName.data());
4592 QCString baseClassName=biName;
4595 baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4597 //QCString stripped;
4598 //baseClassName=stripTemplateSpecifiersFromScope
4599 // (removeRedundantWhiteSpace(baseClassName),TRUE,
4601 MemberDef *baseClassTypeDef=0;
4603 ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4611 //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4612 // baseClassName.data(),baseClass,cd,explicitGlobalScope);
4613 //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4614 // cd ? cd->name().data():"<none>",
4615 // baseClassName.data(),
4616 // baseClass?baseClass->name().data():"<none>",
4619 //if (baseClassName.left(root->name.length())!=root->name ||
4620 // baseClassName.at(root->name.length())!='<'
4621 // ) // Check for base class with the same name.
4622 // // If found then look in the outer scope for a match
4623 // // and prevent recursion.
4624 if (!isRecursiveBaseClass(rootNav->name(),baseClassName)
4625 || explicitGlobalScope
4626 // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4627 // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4628 || (rootNav->lang()==SrcLangExt_IDL &&
4629 (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
4630 rootNav->section()==Entry::INCLUDED_SERVICE_SEC)))
4633 Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4634 baseClassName.data(),
4635 rootNav->name().data(),
4636 (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4637 (bi->virt==Normal)?"normal":"virtual",
4641 int i=baseClassName.find('<');
4642 int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4644 if (baseClass==0 && (root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java))
4646 baseClass = Doxygen::genericsDict->find(baseClassName);
4647 //printf("looking for '%s' result=%p\n",baseClassName.data(),baseClass);
4649 if (baseClass==0 && i!=-1)
4650 // base class has template specifiers
4652 // TODO: here we should try to find the correct template specialization
4653 // but for now, we only look for the unspecializated base class.
4654 int e=findEndOfTemplate(baseClassName,i+1);
4655 //printf("baseClass==0 i=%d e=%d\n",i,e);
4656 if (e!=-1) // end of template was found at e
4658 templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4659 baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4660 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4668 //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4669 // baseClass,baseClassName.data(),templSpec.data());
4672 else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4673 // know it is a template, so see if
4674 // we can also link to the explicit
4675 // instance (for instance if a class
4676 // derived from a template argument)
4678 //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4679 ClassDef *templClass=getClass(baseClass->name()+templSpec);
4682 // use the template instance instead of the template base.
4683 baseClass = templClass;
4684 templSpec.resize(0);
4688 //printf("cd=%p baseClass=%p\n",cd,baseClass);
4689 bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4690 //printf("1. found=%d\n",found);
4691 if (!found && si!=-1)
4693 QCString tmpTemplSpec;
4694 // replace any namespace aliases
4695 replaceNamespaceAliases(baseClassName,si);
4696 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4704 found=baseClass!=0 && baseClass!=cd;
4705 if (found) templSpec = tmpTemplSpec;
4707 //printf("2. found=%d\n",found);
4709 //printf("root->name=%s biName=%s baseClassName=%s\n",
4710 // root->name.data(),biName.data(),baseClassName.data());
4711 //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4713 // baseClassName+="-g";
4718 baseClass=findClassWithinClassContext(context,cd,baseClassName);
4719 //printf("findClassWithinClassContext(%s,%s)=%p\n",
4720 // cd->name().data(),baseClassName.data(),baseClass);
4721 found = baseClass!=0 && baseClass!=cd;
4726 // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4727 // the class name also in the alias mapping.
4728 QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4729 if (aliasName) // see if it is indeed a class.
4731 baseClass=getClass(*aliasName);
4732 found = baseClass!=0 && baseClass!=cd;
4735 bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4736 // make templSpec canonical
4737 // warning: the following line doesn't work for Mixin classes (see bug 560623)
4738 // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4740 //printf("3. found=%d\n",found);
4743 Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
4744 // add base class to this class
4746 // if templSpec is not empty then we should "instantiate"
4747 // the template baseClass. A new ClassDef should be created
4748 // to represent the instance. To be able to add the (instantiated)
4749 // members and documentation of a template class
4750 // (inserted in that template class at a later stage),
4751 // the template should know about its instances.
4752 // the instantiation process, should be done in a recursive way,
4753 // since instantiating a template may introduce new inheritance
4755 if (!templSpec.isEmpty() && mode==TemplateInstances)
4757 // if baseClass is actually a typedef then we should not
4758 // instantiate it, since typedefs are in a different namespace
4759 // see bug531637 for an example where this would otherwise hang
4761 if (baseClassTypeDef==0)
4763 //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4764 findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4767 else if (mode==DocumentedOnly || mode==Undocumented)
4769 //printf(" => insert base class\n");
4771 if (baseClassTypeDef || cd->isCSharp())
4774 //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4776 static bool sipSupport = Config_getBool("SIP_SUPPORT");
4777 if (sipSupport) bi->prot=Public;
4778 if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4780 cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4781 // add this class as super class to the base class
4782 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4786 warn(root->fileName,root->startLine,
4787 "Detected potential recursive class relation "
4788 "between class %s and base class %s!",
4789 cd->name().data(),baseClass->name().data()
4795 else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4797 Debug::print(Debug::Classes,0,
4798 " New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4799 biName.data(),baseClassName.data(),templSpec.data(),isArtificial
4802 if (isATemplateArgument)
4804 baseClass=Doxygen::hiddenClasses->find(baseClassName);
4807 baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4810 Doxygen::hiddenClasses->append(baseClassName,baseClass);
4811 if (isArtificial) baseClass->setArtificial(TRUE);
4812 baseClass->setLanguage(root->lang);
4817 baseClass=Doxygen::classSDict->find(baseClassName);
4818 //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4819 // baseClassName.data(),baseClass,biName.data(),templSpec.data());
4822 baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4825 Doxygen::classSDict->append(baseClassName,baseClass);
4826 if (isArtificial) baseClass->setArtificial(TRUE);
4827 baseClass->setLanguage(root->lang);
4828 int si = baseClassName.findRev("::");
4829 if (si!=-1) // class is nested
4831 Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,rootNav->tagInfo());
4832 if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4834 baseClass->setArtificial(TRUE); // see bug678139
4839 if (biName.right(2)=="-p")
4841 biName="<"+biName.left(biName.length()-2)+">";
4843 // add base class to this class
4844 cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4845 // add this class as super class to the base class
4846 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4847 // the undocumented base was found in this file
4848 baseClass->insertUsedFile(rootNav->fileDef());
4849 baseClass->setOuterScope(Doxygen::globalScope);
4850 if (baseClassName.right(2)=="-p")
4852 baseClass->setCompoundType(ClassDef::Protocol);
4858 Debug::print(Debug::Classes,0," Base class `%s' not found\n",biName.data());
4863 if (mode!=TemplateInstances)
4865 warn(root->fileName,root->startLine,
4866 "Detected potential recursive class relation "
4867 "between class %s and base class %s!\n",
4868 root->name.data(),baseClassName.data()
4871 // for mode==TemplateInstance this case is quite common and
4872 // indicates a relation between a template class and a template
4873 // instance with the same name.
4879 else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4883 //printf("new scopeOffset=`%d'",scopeOffset);
4884 } while (scopeOffset>=0);
4892 parentNode=parentNode->parent();
4894 } while (lastParent);
4899 //----------------------------------------------------------------------
4900 // Computes the base and super classes for each class in the tree
4902 static bool isClassSection(EntryNav *rootNav)
4904 if ( !rootNav->name().isEmpty() )
4906 if (rootNav->section() & Entry::COMPOUND_MASK)
4907 // is it a compound (class, struct, union, interface ...)
4911 else if (rootNav->section() & Entry::COMPOUNDDOC_MASK)
4912 // is it a documentation block with inheritance info.
4914 rootNav->loadEntry(g_storage);
4915 Entry *root = rootNav->entry();
4916 bool extends = root->extends->count()>0;
4917 rootNav->releaseEntry();
4918 if (extends) return TRUE;
4925 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
4927 static void findClassEntries(EntryNav *rootNav)
4929 if (isClassSection(rootNav))
4931 g_classEntries.insert(rootNav->name(),rootNav);
4933 RECURSE_ENTRYTREE(findClassEntries,rootNav);
4936 /*! Using the dictionary build by findClassEntries(), this
4937 * function will look for additional template specialization that
4938 * exists as inheritance relations only. These instances will be
4939 * added to the template they are derived from.
4941 static void findInheritedTemplateInstances()
4943 ClassSDict::Iterator cli(*Doxygen::classSDict);
4944 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4945 QDictIterator<EntryNav> edi(g_classEntries);
4947 for (;(rootNav=edi.current());++edi)
4950 // strip any anonymous scopes first
4951 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4952 bName=stripTemplateSpecifiersFromScope(bName);
4953 Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",bName.data());
4954 if ((cd=getClass(bName)))
4956 rootNav->loadEntry(g_storage);
4957 //printf("Class %s %d\n",cd->name().data(),root->extends->count());
4958 findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
4959 rootNav->releaseEntry();
4964 static void findUsedTemplateInstances()
4966 ClassSDict::Iterator cli(*Doxygen::classSDict);
4967 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4968 QDictIterator<EntryNav> edi(g_classEntries);
4970 for (;(rootNav=edi.current());++edi)
4973 // strip any anonymous scopes first
4974 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4975 bName=stripTemplateSpecifiersFromScope(bName);
4976 Debug::print(Debug::Classes,0," Usage: Class %s : \n",bName.data());
4977 if ((cd=getClass(bName)))
4979 rootNav->loadEntry(g_storage);
4980 findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
4981 rootNav->releaseEntry();
4986 static void computeClassRelations()
4988 ClassSDict::Iterator cli(*Doxygen::classSDict);
4989 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4990 QDictIterator<EntryNav> edi(g_classEntries);
4992 for (;(rootNav=edi.current());++edi)
4996 rootNav->loadEntry(g_storage);
4997 Entry *root = rootNav->entry();
4999 // strip any anonymous scopes first
5000 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
5001 bName=stripTemplateSpecifiersFromScope(bName);
5002 Debug::print(Debug::Classes,0," Relations: Class %s : \n",bName.data());
5003 if ((cd=getClass(bName)))
5005 findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
5007 int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
5008 if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
5009 bName.right(2)!="::")
5011 if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
5012 (guessSection(root->fileName)==Entry::HEADER_SEC ||
5013 Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
5014 protectionLevelVisible(root->protection) && // hidden by protection
5015 !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
5018 root->fileName,root->startLine,
5019 "Compound %s is not documented.",
5024 rootNav->releaseEntry();
5028 static void computeTemplateClassRelations()
5030 QDictIterator<EntryNav> edi(g_classEntries);
5032 for (;(rootNav=edi.current());++edi)
5034 rootNav->loadEntry(g_storage);
5035 Entry *root = rootNav->entry();
5037 QCString bName=stripAnonymousNamespaceScope(root->name);
5038 bName=stripTemplateSpecifiersFromScope(bName);
5039 ClassDef *cd=getClass(bName);
5040 // strip any anonymous scopes first
5041 QDict<ClassDef> *templInstances = 0;
5042 if (cd && (templInstances=cd->getTemplateInstances()))
5044 Debug::print(Debug::Classes,0," Template class %s : \n",cd->name().data());
5045 QDictIterator<ClassDef> tdi(*templInstances);
5047 for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
5049 Debug::print(Debug::Classes,0," Template instance %s : \n",tcd->name().data());
5050 QCString templSpec = tdi.currentKey();
5051 ArgumentList *templArgs = new ArgumentList;
5052 stringToArgumentList(templSpec,templArgs);
5053 QList<BaseInfo> *baseList=root->extends;
5054 QListIterator<BaseInfo> it(*baseList);
5056 for (;(bi=it.current());++it) // for each base class of the template
5058 // check if the base class is a template argument
5059 BaseInfo tbi(bi->name,bi->prot,bi->virt);
5060 ArgumentList *tl = cd->templateArguments();
5063 QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
5064 QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
5065 // for each template name that we inherit from we need to
5066 // substitute the formal with the actual arguments
5067 QDict<int> *actualTemplateNames = new QDict<int>(17);
5068 actualTemplateNames->setAutoDelete(TRUE);
5069 QDictIterator<int> qdi(*templateNames);
5070 for (qdi.toFirst();qdi.current();++qdi)
5072 int templIndex = *qdi.current();
5073 Argument *actArg = 0;
5074 if (templIndex<(int)templArgs->count())
5076 actArg=templArgs->at(templIndex);
5079 baseClassNames!=0 &&
5080 baseClassNames->find(actArg->type)!=0 &&
5081 actualTemplateNames->find(actArg->type)==0
5084 actualTemplateNames->insert(actArg->type,new int(templIndex));
5087 delete templateNames;
5089 tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
5090 // find a documented base class in the correct scope
5091 if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
5093 // no documented base class -> try to find an undocumented one
5094 findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
5096 delete actualTemplateNames;
5100 } // class has no base classes
5103 rootNav->releaseEntry();
5107 //-----------------------------------------------------------------------
5108 // compute the references (anchors in HTML) for each function in the file
5110 static void computeMemberReferences()
5112 ClassSDict::Iterator cli(*Doxygen::classSDict);
5114 for (cli.toFirst();(cd=cli.current());++cli)
5116 cd->computeAnchors();
5118 FileNameListIterator fnli(*Doxygen::inputNameList);
5120 for (fnli.toFirst();(fn=fnli.current());++fnli)
5122 FileNameIterator fni(*fn);
5124 for (;(fd=fni.current());++fni)
5126 fd->computeAnchors();
5129 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5131 for (nli.toFirst();(nd=nli.current());++nli)
5133 nd->computeAnchors();
5135 GroupSDict::Iterator gli(*Doxygen::groupSDict);
5137 for (gli.toFirst();(gd=gli.current());++gli)
5139 gd->computeAnchors();
5143 //----------------------------------------------------------------------
5145 static void addListReferences()
5147 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
5149 for (mnli.toFirst();(mn=mnli.current());++mnli)
5151 MemberNameIterator mni(*mn);
5153 for (mni.toFirst();(md=mni.current());++mni)
5158 MemberNameSDict::Iterator fmnli(*Doxygen::functionNameSDict);
5159 for (fmnli.toFirst();(mn=fmnli.current());++fmnli)
5161 MemberNameIterator mni(*mn);
5163 for (mni.toFirst();(md=mni.current());++mni)
5169 ClassSDict::Iterator cli(*Doxygen::classSDict);
5171 for (cli.toFirst();(cd=cli.current());++cli)
5173 cd->addListReferences();
5176 FileNameListIterator fnli(*Doxygen::inputNameList);
5178 for (fnli.toFirst();(fn=fnli.current());++fnli)
5180 FileNameIterator fni(*fn);
5182 for (;(fd=fni.current());++fni)
5184 fd->addListReferences();
5188 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5190 for (nli.toFirst();(nd=nli.current());++nli)
5192 nd->addListReferences();
5195 GroupSDict::Iterator gli(*Doxygen::groupSDict);
5197 for (gli.toFirst();(gd=gli.current());++gli)
5199 gd->addListReferences();
5202 PageSDict::Iterator pdi(*Doxygen::pageSDict);
5204 for (pdi.toFirst();(pd=pdi.current());++pdi)
5206 QCString name = pd->getOutputFileBase();
5207 if (pd->getGroupDef())
5209 name = pd->getGroupDef()->getOutputFileBase();
5212 QList<ListItemInfo> *xrefItems = pd->xrefListItems();
5213 addRefItem(xrefItems,
5215 theTranslator->trPage(TRUE,TRUE),
5216 name,pd->title(),0);
5220 DirSDict::Iterator ddi(*Doxygen::directories);
5222 for (ddi.toFirst();(dd=ddi.current());++ddi)
5224 QCString name = dd->getOutputFileBase();
5225 //if (dd->getGroupDef())
5227 // name = dd->getGroupDef()->getOutputFileBase();
5229 QList<ListItemInfo> *xrefItems = dd->xrefListItems();
5230 addRefItem(xrefItems,
5232 theTranslator->trDir(TRUE,TRUE),
5233 name,dd->displayName(),0);
5237 //----------------------------------------------------------------------
5239 static void generateXRefPages()
5241 QDictIterator<RefList> di(*Doxygen::xrefLists);
5243 for (di.toFirst();(rl=di.current());++di)
5249 //----------------------------------------------------------------------
5250 // Copy the documentation in entry `root' to member definition `md' and
5251 // set the function declaration of the member to `funcDecl'. If the boolean
5252 // over_load is set the standard overload text is added.
5254 static void addMemberDocs(EntryNav *rootNav,
5255 MemberDef *md, const char *funcDecl,
5261 Entry *root = rootNav->entry();
5262 //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
5263 // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
5264 QCString fDecl=funcDecl;
5265 // strip extern specifier
5266 fDecl.stripPrefix("extern ");
5267 md->setDefinition(fDecl);
5268 md->enableCallGraph(root->callGraph);
5269 md->enableCallerGraph(root->callerGraph);
5270 ClassDef *cd=md->getClassDef();
5271 NamespaceDef *nd=md->getNamespaceDef();
5274 fullName = cd->name();
5276 fullName = nd->name();
5278 if (!fullName.isEmpty()) fullName+="::";
5279 fullName+=md->name();
5280 FileDef *rfd=rootNav->fileDef();
5282 // TODO determine scope based on root not md
5283 Definition *rscope = md->getOuterScope();
5285 ArgumentList *mdAl = md->argumentList();
5288 //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5289 mergeArguments(mdAl,al,!root->doc.isEmpty());
5294 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
5295 rscope,rfd,root->argList,
5300 //printf("merging arguments (2)\n");
5301 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
5304 if (over_load) // the \overload keyword was used
5306 QCString doc=getOverloadDocs();
5307 if (!root->doc.isEmpty())
5312 md->setDocumentation(doc,root->docFile,root->docLine);
5313 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5314 md->setDocsForDefinition(!root->proto);
5318 //printf("overwrite!\n");
5319 md->setDocumentation(root->doc,root->docFile,root->docLine);
5320 md->setDocsForDefinition(!root->proto);
5322 //printf("overwrite!\n");
5323 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5326 (md->inbodyDocumentation().isEmpty() ||
5327 !rootNav->parent()->name().isEmpty()
5328 ) && !root->inbodyDocs.isEmpty()
5331 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5335 //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5336 // md->initializer().data(),md->initializer().isEmpty(),
5337 // root->initializer.data(),root->initializer.isEmpty()
5339 if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5341 //printf("setInitializer\n");
5342 md->setInitializer(root->initializer);
5345 md->setMaxInitLines(root->initLines);
5349 if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5352 //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5353 md->setBodySegment(root->bodyLine,root->endBodyLine);
5354 md->setBodyDef(rfd);
5357 md->setRefItems(root->sli);
5360 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5361 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5363 md->mergeMemberSpecifiers(root->spec);
5364 md->addSectionsToDefinition(root->anchors);
5365 addMemberToGroups(root,md);
5366 if (cd) cd->insertUsedFile(rfd);
5367 //printf("root->mGrpId=%d\n",root->mGrpId);
5368 if (root->mGrpId!=-1)
5370 if (md->getMemberGroupId()!=-1)
5372 if (md->getMemberGroupId()!=root->mGrpId)
5375 root->fileName,root->startLine,
5376 "member %s belongs to two different groups. The second "
5377 "one found here will be ignored.",
5382 else // set group id
5384 //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5385 md->setMemberGroupId(root->mGrpId);
5390 //----------------------------------------------------------------------
5391 // find a class definition given the scope name and (optionally) a
5392 // template list specifier
5394 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5395 const char *scopeName)
5397 ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5402 //----------------------------------------------------------------------
5403 // Adds the documentation contained in `root' to a global function
5404 // with name `name' and argument list `args' (for overloading) and
5405 // function declaration `decl' to the corresponding member definition.
5407 static bool findGlobalMember(EntryNav *rootNav,
5408 const QCString &namespaceName,
5411 const char *tempArg,
5415 Entry *root = rootNav->entry();
5416 Debug::print(Debug::FindMembers,0,
5417 "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5418 namespaceName.data(),type,name,tempArg,decl);
5420 if (n.isEmpty()) return FALSE;
5421 if (n.find("::")!=-1) return FALSE; // skip undefined class members
5422 MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5425 mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5427 if (mn) // function name defined
5429 Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5431 MemberNameIterator mni(*mn);
5434 for (mni.toFirst();(md=mni.current()) && !found;++mni)
5436 NamespaceDef *nd=md->getNamespaceDef();
5438 //printf("Namespace namespaceName=%s nd=%s\n",
5439 // namespaceName.data(),nd ? nd->name().data() : "<none>");
5441 FileDef *fd=rootNav->fileDef();
5442 //printf("File %s\n",fd ? fd->name().data() : "<none>");
5443 NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5444 //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0;
5445 //printf("NamespaceList %p\n",nl);
5447 // search in the list of namespaces that are imported via a
5448 // using declaration
5449 bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5451 if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
5452 (nd && nd->name()==namespaceName) || // or in the same namespace
5453 viaUsingDirective // member in `using' namespace
5456 Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5457 md->name().data(),namespaceName.data());
5458 QCString nsName = nd ? nd->name().data() : "";
5460 NamespaceDef *rnd = 0;
5461 if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5463 ArgumentList *mdAl = md->argumentList();
5465 (mdAl==0 && root->argList->count()==0) ||
5466 md->isVariable() || md->isTypedef() || /* in case of function pointers */
5467 matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl,
5468 rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5471 // for template members we need to check if the number of
5472 // template arguments is the same, otherwise we are dealing with
5473 // different functions.
5474 if (matching && root->tArgLists)
5476 ArgumentList *mdTempl = md->templateArguments();
5479 if (root->tArgLists->getLast()->count()!=mdTempl->count())
5486 //printf("%s<->%s\n",
5487 // argListToString(md->argumentList()).data(),
5488 // argListToString(root->argList).data());
5490 // for static members we also check if the comment block was found in
5491 // the same file. This is needed because static members with the same
5492 // name can be in different files. Thus it would be wrong to just
5493 // put the comment block at the first syntactically matching member.
5494 if (matching && md->isStatic() &&
5495 md->getDefFileName()!=root->fileName &&
5501 // for template member we also need to check the return type
5502 if (md->templateArguments()!=0 && root->tArgLists!=0)
5504 //printf("Comparing return types '%s'<->'%s'\n",
5505 // md->typeString(),type);
5506 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
5507 qstrcmp(md->typeString(),type)!=0)
5509 //printf(" ---> no matching\n");
5514 if (matching) // add docs to the member
5516 Debug::print(Debug::FindMembers,0,"5. Match found\n");
5517 addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5522 if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5524 QCString fullFuncDecl=decl;
5525 if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5527 QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5530 warnMsg+="\nPossible candidates:\n";
5531 for (mni.toFirst();(md=mni.current());++mni)
5534 warnMsg+=substitute(md->declaration(),"%","%%");
5535 warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5536 " of file"+md->getDefFileName()+"\n";
5539 warn(root->fileName,root->startLine,warnMsg);
5542 else // got docs for an undefined member!
5544 if (root->type!="friend class" &&
5545 root->type!="friend struct" &&
5546 root->type!="friend union" &&
5547 (!Config_getBool("TYPEDEF_HIDES_STRUCT") ||
5548 root->type.find("typedef ")==-1)
5551 warn(root->fileName,root->startLine,
5552 "documented symbol `%s' was not declared or defined.",decl
5559 static bool isSpecialization(
5560 const QList<ArgumentList> &srcTempArgLists,
5561 const QList<ArgumentList> &dstTempArgLists
5564 QListIterator<ArgumentList> srclali(srcTempArgLists);
5565 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5566 for (;srclali.current();++srclali,++dstlali)
5568 ArgumentList *sal = srclali.current();
5569 ArgumentList *dal = dstlali.current();
5570 if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5575 static bool scopeIsTemplate(Definition *d)
5578 if (d && d->definitionType()==Definition::TypeClass)
5580 result = ((ClassDef*)d)->templateArguments() || scopeIsTemplate(d->getOuterScope());
5585 static QCString substituteTemplatesInString(
5586 const QList<ArgumentList> &srcTempArgLists,
5587 const QList<ArgumentList> &dstTempArgLists,
5588 ArgumentList *funcTempArgList, // can be used to match template specializations
5593 QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5594 //printf("type=%s\n",sa->type.data());
5596 while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5599 dst+=src.mid(p,i-p);
5600 QCString name=src.mid(i,l);
5602 QListIterator<ArgumentList> srclali(srcTempArgLists);
5603 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5604 for (;srclali.current() && !found;++srclali,++dstlali)
5606 ArgumentListIterator tsali(*srclali.current());
5607 ArgumentListIterator tdali(*dstlali.current());
5608 ArgumentListIterator *fali=0;
5609 Argument *tsa =0,*tda=0, *fa=0;
5610 if (funcTempArgList)
5612 fali = new ArgumentListIterator(*funcTempArgList);
5613 fa = fali->current();
5616 for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5618 tda = tdali.current();
5619 //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5620 // tsa->type.data(),tsa->name.data(),
5621 // tda->type.data(),tda->name.data());
5622 if (name==tsa->name)
5624 if (tda && tda->name.isEmpty())
5627 if (tda->type.left(6)=="class ") vc=6;
5628 else if (tda->type.left(9)=="typename ") vc=9;
5629 if (vc>0) // convert type=="class T" to type=="class" name=="T"
5631 tda->name = tda->type.mid(vc);
5632 tda->type = tda->type.left(vc-1);
5635 if (tda && !tda->name.isEmpty())
5637 name=tda->name; // substitute
5649 { ++(*fali); fa=fali->current(); }
5653 //printf(" srcList='%s' dstList='%s faList='%s'\n",
5654 // argListToString(srclali.current()).data(),
5655 // argListToString(dstlali.current()).data(),
5656 // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5661 dst+=src.right(src.length()-p);
5662 //printf(" substituteTemplatesInString(%s)=%s\n",
5663 // src.data(),dst.data());
5667 static void substituteTemplatesInArgList(
5668 const QList<ArgumentList> &srcTempArgLists,
5669 const QList<ArgumentList> &dstTempArgLists,
5672 ArgumentList *funcTempArgs = 0
5675 ArgumentListIterator sali(*src);
5676 ArgumentListIterator dali(*dst);
5678 Argument *da=dali.current();
5680 for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5682 QCString dstType = substituteTemplatesInString(
5683 srcTempArgLists,dstTempArgLists,funcTempArgs,
5685 QCString dstArray = substituteTemplatesInString(
5686 srcTempArgLists,dstTempArgLists,funcTempArgs,
5690 da=new Argument(*sa);
5704 dst->constSpecifier = src->constSpecifier;
5705 dst->volatileSpecifier = src->volatileSpecifier;
5706 dst->pureSpecifier = src->pureSpecifier;
5707 dst->trailingReturnType = substituteTemplatesInString(
5708 srcTempArgLists,dstTempArgLists,
5709 funcTempArgs,src->trailingReturnType);
5710 //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5711 // argListToString(src).data(),argListToString(dst).data()
5717 /*! This function tries to find a member (in a documented class/file/namespace)
5718 * that corresponds to the function/variable declaration given in \a funcDecl.
5720 * The boolean \a overloaded is used to specify whether or not a standard
5721 * overload documentation line should be generated.
5723 * The boolean \a isFunc is a hint that indicates that this is a function
5724 * instead of a variable or typedef.
5726 static void findMember(EntryNav *rootNav,
5732 Entry *root = rootNav->entry();
5734 Debug::print(Debug::FindMembers,0,
5735 "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5736 "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5737 "spec=%lld lang=%x\n",
5738 root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
5739 root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5740 root->spec,root->lang
5745 QCString namespaceName;
5749 QCString funcTempList;
5750 QCString exceptions;
5752 bool isRelated=FALSE;
5753 bool isMemberOf=FALSE;
5754 bool isFriend=FALSE;
5759 if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5764 if (funcDecl.stripPrefix("inline "))
5766 root->spec|=Entry::Inline;
5769 if (funcDecl.stripPrefix("explicit "))
5771 root->spec|=Entry::Explicit;
5774 if (funcDecl.stripPrefix("mutable "))
5776 root->spec|=Entry::Mutable;
5779 if (funcDecl.stripPrefix("virtual "))
5785 // delete any ; from the function declaration
5787 while ((sep=funcDecl.find(';'))!=-1)
5789 funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5792 // make sure the first character is a space to simplify searching.
5793 if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5795 // remove some superfluous spaces
5796 funcDecl= substitute(
5798 substitute(funcDecl,"~ ","~"),
5802 ).stripWhiteSpace();
5804 //printf("funcDecl=`%s'\n",funcDecl.data());
5805 if (isFriend && funcDecl.left(6)=="class ")
5807 //printf("friend class\n");
5808 funcDecl=funcDecl.right(funcDecl.length()-6);
5809 funcName = funcDecl.copy();
5811 else if (isFriend && funcDecl.left(7)=="struct ")
5813 funcDecl=funcDecl.right(funcDecl.length()-7);
5814 funcName = funcDecl.copy();
5818 // extract information from the declarations
5819 parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5820 funcArgs,funcTempList,exceptions
5823 //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5824 // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5826 // the class name can also be a namespace name, we decide this later.
5827 // if a related class name is specified and the class name could
5828 // not be derived from the function declaration, then use the
5830 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5831 // scopeName.data(),className.data(),namespaceName.data());
5832 if (!root->relates.isEmpty())
5833 { // related member, prefix user specified scope
5835 isMemberOf=(root->relatesType == MemberOf);
5836 if (getClass(root->relates)==0 && !scopeName.isEmpty())
5838 scopeName= mergeScopes(scopeName,root->relates);
5842 scopeName = root->relates;
5846 if (root->relates.isEmpty() && rootNav->parent() &&
5847 ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5848 (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5850 !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName
5851 // with the scope in which it was found
5853 QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5854 if (!scopeName.isEmpty() &&
5855 (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5857 scopeName = joinedName;
5861 scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5864 else // see if we can prefix a namespace or class that is used from the file
5866 FileDef *fd=rootNav->fileDef();
5869 NamespaceSDict *fnl = fd->getUsedNamespaces();
5872 QCString joinedName;
5874 NamespaceSDict::Iterator nsdi(*fnl);
5875 for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5877 joinedName = fnd->name()+"::"+scopeName;
5878 if (Doxygen::namespaceSDict->find(joinedName))
5880 scopeName=joinedName;
5887 scopeName=stripTemplateSpecifiersFromScope(
5888 removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
5890 // funcSpec contains the last template specifiers of the given scope.
5891 // If this method does not have any template arguments or they are
5892 // empty while funcSpec is not empty we assume this is a
5893 // specialization of a method. If not, we clear the funcSpec and treat
5894 // this as a normal method of a template class.
5895 if (!(root->tArgLists &&
5896 root->tArgLists->count()>0 &&
5897 root->tArgLists->getFirst()->count()==0
5904 // split scope into a namespace and a class part
5905 extractNamespaceName(scopeName,className,namespaceName,TRUE);
5906 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5907 // scopeName.data(),className.data(),namespaceName.data());
5909 //namespaceName=removeAnonymousScopes(namespaceName);
5910 if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5912 //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5913 // merge class and namespace scopes again
5914 scopeName.resize(0);
5915 if (!namespaceName.isEmpty())
5917 if (className.isEmpty())
5919 scopeName=namespaceName;
5921 else if (!root->relates.isEmpty() || // relates command with explicit scope
5922 !getClass(className)) // class name only exists in a namespace
5924 scopeName=namespaceName+"::"+className;
5928 scopeName=className;
5931 else if (!className.isEmpty())
5933 scopeName=className;
5935 //printf("new scope=`%s'\n",scopeName.data());
5937 QCString tempScopeName=scopeName;
5938 ClassDef *cd=getClass(scopeName);
5941 if (funcSpec.isEmpty())
5944 tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists,&argListIndex);
5948 tempScopeName=scopeName+funcSpec;
5951 //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
5952 // scopeName.data(),cd,root->tArgLists,tempScopeName.data());
5954 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
5955 // rebuild the function declaration (needed to get the scope right).
5956 if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
5958 if (!funcType.isEmpty())
5960 if (isFunc) // a function -> we use argList for the arguments
5962 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
5966 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
5971 if (isFunc) // a function => we use argList for the arguments
5973 funcDecl=tempScopeName+"::"+funcName+funcTempList;
5975 else // variable => add `argument' list
5977 funcDecl=tempScopeName+"::"+funcName+funcArgs;
5981 else // build declaration without scope
5983 if (!funcType.isEmpty()) // but with a type
5985 if (isFunc) // function => omit argument list
5987 funcDecl=funcType+" "+funcName+funcTempList;
5989 else // variable => add `argument' list
5991 funcDecl=funcType+" "+funcName+funcArgs;
5998 funcDecl=funcName+funcTempList;
6002 funcDecl=funcName+funcArgs;
6007 if (funcType=="template class" && !funcTempList.isEmpty())
6008 return; // ignore explicit template instantiations
6010 Debug::print(Debug::FindMembers,0,
6011 "findMember() Parse results:\n"
6012 " namespaceName=`%s'\n"
6018 " funcTempList=`%s'\n"
6021 " exceptions=`%s'\n"
6026 namespaceName.data(),className.data(),
6027 funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
6028 funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,
6033 if (!funcName.isEmpty()) // function name is valid
6035 Debug::print(Debug::FindMembers,0,
6036 "1. funcName=`%s'\n",funcName.data());
6037 if (funcName.left(9)=="operator ") // strip class scope from cast operator
6039 funcName = substitute(funcName,className+"::","");
6041 if (!funcTempList.isEmpty()) // try with member specialization
6043 mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
6045 if (mn==0) // try without specialization
6047 mn=Doxygen::memberNameSDict->find(funcName);
6049 if (!isRelated && mn) // function name already found
6051 Debug::print(Debug::FindMembers,0,
6052 "2. member name exists (%d members with this name)\n",mn->count());
6053 if (!className.isEmpty()) // class name is valid
6055 if (funcSpec.isEmpty()) // not a member specialization
6059 MemberNameIterator mni(*mn);
6061 bool memFound=FALSE;
6062 for (mni.toFirst();!memFound && (md=mni.current());++mni)
6064 ClassDef *cd=md->getClassDef();
6065 Debug::print(Debug::FindMembers,0,
6066 "3. member definition found, "
6067 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
6068 scopeName.data(),cd ? cd->name().data() : "<none>",
6070 root->fileName.data());
6071 //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
6072 FileDef *fd=rootNav->fileDef();
6074 if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
6076 //printf("scopeName %s->%s\n",scopeName.data(),
6077 // stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
6079 ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
6080 if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
6082 // don't be fooled by anonymous scopes
6085 //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
6086 // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
6088 if (cd && tcd==cd) // member's classes match
6090 Debug::print(Debug::FindMembers,0,
6091 "4. class definition %s found\n",cd->name().data());
6093 // get the template parameter lists found at the member declaration
6094 QList<ArgumentList> declTemplArgs;
6095 cd->getTemplateParameterLists(declTemplArgs);
6096 ArgumentList *templAl = md->templateArguments();
6099 declTemplArgs.append(templAl);
6102 // get the template parameter lists found at the member definition
6103 QList<ArgumentList> *defTemplArgs = root->tArgLists;
6104 //printf("defTemplArgs=%p\n",defTemplArgs);
6106 // do we replace the decl argument lists with the def argument lists?
6107 bool substDone=FALSE;
6108 ArgumentList *argList=0;
6110 /* substitute the occurrences of class template names in the
6111 * argument list before matching
6113 ArgumentList *mdAl = md->argumentList();
6114 if (declTemplArgs.count()>0 && defTemplArgs &&
6115 declTemplArgs.count()==defTemplArgs->count() &&
6119 /* the function definition has template arguments
6120 * and the class definition also has template arguments, so
6121 * we must substitute the template names of the class by that
6122 * of the function definition before matching.
6124 argList = new ArgumentList;
6125 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
6130 else /* no template arguments, compare argument lists directly */
6135 Debug::print(Debug::FindMembers,0,
6136 "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
6137 argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
6138 className.data(),namespaceName.data()
6142 md->isVariable() || md->isTypedef() || // needed for function pointers
6143 (mdAl==0 && root->argList->count()==0) ||
6145 md->getClassDef(),md->getFileDef(),argList,
6146 cd,fd,root->argList,
6149 if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
6151 matching = FALSE; // don't match methods and attributes with the same name
6154 // for template member we also need to check the return type
6155 if (md->templateArguments()!=0 && root->tArgLists!=0)
6157 QCString memType = md->typeString();
6158 memType.stripPrefix("static "); // see bug700696
6159 funcType=substitute(stripTemplateSpecifiersFromScope(funcType,TRUE),
6160 className+"::",""); // see bug700693 & bug732594
6161 Debug::print(Debug::FindMembers,0,
6162 "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
6163 md->typeString(),funcType.data(),
6164 md->templateArguments()->count(),root->tArgLists->getLast()->count());
6165 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
6166 qstrcmp(memType,funcType))
6168 //printf(" ---> no matching\n");
6172 bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
6173 bool classIsTemplate = scopeIsTemplate(md->getClassDef());
6174 bool mdIsTemplate = md->templateArguments()!=0;
6175 bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
6176 bool rootIsTemplate = root->tArgLists!=0;
6177 //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
6178 if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
6179 (mdIsTemplate || rootIsTemplate) && // either md or root is a template
6180 ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
6183 // Method with template return type does not match method without return type
6184 // even if the parameters are the same. See also bug709052
6185 Debug::print(Debug::FindMembers,0,
6186 "5b. Comparing return types: template v.s. non-template\n");
6191 Debug::print(Debug::FindMembers,0,
6192 "6. match results of matchArguments2 = %d\n",matching);
6194 if (substDone) // found a new argument list
6196 if (matching) // replace member's argument list
6198 md->setDefinitionTemplateParameterLists(root->tArgLists);
6199 md->setArgumentList(argList); // new owner of the list => no delete
6203 if (!funcTempList.isEmpty() &&
6204 isSpecialization(declTemplArgs,*defTemplArgs))
6206 // check if we are dealing with a partial template
6207 // specialization. In this case we add it to the class
6208 // even though the member arguments do not match.
6210 // TODO: copy other aspects?
6211 root->protection=md->protection(); // copy protection level
6212 addMethodToClass(rootNav,cd,md->name(),isFriend);
6220 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
6225 else if (cd && cd!=tcd) // we did find a class with the same name as cd
6226 // but in a different namespace
6231 if (count==0 && rootNav->parent() &&
6232 rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6234 goto localObjCMethod;
6236 if (count==0 && !(isFriend && funcType=="class"))
6239 ClassDef *ecd = 0, *ucd = 0;
6240 MemberDef *emd = 0, *umd = 0;
6243 //printf("Assume template class\n");
6244 for (mni.toFirst();(md=mni.current());++mni)
6246 ClassDef *ccd=md->getClassDef();
6248 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
6249 if (ccd!=0 && rightScopeMatch(ccd->name(),className))
6251 ArgumentList *templAl = md->templateArguments();
6252 if (root->tArgLists && templAl!=0 &&
6253 root->tArgLists->getLast()->count()<=templAl->count())
6255 addMethodToClass(rootNav,ccd,md->name(),isFriend);
6258 if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
6259 { // exact argument list match -> remember
6262 Debug::print(Debug::FindMembers,0,
6263 "7. new candidate className=%s scope=%s args=%s exact match\n",
6264 className.data(),ccd->name().data(),md->argsString());
6266 else // arguments do not match, but member name and scope do -> remember
6270 Debug::print(Debug::FindMembers,0,
6271 "7. new candidate className=%s scope=%s args=%s no match\n",
6272 className.data(),ccd->name().data(),md->argsString());
6278 static bool strictProtoMatching = Config_getBool("STRICT_PROTO_MATCHING");
6279 if (!strictProtoMatching)
6281 if (candidates==1 && ucd && umd)
6283 // we didn't find an actual match on argument lists, but there is only 1 member with this
6284 // name in the same scope, so that has to be the one.
6285 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
6288 else if (candidates>1 && ecd && emd)
6290 // we didn't find a unique match using type resolution,
6291 // but one of the matches has the exact same signature so
6292 // we take that one.
6293 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
6298 QCString warnMsg = "no ";
6299 if (noMatchCount>1) warnMsg+="uniquely ";
6300 warnMsg+="matching class member found for \n";
6302 if (root->tArgLists)
6304 QListIterator<ArgumentList> alli(*root->tArgLists);
6306 for (;(al=alli.current());++alli)
6308 warnMsg+=" template ";
6309 warnMsg+=tempArgListToString(al);
6313 QCString fullFuncDecl=funcDecl.copy();
6314 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6317 warnMsg+=fullFuncDecl;
6322 warnMsg+="Possible candidates:\n";
6323 for (mni.toFirst();(md=mni.current());++mni)
6325 ClassDef *cd=md->getClassDef();
6326 if (cd!=0 && rightScopeMatch(cd->name(),className))
6328 ArgumentList *templAl = md->templateArguments();
6331 warnMsg+=" 'template ";
6332 warnMsg+=tempArgListToString(templAl);
6336 if (md->typeString())
6338 warnMsg+=md->typeString();
6341 QCString qScope = cd->qualifiedNameWithTemplateParameters();
6342 if (!qScope.isEmpty())
6343 warnMsg+=qScope+"::"+md->name();
6344 if (md->argsString())
6345 warnMsg+=md->argsString();
6348 warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6349 " of file "+md->getDefFileName();
6356 warn_simple(root->fileName,root->startLine,warnMsg);
6359 else if (cd) // member specialization
6361 MemberNameIterator mni(*mn);
6362 MemberDef *declMd=0;
6364 for (mni.toFirst();(md=mni.current());++mni)
6366 if (md->getClassDef()==cd)
6368 // TODO: we should probably also check for matching arguments
6373 MemberType mtype=MemberType_Function;
6374 ArgumentList *tArgList = new ArgumentList;
6375 // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6377 root->fileName,root->startLine,root->startColumn,
6378 funcType,funcName,funcArgs,exceptions,
6379 declMd ? declMd->protection() : root->protection,
6380 root->virt,root->stat,Member,
6381 mtype,tArgList,root->argList);
6382 //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6383 md->setTagInfo(rootNav->tagInfo());
6384 md->setLanguage(root->lang);
6385 md->setId(root->id);
6386 md->setMemberClass(cd);
6387 md->setTemplateSpecialization(TRUE);
6388 md->setTypeConstraints(root->typeConstr);
6389 md->setDefinition(funcDecl);
6390 md->enableCallGraph(root->callGraph);
6391 md->enableCallerGraph(root->callerGraph);
6392 md->setDocumentation(root->doc,root->docFile,root->docLine);
6393 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6394 md->setDocsForDefinition(!root->proto);
6395 md->setPrototype(root->proto);
6396 md->addSectionsToDefinition(root->anchors);
6397 md->setBodySegment(root->bodyLine,root->endBodyLine);
6398 FileDef *fd=rootNav->fileDef();
6400 md->setMemberSpecifiers(root->spec);
6401 md->setMemberGroupId(root->mGrpId);
6403 cd->insertMember(md);
6404 md->setRefItems(root->sli);
6409 //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6410 // scopeName.data(),funcName.data(),funcArgs.data());
6413 else if (overloaded) // check if the function belongs to only one class
6415 // for unique overloaded member we allow the class to be
6416 // omitted, this is to be Qt compatible. Using this should
6417 // however be avoided, because it is error prone
6418 MemberNameIterator mni(*mn);
6419 MemberDef *md=mni.toFirst();
6421 ClassDef *cd=md->getClassDef();
6423 QCString className=cd->name().copy();
6426 for (;(md=mni.current());++mni)
6428 ClassDef *cd=md->getClassDef();
6429 if (className!=cd->name()) unique=FALSE;
6434 if (root->mtype==Signal) mtype=MemberType_Signal;
6435 else if (root->mtype==Slot) mtype=MemberType_Slot;
6436 else if (root->mtype==DCOP) mtype=MemberType_DCOP;
6437 else mtype=MemberType_Function;
6439 // new overloaded member function
6440 ArgumentList *tArgList =
6441 getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6442 //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6443 MemberDef *md=new MemberDef(
6444 root->fileName,root->startLine,root->startColumn,
6445 funcType,funcName,funcArgs,exceptions,
6446 root->protection,root->virt,root->stat,Related,
6447 mtype,tArgList,root->argList);
6448 md->setTagInfo(rootNav->tagInfo());
6449 md->setLanguage(root->lang);
6450 md->setId(root->id);
6451 md->setTypeConstraints(root->typeConstr);
6452 md->setMemberClass(cd);
6453 md->setDefinition(funcDecl);
6454 md->enableCallGraph(root->callGraph);
6455 md->enableCallerGraph(root->callerGraph);
6456 QCString doc=getOverloadDocs();
6459 md->setDocumentation(doc,root->docFile,root->docLine);
6460 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6461 md->setDocsForDefinition(!root->proto);
6462 md->setPrototype(root->proto);
6463 md->addSectionsToDefinition(root->anchors);
6464 md->setBodySegment(root->bodyLine,root->endBodyLine);
6465 FileDef *fd=rootNav->fileDef();
6467 md->setMemberSpecifiers(root->spec);
6468 md->setMemberGroupId(root->mGrpId);
6470 cd->insertMember(md);
6471 cd->insertUsedFile(fd);
6472 md->setRefItems(root->sli);
6475 else // unrelated function with the same name as a member
6477 if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6479 QCString fullFuncDecl=funcDecl.copy();
6480 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6481 warn(root->fileName,root->startLine,
6482 "Cannot determine class for function\n%s",
6488 else if (isRelated && !root->relates.isEmpty())
6490 Debug::print(Debug::FindMembers,0,"2. related function\n"
6491 " scopeName=%s className=%s\n",scopeName.data(),className.data());
6492 if (className.isEmpty()) className=root->relates;
6494 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6495 if ((cd=getClass(scopeName)))
6497 bool newMember=TRUE; // assume we have a new member
6498 bool newMemberName=FALSE;
6499 MemberDef *mdDefine=0;
6500 bool isDefine=FALSE;
6502 MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6505 MemberNameIterator mni(*mn);
6506 mdDefine = mni.current();
6507 while (mdDefine && !isDefine)
6509 isDefine = isDefine || mdDefine->isDefine();
6510 if (!isDefine) { ++mni; mdDefine=mni.current(); }
6515 FileDef *fd=rootNav->fileDef();
6517 if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6519 mn=new MemberName(funcName);
6520 newMemberName=TRUE; // we create a new member name
6524 MemberNameIterator mni(*mn);
6526 while ((rmd=mni.current()) && newMember) // see if we got another member with matching arguments
6528 ArgumentList *rmdAl = rmd->argumentList();
6531 className!=rmd->getOuterScope()->name() ||
6532 !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6533 cd,fd,root->argList,
6535 if (newMember) ++mni;
6537 if (!newMember && rmd) // member already exists as rmd -> add docs
6539 //printf("addMemberDocs for related member %s\n",root->name.data());
6540 //rmd->setMemberDefTemplateArguments(root->mtArgList);
6541 addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6545 if (newMember) // need to create a new member
6549 mtype=MemberType_Define;
6550 else if (root->mtype==Signal)
6551 mtype=MemberType_Signal;
6552 else if (root->mtype==Slot)
6553 mtype=MemberType_Slot;
6554 else if (root->mtype==DCOP)
6555 mtype=MemberType_DCOP;
6557 mtype=MemberType_Function;
6559 if (isDefine && mdDefine)
6561 mdDefine->setHidden(TRUE);
6563 funcArgs=mdDefine->argsString();
6564 funcDecl=funcType + " " + funcName;
6567 //printf("New related name `%s' `%d'\n",funcName.data(),
6568 // root->argList ? (int)root->argList->count() : -1);
6570 // first note that we pass:
6571 // (root->tArgLists ? root->tArgLists->last() : 0)
6572 // for the template arguments fo the new "member."
6573 // this accurately reflects the template arguments of
6574 // the related function, which don't have to do with
6575 // those of the related class.
6576 MemberDef *md=new MemberDef(
6577 root->fileName,root->startLine,root->startColumn,
6578 funcType,funcName,funcArgs,exceptions,
6579 root->protection,root->virt,
6580 root->stat && !isMemberOf,
6581 isMemberOf ? Foreign : isRelated ? Related : Member,
6583 (root->tArgLists ? root->tArgLists->getLast() : 0),
6584 funcArgs.isEmpty() ? 0 : root->argList);
6586 if (isDefine && mdDefine)
6588 md->setInitializer(mdDefine->initializer());
6592 // we still have the problem that
6593 // MemberDef::writeDocumentation() in memberdef.cpp
6594 // writes the template argument list for the class,
6595 // as if this member is a member of the class.
6596 // fortunately, MemberDef::writeDocumentation() has
6597 // a special mechanism that allows us to totally
6598 // override the set of template argument lists that
6599 // are printed. We use that and set it to the
6600 // template argument lists of the related function.
6602 md->setDefinitionTemplateParameterLists(root->tArgLists);
6604 md->setTagInfo(rootNav->tagInfo());
6608 //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6609 // funcName.data(),funcDecl.data(),root->bodyLine);
6611 // try to find the matching line number of the body from the
6612 // global function list
6614 if (root->bodyLine==-1)
6616 MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6619 MemberNameIterator rmni(*rmn);
6621 while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
6623 ArgumentList *rmdAl = rmd->argumentList();
6624 // check for matching argument lists
6626 matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6627 cd,fd,root->argList,
6635 if (rmd) // member found -> copy line number info
6637 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6638 md->setBodyDef(rmd->getBodyDef());
6639 //md->setBodyMember(rmd);
6643 if (!found) // line number could not be found or is available in this
6646 md->setBodySegment(root->bodyLine,root->endBodyLine);
6650 //if (root->mGrpId!=-1)
6652 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
6654 md->setMemberClass(cd);
6655 md->setMemberSpecifiers(root->spec);
6656 md->setDefinition(funcDecl);
6657 md->enableCallGraph(root->callGraph);
6658 md->enableCallerGraph(root->callerGraph);
6659 md->setDocumentation(root->doc,root->docFile,root->docLine);
6660 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6661 md->setDocsForDefinition(!root->proto);
6662 md->setPrototype(root->proto);
6663 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6664 md->addSectionsToDefinition(root->anchors);
6665 md->setMemberGroupId(root->mGrpId);
6666 md->setLanguage(root->lang);
6667 md->setId(root->id);
6668 //md->setMemberDefTemplateArguments(root->mtArgList);
6670 cd->insertMember(md);
6671 cd->insertUsedFile(fd);
6672 md->setRefItems(root->sli);
6673 if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6676 addMemberToGroups(root,md);
6678 //printf("Adding member=%s\n",md->name().data());
6681 //Doxygen::memberNameList.append(mn);
6682 //Doxygen::memberNameDict.insert(funcName,mn);
6683 Doxygen::memberNameSDict->append(funcName,mn);
6686 if (root->relatesType == Duplicate)
6688 if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6690 QCString fullFuncDecl=funcDecl.copy();
6691 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6692 warn(root->fileName,root->startLine,
6693 "Cannot determine file/namespace for relatedalso function\n%s",
6701 warn_undoc(root->fileName,root->startLine,
6702 "class `%s' for related function `%s' is not "
6704 className.data(),funcName.data()
6708 else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6712 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6713 if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
6715 Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6716 " scopeName=%s className=%s\n",root->name.data(),scopeName.data(),className.data());
6717 //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6718 MemberDef *md=new MemberDef(
6719 root->fileName,root->startLine,root->startColumn,
6720 funcType,funcName,funcArgs,exceptions,
6721 root->protection,root->virt,root->stat,Member,
6722 MemberType_Function,0,root->argList);
6723 md->setTagInfo(rootNav->tagInfo());
6724 md->setLanguage(root->lang);
6725 md->setId(root->id);
6726 md->makeImplementationDetail();
6727 md->setMemberClass(cd);
6728 md->setDefinition(funcDecl);
6729 md->enableCallGraph(root->callGraph);
6730 md->enableCallerGraph(root->callerGraph);
6731 md->setDocumentation(root->doc,root->docFile,root->docLine);
6732 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6733 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6734 md->setDocsForDefinition(!root->proto);
6735 md->setPrototype(root->proto);
6736 md->addSectionsToDefinition(root->anchors);
6737 md->setBodySegment(root->bodyLine,root->endBodyLine);
6738 FileDef *fd=rootNav->fileDef();
6740 md->setMemberSpecifiers(root->spec);
6741 md->setMemberGroupId(root->mGrpId);
6742 cd->insertMember(md);
6743 cd->insertUsedFile(fd);
6744 md->setRefItems(root->sli);
6745 if ((mn=Doxygen::memberNameSDict->find(root->name)))
6751 mn = new MemberName(root->name);
6753 Doxygen::memberNameSDict->append(root->name,mn);
6758 // local objective C method found for class without interface
6761 else // unrelated not overloaded member found
6763 bool globMem = findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl);
6764 if (className.isEmpty() && !globMem)
6766 warn(root->fileName,root->startLine,
6767 "class for member `%s' cannot "
6768 "be found.", funcName.data()
6771 else if (!className.isEmpty() && !globMem)
6773 warn(root->fileName,root->startLine,
6774 "member `%s' of class `%s' cannot be found",
6775 funcName.data(),className.data());
6781 // this should not be called
6782 warn(root->fileName,root->startLine,
6783 "member with no name found.");
6788 //----------------------------------------------------------------------
6789 // find the members corresponding to the different documentation blocks
6790 // that are extracted from the sources.
6792 static void filterMemberDocumentation(EntryNav *rootNav)
6794 Entry *root = rootNav->entry();
6796 Debug::print(Debug::FindMembers,0,
6797 "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6798 root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
6800 //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6803 if (root->relatesType == Duplicate && !root->relates.isEmpty())
6805 QCString tmp = root->relates;
6806 root->relates.resize(0);
6807 filterMemberDocumentation(rootNav);
6808 root->relates = tmp;
6811 if ( // detect func variable/typedef to func ptr
6812 (i=findFunctionPtr(root->type,root->lang,&l))!=-1
6815 //printf("Fixing function pointer!\n");
6816 // fix type and argument
6817 root->args.prepend(root->type.right(root->type.length()-i-l));
6818 root->type=root->type.left(i+l);
6819 //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6822 else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1))
6823 // detect function types marked as functions
6828 //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6829 if (root->section==Entry::MEMBERDOC_SEC)
6831 //printf("Documentation for inline member `%s' found args=`%s'\n",
6832 // root->name.data(),root->args.data());
6833 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6834 if (root->type.isEmpty())
6836 findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6840 findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6843 else if (root->section==Entry::OVERLOADDOC_SEC)
6845 //printf("Overloaded member %s found\n",root->name.data());
6846 findMember(rootNav,root->name,TRUE,isFunc);
6849 ((root->section==Entry::FUNCTION_SEC // function
6851 (root->section==Entry::VARIABLE_SEC && // variable
6852 !root->type.isEmpty() && // with a type
6853 g_compoundKeywordDict.find(root->type)==0 // that is not a keyword
6854 // (to skip forward declaration of class etc.)
6859 //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6860 // root->name.data(),root->args.data(),root->exception.data());
6861 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6862 //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6863 if (root->type=="friend class" || root->type=="friend struct" ||
6864 root->type=="friend union")
6872 else if (!root->type.isEmpty())
6892 else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6894 findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6896 else if (root->section==Entry::VARIABLEDOC_SEC)
6898 //printf("Documentation for variable %s found\n",root->name.data());
6899 //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data());
6900 findMember(rootNav,root->name,FALSE,FALSE);
6902 else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
6903 root->section==Entry::INCLUDED_SERVICE_SEC)
6905 findMember(rootNav,root->type + " " + root->name,FALSE,FALSE);
6910 //printf("skip section\n");
6914 static void findMemberDocumentation(EntryNav *rootNav)
6916 if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6917 rootNav->section()==Entry::OVERLOADDOC_SEC ||
6918 rootNav->section()==Entry::FUNCTION_SEC ||
6919 rootNav->section()==Entry::VARIABLE_SEC ||
6920 rootNav->section()==Entry::VARIABLEDOC_SEC ||
6921 rootNav->section()==Entry::DEFINE_SEC ||
6922 rootNav->section()==Entry::INCLUDED_SERVICE_SEC ||
6923 rootNav->section()==Entry::EXPORTED_INTERFACE_SEC
6926 rootNav->loadEntry(g_storage);
6928 filterMemberDocumentation(rootNav);
6930 rootNav->releaseEntry();
6932 if (rootNav->children())
6934 EntryNavListIterator eli(*rootNav->children());
6936 for (;(e=eli.current());++eli)
6938 if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6943 //----------------------------------------------------------------------
6945 static void findObjCMethodDefinitions(EntryNav *rootNav)
6947 if (rootNav->children())
6949 EntryNavListIterator eli(*rootNav->children());
6950 EntryNav *objCImplNav;
6951 for (;(objCImplNav=eli.current());++eli)
6953 if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
6955 EntryNavListIterator seli(*objCImplNav->children());
6956 EntryNav *objCMethodNav;
6957 for (;(objCMethodNav=seli.current());++seli)
6959 if (objCMethodNav->section()==Entry::FUNCTION_SEC)
6961 objCMethodNav->loadEntry(g_storage);
6962 Entry *objCMethod = objCMethodNav->entry();
6964 //Printf(" Found ObjC method definition %s\n",objCMethod->name.data());
6965 findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
6966 objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
6967 objCMethod->section=Entry::EMPTY_SEC;
6969 objCMethodNav->releaseEntry();
6977 //----------------------------------------------------------------------
6978 // find and add the enumeration to their classes, namespaces or files
6980 static void findEnums(EntryNav *rootNav)
6982 if (rootNav->section()==Entry::ENUM_SEC)
6984 rootNav->loadEntry(g_storage);
6985 Entry *root = rootNav->entry();
6991 MemberNameSDict *mnsd=0;
6993 bool isRelated=FALSE;
6994 bool isMemberOf=FALSE;
6995 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7001 if ((i=root->name.findRev("::"))!=-1) // scope is specified
7003 scope=root->name.left(i); // extract scope
7004 name=root->name.right(root->name.length()-i-2); // extract name
7005 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7007 else // no scope, check the scope in which the docs where found
7009 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7010 && !rootNav->parent()->name().isEmpty()
7011 ) // found enum docs inside a compound
7013 scope=rootNav->parent()->name();
7014 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7019 if (!root->relates.isEmpty())
7020 { // related member, prefix user specified scope
7022 isMemberOf=(root->relatesType == MemberOf);
7023 if (getClass(root->relates)==0 && !scope.isEmpty())
7024 scope=mergeScopes(scope,root->relates);
7026 scope=root->relates.copy();
7027 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7030 if (cd && !name.isEmpty()) // found a enum inside a compound
7032 //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
7034 mnsd=Doxygen::memberNameSDict;
7037 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7039 mnsd=Doxygen::functionNameSDict;
7042 else // found a global enum
7044 fd=rootNav->fileDef();
7045 mnsd=Doxygen::functionNameSDict;
7049 if (!name.isEmpty())
7053 root->fileName,root->startLine,root->startColumn,
7055 root->protection,Normal,FALSE,
7056 isMemberOf ? Foreign : isRelated ? Related : Member,
7057 MemberType_Enumeration,
7059 md->setTagInfo(rootNav->tagInfo());
7060 md->setLanguage(root->lang);
7061 md->setId(root->id);
7062 if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7063 md->setBodySegment(root->bodyLine,root->endBodyLine);
7064 md->setBodyDef(rootNav->fileDef());
7065 md->setMemberSpecifiers(root->spec); // UNO IDL "published"
7066 md->setEnumBaseType(root->args);
7067 //printf("Enum %s definition at line %d of %s: protection=%d\n",
7068 // root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
7069 md->addSectionsToDefinition(root->anchors);
7070 md->setMemberGroupId(root->mGrpId);
7071 md->enableCallGraph(root->callGraph);
7072 md->enableCallerGraph(root->callerGraph);
7073 //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
7074 md->setRefItems(root->sli);
7075 //printf("found enum %s nd=%p\n",name.data(),nd);
7078 QCString baseType = root->args;
7079 if (!baseType.isEmpty())
7081 baseType.prepend(" : ");
7084 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7086 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
7088 md->setDefinition(name+baseType);
7092 md->setDefinition(nd->name()+"::"+name+baseType);
7094 //printf("definition=%s\n",md->definition());
7096 md->setNamespace(nd);
7097 nd->insertMember(md);
7100 // even if we have already added the enum to a namespace, we still
7101 // also want to add it to other appropriate places such as file
7105 if (!defSet) md->setDefinition(name+baseType);
7106 if (fd==0 && rootNav->parent())
7108 fd=rootNav->parent()->fileDef();
7113 fd->insertMember(md);
7118 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
7120 md->setDefinition(name+baseType);
7124 md->setDefinition(cd->name()+"::"+name+baseType);
7126 cd->insertMember(md);
7127 cd->insertUsedFile(fd);
7129 md->setDocumentation(root->doc,root->docFile,root->docLine);
7130 md->setDocsForDefinition(!root->proto);
7131 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7132 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7134 //printf("Adding member=%s\n",md->name().data());
7136 if ((mn=(*mnsd)[name]))
7138 // this is used if the same enum is in multiple namespaces/classes
7141 else // new enum name
7143 mn = new MemberName(name);
7145 mnsd->append(name,mn);
7146 //printf("add %s to new memberName. Now %d members\n",
7147 // name.data(),mn->count());
7149 addMemberToGroups(root,md);
7151 rootNav->releaseEntry();
7155 RECURSE_ENTRYTREE(findEnums,rootNav);
7159 //----------------------------------------------------------------------
7161 static void addEnumValuesToEnums(EntryNav *rootNav)
7163 if (rootNav->section()==Entry::ENUM_SEC)
7164 // non anonymous enumeration
7166 rootNav->loadEntry(g_storage);
7167 Entry *root = rootNav->entry();
7172 MemberNameSDict *mnsd=0;
7174 bool isRelated=FALSE;
7175 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7181 if ((i=root->name.findRev("::"))!=-1) // scope is specified
7183 scope=root->name.left(i); // extract scope
7184 name=root->name.right(root->name.length()-i-2); // extract name
7185 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7187 else // no scope, check the scope in which the docs where found
7189 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7190 && !rootNav->parent()->name().isEmpty()
7191 ) // found enum docs inside a compound
7193 scope=rootNav->parent()->name();
7194 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7199 if (!root->relates.isEmpty())
7200 { // related member, prefix user specified scope
7202 if (getClass(root->relates)==0 && !scope.isEmpty())
7203 scope=mergeScopes(scope,root->relates);
7205 scope=root->relates.copy();
7206 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7209 if (cd && !name.isEmpty()) // found a enum inside a compound
7211 //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
7213 mnsd=Doxygen::memberNameSDict;
7216 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7218 //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
7219 mnsd=Doxygen::functionNameSDict;
7222 else // found a global enum
7224 fd=rootNav->fileDef();
7225 //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
7226 mnsd=Doxygen::functionNameSDict;
7230 if (!name.isEmpty())
7232 //printf("** name=%s\n",name.data());
7233 MemberName *mn = mnsd->find(name); // for all members with this name
7236 MemberNameIterator mni(*mn);
7238 for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list
7240 if (md->isEnumerate() && rootNav->children())
7242 //printf(" enum with %d children\n",rootNav->children()->count());
7243 EntryNavListIterator eli(*rootNav->children()); // for each enum value
7245 for (;(e=eli.current());++eli)
7249 (sle=rootNav->lang())==SrcLangExt_CSharp ||
7250 sle==SrcLangExt_Java ||
7251 sle==SrcLangExt_XML ||
7252 (root->spec&Entry::Strong)
7255 // Unlike classic C/C++ enums, for C++11, C# & Java enum
7256 // values are only visible inside the enum scope, so we must create
7257 // them here and only add them to the enum
7258 e->loadEntry(g_storage);
7259 Entry *root = e->entry();
7260 //printf("md->qualifiedName()=%s rootNav->name()=%s tagInfo=%p name=%s\n",
7261 // md->qualifiedName().data(),rootNav->name().data(),rootNav->tagInfo(),root->name.data());
7262 if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7263 substitute(rootNav->name(),"::",".") || // enum value scope matches that of the enum
7264 rootNav->tagInfo() // be less strict for tag files as members can have incomplete scope
7267 MemberDef *fmd=new MemberDef(
7268 root->fileName,root->startLine,root->startColumn,
7269 root->type,root->name,root->args,0,
7270 Public, Normal,root->stat,Member,
7271 MemberType_EnumValue,0,0);
7272 if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
7273 else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
7274 else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
7275 fmd->setOuterScope(md->getOuterScope());
7276 fmd->setTagInfo(e->tagInfo());
7277 fmd->setLanguage(root->lang);
7278 fmd->setId(root->id);
7279 fmd->setDocumentation(root->doc,root->docFile,root->docLine);
7280 fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7281 fmd->addSectionsToDefinition(root->anchors);
7282 fmd->setInitializer(root->initializer);
7283 fmd->setMaxInitLines(root->initLines);
7284 fmd->setMemberGroupId(root->mGrpId);
7285 fmd->setExplicitExternal(root->explicitExternal);
7286 fmd->setRefItems(root->sli);
7288 md->insertEnumField(fmd);
7289 fmd->setEnumScope(md,TRUE);
7290 MemberName *mn=mnsd->find(root->name);
7297 mn = new MemberName(root->name);
7299 mnsd->append(root->name,mn);
7306 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
7308 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
7309 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
7310 // get list of members with the same name as the field
7312 MemberNameIterator fmni(*fmn);
7314 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
7316 if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7318 //printf("found enum value with same name %s in scope %s\n",
7319 // fmd->name().data(),fmd->getOuterScope()->name().data());
7320 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7322 NamespaceDef *fnd=fmd->getNamespaceDef();
7323 if (fnd==nd) // enum value is inside a namespace
7325 md->insertEnumField(fmd);
7326 fmd->setEnumScope(md);
7331 FileDef *ffd=fmd->getFileDef();
7332 if (ffd==fd) // enum value has file scope
7334 md->insertEnumField(fmd);
7335 fmd->setEnumScope(md);
7338 else if (isRelated && cd) // reparent enum value to
7339 // match the enum's scope
7341 md->insertEnumField(fmd); // add field def to list
7342 fmd->setEnumScope(md); // cross ref with enum name
7343 fmd->setEnumClassScope(cd); // cross ref with enum name
7344 fmd->setOuterScope(cd);
7346 cd->insertMember(fmd);
7350 ClassDef *fcd=fmd->getClassDef();
7351 if (fcd==cd) // enum value is inside a class
7353 //printf("Inserting enum field %s in enum scope %s\n",
7354 // fmd->name().data(),md->name().data());
7355 md->insertEnumField(fmd); // add field def to list
7356 fmd->setEnumScope(md); // cross ref with enum name
7369 rootNav->releaseEntry();
7373 RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7378 //----------------------------------------------------------------------
7379 // find the documentation blocks for the enumerations
7381 static void findEnumDocumentation(EntryNav *rootNav)
7383 if (rootNav->section()==Entry::ENUMDOC_SEC
7384 && !rootNav->name().isEmpty()
7385 && rootNav->name().at(0)!='@' // skip anonymous enums
7388 rootNav->loadEntry(g_storage);
7389 Entry *root = rootNav->entry();
7391 //printf("Found docs for enum with name `%s' in context %s\n",
7392 // root->name.data(),root->parent->name.data());
7396 if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7398 name=root->name.right(root->name.length()-i-2); // extract name
7399 scope=root->name.left(i); // extract scope
7400 //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7402 else // just the name
7406 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7407 && !rootNav->parent()->name().isEmpty()
7408 ) // found enum docs inside a compound
7410 if (!scope.isEmpty()) scope.prepend("::");
7411 scope.prepend(rootNav->parent()->name());
7413 ClassDef *cd=getClass(scope);
7415 if (!name.isEmpty())
7420 //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7421 QCString className=cd->name().copy();
7422 MemberName *mn=Doxygen::memberNameSDict->find(name);
7425 MemberNameIterator mni(*mn);
7427 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7429 ClassDef *cd=md->getClassDef();
7430 if (cd && cd->name()==className && md->isEnumerate())
7432 // documentation outside a compound overrides the documentation inside it
7434 if (!md->documentation() || rootNav->parent()->name().isEmpty())
7437 md->setDocumentation(root->doc,root->docFile,root->docLine);
7438 md->setDocsForDefinition(!root->proto);
7441 // brief descriptions inside a compound override the documentation
7444 if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7447 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7450 if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7452 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7455 if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7457 md->setMemberGroupId(root->mGrpId);
7460 md->addSectionsToDefinition(root->anchors);
7461 md->setRefItems(root->sli);
7463 GroupDef *gd=md->getGroupDef();
7464 if (gd==0 &&root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7466 addMemberToGroups(root,md);
7475 //printf("MemberName %s not found!\n",name.data());
7478 else // enum outside class
7480 //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7481 MemberName *mn=Doxygen::functionNameSDict->find(name);
7484 MemberNameIterator mni(*mn);
7486 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7488 if (md->isEnumerate())
7490 md->setDocumentation(root->doc,root->docFile,root->docLine);
7491 md->setDocsForDefinition(!root->proto);
7492 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7493 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7494 md->addSectionsToDefinition(root->anchors);
7495 md->setMemberGroupId(root->mGrpId);
7497 GroupDef *gd=md->getGroupDef();
7498 if (gd==0 && root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7500 addMemberToGroups(root,md);
7510 warn(root->fileName,root->startLine,
7511 "Documentation for undefined enum `%s' found.",
7517 rootNav->releaseEntry();
7519 RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7522 // search for each enum (member or function) in mnl if it has documented
7524 static void findDEV(const MemberNameSDict &mnsd)
7527 MemberNameSDict::Iterator mnli(mnsd);
7528 // for each member name
7529 for (mnli.toFirst();(mn=mnli.current());++mnli)
7532 MemberNameIterator mni(*mn);
7533 // for each member definition
7534 for (mni.toFirst();(md=mni.current());++mni)
7536 if (md->isEnumerate()) // member is an enum
7538 MemberList *fmdl = md->enumFieldList();
7539 int documentedEnumValues=0;
7540 if (fmdl) // enum has values
7542 MemberListIterator fmni(*fmdl);
7544 // for each enum value
7545 for (fmni.toFirst();(fmd=fmni.current());++fmni)
7547 if (fmd->isLinkableInProject()) documentedEnumValues++;
7550 // at least one enum value is documented
7551 if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7557 // search for each enum (member or function) if it has documented enum
7559 static void findDocumentedEnumValues()
7561 findDEV(*Doxygen::memberNameSDict);
7562 findDEV(*Doxygen::functionNameSDict);
7565 //----------------------------------------------------------------------
7567 static void addMembersToIndex()
7570 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7571 // for each member name
7572 for (mnli.toFirst();(mn=mnli.current());++mnli)
7575 MemberNameIterator mni(*mn);
7576 // for each member definition
7577 for (mni.toFirst();(md=mni.current());++mni)
7579 addClassMemberNameToIndex(md);
7582 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7583 // for each member name
7584 for (fnli.toFirst();(mn=fnli.current());++fnli)
7587 MemberNameIterator mni(*mn);
7588 // for each member definition
7589 for (mni.toFirst();(md=mni.current());++mni)
7591 if (md->getNamespaceDef())
7593 addNamespaceMemberNameToIndex(md);
7597 addFileMemberNameToIndex(md);
7603 //----------------------------------------------------------------------
7604 // computes the relation between all members. For each member `m'
7605 // the members that override the implementation of `m' are searched and
7606 // the member that `m' overrides is searched.
7608 static void computeMemberRelations()
7610 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7612 for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7614 MemberNameIterator mdi(*mn);
7615 MemberNameIterator bmdi(*mn);
7618 for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7620 for ( bmdi.toFirst() ; (bmd=bmdi.current()); ++bmdi ) // for each other member with the same name
7622 ClassDef *mcd = md->getClassDef();
7623 if (mcd && mcd->baseClasses())
7625 ClassDef *bmcd = bmd->getClassDef();
7626 //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7627 // mcd->name().data(),md->name().data(),md,
7628 // bmcd->name().data(),bmd->name().data(),bmd
7630 if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
7631 (bmd->virtualness()!=Normal ||
7632 bmcd->compoundType()==ClassDef::Interface ||
7633 bmcd->compoundType()==ClassDef::Protocol
7636 mcd->isLinkable() &&
7637 bmcd->isLinkable() &&
7638 mcd->isBaseClass(bmcd,TRUE))
7640 //printf(" derived scope\n");
7641 ArgumentList *bmdAl = bmd->argumentList();
7642 ArgumentList *mdAl = md->argumentList();
7643 //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7644 // argListToString(bmdAl.pointer()).data(),
7645 // argListToString(mdAl.pointer()).data()
7648 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl,
7649 md->getOuterScope(), md->getFileDef(), mdAl,
7655 if ((rmd=md->reimplements())==0 ||
7656 minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7659 //printf("setting (new) reimplements member\n");
7660 md->setReimplements(bmd);
7662 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7663 bmd->insertReimplementedBy(md);
7673 //----------------------------------------------------------------------------
7674 //static void computeClassImplUsageRelations()
7677 // ClassSDict::Iterator cli(*Doxygen::classSDict);
7678 // for (;(cd=cli.current());++cli)
7680 // cd->determineImplUsageRelation();
7684 //----------------------------------------------------------------------------
7686 static void createTemplateInstanceMembers()
7688 ClassSDict::Iterator cli(*Doxygen::classSDict);
7691 for (cli.toFirst();(cd=cli.current());++cli)
7693 // that is a template
7694 QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7697 QDictIterator<ClassDef> qdi(*templInstances);
7699 // for each instance of the template
7700 for (qdi.toFirst();(tcd=qdi.current());++qdi)
7702 tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7708 //----------------------------------------------------------------------------
7710 static void mergeCategories()
7713 ClassSDict::Iterator cli(*Doxygen::classSDict);
7714 // merge members of categories into the class they extend
7715 for (cli.toFirst();(cd=cli.current());++cli)
7717 int i=cd->name().find('(');
7718 if (i!=-1) // it is an Objective-C category
7720 QCString baseName=cd->name().left(i);
7721 ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7724 //printf("*** merging members of category %s into %s\n",
7725 // cd->name().data(),baseClass->name().data());
7726 baseClass->mergeCategory(cd);
7732 // builds the list of all members for each class
7734 static void buildCompleteMemberLists()
7737 ClassSDict::Iterator cli(*Doxygen::classSDict);
7738 // merge the member list of base classes into the inherited classes.
7739 for (cli.toFirst();(cd=cli.current());++cli)
7741 if (// !cd->isReference() && // not an external class
7742 cd->subClasses()==0 && // is a root of the hierarchy
7743 cd->baseClasses()) // and has at least one base class
7745 //printf("*** merging members for %s\n",cd->name().data());
7749 // now sort the member list of all classes.
7750 for (cli.toFirst();(cd=cli.current());++cli)
7752 if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7756 //----------------------------------------------------------------------------
7758 static void generateFileSources()
7760 if (Doxygen::inputNameList->count()>0)
7763 static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
7764 if (clangAssistedParsing)
7766 QDict<void> g_processedFiles(10007);
7768 // create a dictionary with files to process
7769 QDict<void> g_filesToProcess(10007);
7770 FileNameListIterator fnli(*Doxygen::inputNameList);
7772 for (fnli.toFirst();(fn=fnli.current());++fnli)
7774 FileNameIterator fni(*fn);
7776 for (;(fd=fni.current());++fni)
7778 g_filesToProcess.insert(fd->absFilePath(),(void*)0x8);
7781 // process source files (and their include dependencies)
7782 for (fnli.toFirst();(fn=fnli.current());++fnli)
7784 FileNameIterator fni(*fn);
7786 for (;(fd=fni.current());++fni)
7788 if (fd->isSource() && !fd->isReference())
7790 QStrList filesInSameTu;
7791 fd->getAllIncludeFilesRecursively(filesInSameTu);
7793 if (fd->generateSourceFile()) // sources need to be shown in the output
7795 msg("Generating code for file %s...\n",fd->docName().data());
7796 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7799 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7800 // we needed to parse the sources even if we do not show them
7802 msg("Parsing code for file %s...\n",fd->docName().data());
7803 fd->parseSource(FALSE,filesInSameTu);
7806 char *incFile = filesInSameTu.first();
7807 while (incFile && g_filesToProcess.find(incFile))
7809 if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile))
7813 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
7814 if (ifd && !ifd->isReference())
7816 if (ifd->generateSourceFile()) // sources need to be shown in the output
7818 msg(" Generating code for file %s...\n",ifd->docName().data());
7819 ifd->writeSource(*g_outputList,TRUE,moreFiles);
7822 else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
7823 // we needed to parse the sources even if we do not show them
7825 msg(" Parsing code for file %s...\n",ifd->docName().data());
7826 ifd->parseSource(TRUE,moreFiles);
7828 g_processedFiles.insert(incFile,(void*)0x8);
7831 incFile = filesInSameTu.next();
7833 fd->finishParsing();
7834 g_processedFiles.insert(fd->absFilePath(),(void*)0x8);
7838 // process remaining files
7839 for (fnli.toFirst();(fn=fnli.current());++fnli)
7841 FileNameIterator fni(*fn);
7843 for (;(fd=fni.current());++fni)
7845 if (!g_processedFiles.find(fd->absFilePath())) // not yet processed
7847 QStrList filesInSameTu;
7849 if (fd->generateSourceFile()) // sources need to be shown in the output
7851 msg("Generating code for file %s...\n",fd->docName().data());
7852 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7855 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7856 // we needed to parse the sources even if we do not show them
7858 msg("Parsing code for file %s...\n",fd->docName().data());
7859 fd->parseSource(FALSE,filesInSameTu);
7861 fd->finishParsing();
7869 FileNameListIterator fnli(*Doxygen::inputNameList);
7871 for (;(fn=fnli.current());++fnli)
7873 FileNameIterator fni(*fn);
7875 for (;(fd=fni.current());++fni)
7877 QStrList filesInSameTu;
7879 if (fd->generateSourceFile()) // sources need to be shown in the output
7881 msg("Generating code for file %s...\n",fd->docName().data());
7882 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7885 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7886 // we needed to parse the sources even if we do not show them
7888 msg("Parsing code for file %s...\n",fd->docName().data());
7889 fd->parseSource(FALSE,filesInSameTu);
7891 fd->finishParsing();
7898 //----------------------------------------------------------------------------
7900 static void generateFileDocs()
7902 if (documentedHtmlFiles==0) return;
7904 if (Doxygen::inputNameList->count()>0)
7906 FileNameListIterator fnli(*Doxygen::inputNameList);
7908 for (fnli.toFirst();(fn=fnli.current());++fnli)
7910 FileNameIterator fni(*fn);
7912 for (fni.toFirst();(fd=fni.current());++fni)
7914 bool doc = fd->isLinkableInProject();
7917 msg("Generating docs for file %s...\n",fd->docName().data());
7918 fd->writeDocumentation(*g_outputList);
7925 //----------------------------------------------------------------------------
7927 static void addSourceReferences()
7929 // add source references for class definitions
7930 ClassSDict::Iterator cli(*Doxygen::classSDict);
7932 for (cli.toFirst();(cd=cli.current());++cli)
7934 FileDef *fd=cd->getBodyDef();
7935 if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
7937 fd->addSourceRef(cd->getStartBodyLine(),cd,0);
7940 // add source references for namespace definitions
7941 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7943 for (nli.toFirst();(nd=nli.current());++nli)
7945 FileDef *fd=nd->getBodyDef();
7946 if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
7948 fd->addSourceRef(nd->getStartBodyLine(),nd,0);
7952 // add source references for member names
7953 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7955 for (mnli.toFirst();(mn=mnli.current());++mnli)
7957 MemberNameIterator mni(*mn);
7959 for (mni.toFirst();(md=mni.current());++mni)
7961 //printf("class member %s: def=%s body=%d link?=%d\n",
7962 // md->name().data(),
7963 // md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
7964 // md->getStartBodyLine(),md->isLinkableInProject());
7965 FileDef *fd=md->getBodyDef();
7967 md->getStartBodyLine()!=-1 &&
7968 md->isLinkableInProject() &&
7969 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7972 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7973 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
7974 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7978 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7979 for (fnli.toFirst();(mn=fnli.current());++fnli)
7981 MemberNameIterator mni(*mn);
7983 for (mni.toFirst();(md=mni.current());++mni)
7985 FileDef *fd=md->getBodyDef();
7986 //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
7987 // md->name().data(),
7988 // md->getStartBodyLine(),md->getEndBodyLine(),fd,
7989 // md->isLinkableInProject(),
7990 // Doxygen::parseSourcesNeeded);
7992 md->getStartBodyLine()!=-1 &&
7993 md->isLinkableInProject() &&
7994 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7997 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7998 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
7999 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8005 //----------------------------------------------------------------------------
8007 static void sortMemberLists()
8009 // sort class member lists
8010 ClassSDict::Iterator cli(*Doxygen::classSDict);
8012 for (cli.toFirst();(cd=cli.current());++cli)
8014 cd->sortMemberLists();
8017 // sort namespace member lists
8018 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8020 for (nli.toFirst();(nd=nli.current());++nli)
8022 nd->sortMemberLists();
8025 // sort file member lists
8026 FileNameListIterator fnli(*Doxygen::inputNameList);
8028 for (;(fn=fnli.current());++fnli)
8030 FileNameIterator fni(*fn);
8032 for (;(fd=fni.current());++fni)
8034 fd->sortMemberLists();
8038 // sort group member lists
8039 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8041 for (gli.toFirst();(gd=gli.current());++gli)
8043 gd->sortMemberLists();
8047 //----------------------------------------------------------------------------
8048 // generate the documentation of all classes
8050 static void generateClassList(ClassSDict &classSDict)
8052 ClassSDict::Iterator cli(classSDict);
8053 for ( ; cli.current() ; ++cli )
8055 ClassDef *cd=cli.current();
8057 //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
8058 if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8059 cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8060 ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8063 // skip external references, anonymous compounds and
8064 // template instances
8065 if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8067 msg("Generating docs for compound %s...\n",cd->name().data());
8069 cd->writeDocumentation(*g_outputList);
8070 cd->writeMemberList(*g_outputList);
8072 // even for undocumented classes, the inner classes can be documented.
8073 cd->writeDocumentationForInnerClasses(*g_outputList);
8078 static void generateClassDocs()
8080 generateClassList(*Doxygen::classSDict);
8081 generateClassList(*Doxygen::hiddenClasses);
8084 //----------------------------------------------------------------------------
8086 static void inheritDocumentation()
8088 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8091 for (;(mn=mnli.current());++mnli)
8093 MemberNameIterator mni(*mn);
8095 for (;(md=mni.current());++mni)
8097 //printf("%04d Member `%s'\n",count++,md->name().data());
8098 if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
8099 { // no documentation yet
8100 MemberDef *bmd = md->reimplements();
8101 while (bmd && bmd->documentation().isEmpty() &&
8102 bmd->briefDescription().isEmpty()
8104 { // search up the inheritance tree for a documentation member
8105 //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
8106 bmd = bmd->reimplements();
8108 if (bmd) // copy the documentation from the reimplemented member
8110 md->setInheritsDocsFrom(bmd);
8111 md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8112 md->setDocsForDefinition(bmd->isDocsForDefinition());
8113 md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8114 md->copyArgumentNames(bmd);
8115 md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
8122 //----------------------------------------------------------------------------
8124 static void combineUsingRelations()
8127 FileNameListIterator fnli(*Doxygen::inputNameList);
8129 for (fnli.toFirst();(fn=fnli.current());++fnli)
8131 FileNameIterator fni(*fn);
8133 for (fni.toFirst();(fd=fni.current());++fni)
8138 for (fnli.toFirst();(fn=fnli.current());++fnli)
8140 FileNameIterator fni(*fn);
8142 for (fni.toFirst();(fd=fni.current());++fni)
8144 fd->combineUsingRelations();
8148 // for each namespace
8149 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8151 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8155 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8157 nd->combineUsingRelations();
8161 //----------------------------------------------------------------------------
8163 static void addMembersToMemberGroup()
8166 ClassSDict::Iterator cli(*Doxygen::classSDict);
8168 for ( ; (cd=cli.current()) ; ++cli )
8170 cd->addMembersToMemberGroup();
8173 FileNameListIterator fnli(*Doxygen::inputNameList);
8175 for (fnli.toFirst();(fn=fnli.current());++fnli)
8177 FileNameIterator fni(*fn);
8179 for (fni.toFirst();(fd=fni.current());++fni)
8181 fd->addMembersToMemberGroup();
8184 // for each namespace
8185 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8187 for ( ; (nd=nli.current()) ; ++nli )
8189 nd->addMembersToMemberGroup();
8192 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8194 for (gli.toFirst();(gd=gli.current());++gli)
8196 gd->addMembersToMemberGroup();
8200 //----------------------------------------------------------------------------
8202 static void distributeMemberGroupDocumentation()
8205 ClassSDict::Iterator cli(*Doxygen::classSDict);
8207 for ( ; (cd=cli.current()) ; ++cli )
8209 cd->distributeMemberGroupDocumentation();
8212 FileNameListIterator fnli(*Doxygen::inputNameList);
8214 for (fnli.toFirst();(fn=fnli.current());++fnli)
8216 FileNameIterator fni(*fn);
8218 for (fni.toFirst();(fd=fni.current());++fni)
8220 fd->distributeMemberGroupDocumentation();
8223 // for each namespace
8224 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8226 for ( ; (nd=nli.current()) ; ++nli )
8228 nd->distributeMemberGroupDocumentation();
8231 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8233 for (gli.toFirst();(gd=gli.current());++gli)
8235 gd->distributeMemberGroupDocumentation();
8239 //----------------------------------------------------------------------------
8241 static void findSectionsInDocumentation()
8244 ClassSDict::Iterator cli(*Doxygen::classSDict);
8246 for ( ; (cd=cli.current()) ; ++cli )
8248 cd->findSectionsInDocumentation();
8251 FileNameListIterator fnli(*Doxygen::inputNameList);
8253 for (fnli.toFirst();(fn=fnli.current());++fnli)
8255 FileNameIterator fni(*fn);
8257 for (fni.toFirst();(fd=fni.current());++fni)
8259 fd->findSectionsInDocumentation();
8262 // for each namespace
8263 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8265 for ( ; (nd=nli.current()) ; ++nli )
8267 nd->findSectionsInDocumentation();
8270 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8272 for (gli.toFirst();(gd=gli.current());++gli)
8274 gd->findSectionsInDocumentation();
8277 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8279 for (pdi.toFirst();(pd=pdi.current());++pdi)
8281 pd->findSectionsInDocumentation();
8283 if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8286 static void flushCachedTemplateRelations()
8288 // remove all references to classes from the cache
8289 // as there can be new template instances in the inheritance path
8290 // to this class. Optimization: only remove those classes that
8291 // have inheritance instances as direct or indirect sub classes.
8292 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8294 for (ci.toFirst();(li=ci.current());++ci)
8298 Doxygen::lookupCache->remove(ci.currentKey());
8301 // remove all cached typedef resolutions whose target is a
8302 // template class as this may now be a template instance
8303 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8305 for (;(fn=fnli.current());++fnli) // for each global function name
8307 MemberNameIterator fni(*fn);
8309 for (;(fmd=fni.current());++fni) // for each function with that name
8311 if (fmd->isTypedefValCached())
8313 ClassDef *cd = fmd->getCachedTypedefVal();
8314 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8318 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8319 for (;(fn=mnli.current());++mnli) // for each class method name
8321 MemberNameIterator mni(*fn);
8323 for (;(fmd=mni.current());++mni) // for each function with that name
8325 if (fmd->isTypedefValCached())
8327 ClassDef *cd = fmd->getCachedTypedefVal();
8328 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8334 //----------------------------------------------------------------------------
8336 static void flushUnresolvedRelations()
8338 // Remove all unresolved references to classes from the cache.
8339 // This is needed before resolving the inheritance relations, since
8340 // it would otherwise not find the inheritance relation
8341 // for C in the example below, as B::I was already found to be unresolvable
8342 // (which is correct if you igore the inheritance relation between A and B).
8344 // class A { class I {} };
8345 // class B : public A {};
8346 // class C : public B::I {};
8348 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8350 for (ci.toFirst();(li=ci.current());++ci)
8352 if (li->classDef==0 && li->typeDef==0)
8354 Doxygen::lookupCache->remove(ci.currentKey());
8358 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8360 for (;(fn=fnli.current());++fnli) // for each global function name
8362 MemberNameIterator fni(*fn);
8364 for (;(fmd=fni.current());++fni) // for each function with that name
8366 fmd->invalidateCachedArgumentTypes();
8369 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8370 for (;(fn=mnli.current());++mnli) // for each class method name
8372 MemberNameIterator mni(*fn);
8374 for (;(fmd=mni.current());++mni) // for each function with that name
8376 fmd->invalidateCachedArgumentTypes();
8382 //----------------------------------------------------------------------------
8384 static void findDefineDocumentation(EntryNav *rootNav)
8386 if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
8387 rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
8390 rootNav->loadEntry(g_storage);
8391 Entry *root = rootNav->entry();
8393 //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
8394 // root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
8396 if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8398 MemberDef *md=new MemberDef("<tagfile>",1,1,
8399 "#define",root->name,root->args,0,
8400 Public,Normal,FALSE,Member,MemberType_Define,0,0);
8401 md->setTagInfo(rootNav->tagInfo());
8402 md->setLanguage(root->lang);
8403 //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
8404 md->setFileDef(rootNav->parent()->fileDef());
8405 //printf("Adding member=%s\n",md->name().data());
8407 if ((mn=Doxygen::functionNameSDict->find(root->name)))
8413 mn = new MemberName(root->name);
8415 Doxygen::functionNameSDict->append(root->name,mn);
8418 MemberName *mn=Doxygen::functionNameSDict->find(root->name);
8421 MemberNameIterator mni(*mn);
8424 for (;(md=mni.current());++mni)
8426 if (md->memberType()==MemberType_Define) count++;
8430 for (mni.toFirst();(md=mni.current());++mni)
8432 if (md->memberType()==MemberType_Define)
8434 md->setDocumentation(root->doc,root->docFile,root->docLine);
8435 md->setDocsForDefinition(!root->proto);
8436 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8437 if (md->inbodyDocumentation().isEmpty())
8439 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8441 md->setBodySegment(root->bodyLine,root->endBodyLine);
8442 md->setBodyDef(rootNav->fileDef());
8443 md->addSectionsToDefinition(root->anchors);
8444 md->setMaxInitLines(root->initLines);
8445 md->setRefItems(root->sli);
8446 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8447 addMemberToGroups(root,md);
8452 (!root->doc.isEmpty() ||
8453 !root->brief.isEmpty() ||
8457 // multiple defines don't know where to add docs
8458 // but maybe they are in different files together with their documentation
8460 for (mni.toFirst();(md=mni.current());++mni)
8462 if (md->memberType()==MemberType_Define)
8464 FileDef *fd=md->getFileDef();
8465 if (fd && fd->absFilePath()==root->fileName)
8466 // doc and define in the same file assume they belong together.
8469 if (md->documentation().isEmpty())
8472 md->setDocumentation(root->doc,root->docFile,root->docLine);
8473 md->setDocsForDefinition(!root->proto);
8476 if (md->briefDescription().isEmpty())
8479 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8481 if (md->inbodyDocumentation().isEmpty())
8483 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8485 md->setBodySegment(root->bodyLine,root->endBodyLine);
8486 md->setBodyDef(rootNav->fileDef());
8487 md->addSectionsToDefinition(root->anchors);
8488 md->setRefItems(root->sli);
8489 md->setLanguage(root->lang);
8490 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8491 addMemberToGroups(root,md);
8495 //warn("define %s found in the following files:\n",root->name.data());
8496 //warn("Cannot determine where to add the documentation found "
8497 // "at line %d of file %s. \n",
8498 // root->startLine,root->fileName.data());
8501 else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8503 static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
8506 warn(root->fileName,root->startLine,
8507 "documentation for unknown define %s found.\n",
8513 warn(root->fileName,root->startLine,
8514 "found documented #define but ignoring it because "
8515 "ENABLE_PREPROCESSING is NO.\n",
8521 rootNav->releaseEntry();
8523 RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8526 //----------------------------------------------------------------------------
8528 static void findDirDocumentation(EntryNav *rootNav)
8530 if (rootNav->section() == Entry::DIRDOC_SEC)
8532 rootNav->loadEntry(g_storage);
8533 Entry *root = rootNav->entry();
8535 QCString normalizedName = root->name;
8536 normalizedName = substitute(normalizedName,"\\","/");
8537 //printf("root->docFile=%s normalizedName=%s\n",
8538 // root->docFile.data(),normalizedName.data());
8539 if (root->docFile==normalizedName) // current dir?
8541 int lastSlashPos=normalizedName.findRev('/');
8542 if (lastSlashPos!=-1) // strip file name
8544 normalizedName=normalizedName.left(lastSlashPos);
8547 if (normalizedName.at(normalizedName.length()-1)!='/')
8549 normalizedName+='/';
8551 DirDef *dir,*matchingDir=0;
8552 SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8553 for (sdi.toFirst();(dir=sdi.current());++sdi)
8555 //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8556 if (dir->name().right(normalizedName.length())==normalizedName)
8560 warn(root->fileName,root->startLine,
8561 "\\dir command matches multiple directories.\n"
8562 " Applying the command for directory %s\n"
8563 " Ignoring the command for directory %s\n",
8564 matchingDir->name().data(),dir->name().data()
8575 //printf("Match for with dir %s\n",matchingDir->name().data());
8576 matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8577 matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8578 matchingDir->setRefItems(root->sli);
8579 addDirToGroups(root,matchingDir);
8583 warn(root->fileName,root->startLine,"No matching "
8584 "directory found for command \\dir %s\n",normalizedName.data());
8586 rootNav->releaseEntry();
8588 RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8592 //----------------------------------------------------------------------------
8593 // create a (sorted) list of separate documentation pages
8595 static void buildPageList(EntryNav *rootNav)
8597 if (rootNav->section() == Entry::PAGEDOC_SEC)
8599 rootNav->loadEntry(g_storage);
8600 Entry *root = rootNav->entry();
8602 if (!root->name.isEmpty())
8604 addRelatedPage(rootNav);
8607 rootNav->releaseEntry();
8609 else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8611 rootNav->loadEntry(g_storage);
8612 Entry *root = rootNav->entry();
8614 QCString title=root->args.stripWhiteSpace();
8615 if (title.isEmpty()) title=theTranslator->trMainPage();
8616 //QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8617 QCString name = "index";
8618 addRefItem(root->sli,
8626 rootNav->releaseEntry();
8628 RECURSE_ENTRYTREE(buildPageList,rootNav);
8631 // search for the main page defined in this project
8632 static void findMainPage(EntryNav *rootNav)
8634 if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8636 rootNav->loadEntry(g_storage);
8638 if (Doxygen::mainPage==0 && rootNav->tagInfo()==0)
8640 Entry *root = rootNav->entry();
8641 //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8642 QCString title=root->args.stripWhiteSpace();
8643 //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8644 QCString indexName="index";
8645 Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8646 indexName, root->brief+root->doc+root->inbodyDocs,title);
8647 //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8648 Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8649 Doxygen::mainPage->setFileName(indexName,TRUE);
8650 Doxygen::mainPage->setShowToc(root->stat);
8651 addPageToContext(Doxygen::mainPage,rootNav);
8653 SectionInfo *si = Doxygen::sectionDict->find(Doxygen::mainPage->name());
8656 if (si->lineNr != -1)
8658 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);
8662 warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s)",Doxygen::mainPage->name().data(),si->fileName.data());
8667 // a page name is a label as well! but should no be double either
8669 indexName, root->startLine,
8670 Doxygen::mainPage->name(),
8671 Doxygen::mainPage->title(),
8674 Doxygen::sectionDict->append(indexName,si);
8675 Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8678 else if (rootNav->tagInfo()==0)
8680 Entry *root = rootNav->entry();
8681 warn(root->fileName,root->startLine,
8682 "found more than one \\mainpage comment block! Skipping this "
8687 rootNav->releaseEntry();
8689 RECURSE_ENTRYTREE(findMainPage,rootNav);
8692 // search for the main page imported via tag files and add only the section labels
8693 static void findMainPageTagFiles(EntryNav *rootNav)
8695 if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8697 rootNav->loadEntry(g_storage);
8699 if (Doxygen::mainPage && rootNav->tagInfo())
8701 Entry *root = rootNav->entry();
8702 Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8705 RECURSE_ENTRYTREE(findMainPageTagFiles,rootNav);
8708 static void computePageRelations(EntryNav *rootNav)
8710 if ((rootNav->section()==Entry::PAGEDOC_SEC ||
8711 rootNav->section()==Entry::MAINPAGEDOC_SEC
8713 && !rootNav->name().isEmpty()
8716 rootNav->loadEntry(g_storage);
8717 Entry *root = rootNav->entry();
8719 PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8720 Doxygen::pageSDict->find(root->name) :
8724 QListIterator<BaseInfo> bii(*root->extends);
8726 for (bii.toFirst();(bi=bii.current());++bii)
8728 PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8731 pd->addInnerCompound(subPd);
8732 //printf("*** Added subpage relation: %s->%s\n",
8733 // pd->name().data(),subPd->name().data());
8738 rootNav->releaseEntry();
8740 RECURSE_ENTRYTREE(computePageRelations,rootNav);
8743 static void checkPageRelations()
8745 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8747 for (pdi.toFirst();(pd=pdi.current());++pdi)
8749 Definition *ppd = pd->getOuterScope();
8754 err("page defined at line %d of file %s with label %s is a subpage "
8755 "of itself! Please remove this cyclic dependency.\n",
8756 pd->docLine(),pd->docFile().data(),pd->name().data());
8759 ppd=ppd->getOuterScope();
8764 //----------------------------------------------------------------------------
8766 static void resolveUserReferences()
8768 SDict<SectionInfo>::Iterator sdi(*Doxygen::sectionDict);
8770 for (;(si=sdi.current());++sdi)
8772 //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8773 // si->label.data(),si->definition?si->definition->name().data():"<none>",
8774 // si->fileName.data());
8777 // hack: the items of a todo/test/bug/deprecated list are all fragments from
8778 // different files, so the resulting section's all have the wrong file
8779 // name (not from the todo/test/bug/deprecated list, but from the file in
8780 // which they are defined). We correct this here by looking at the
8781 // generated section labels!
8782 QDictIterator<RefList> rli(*Doxygen::xrefLists);
8784 for (rli.toFirst();(rl=rli.current());++rli)
8786 QCString label="_"+rl->listName(); // "_todo", "_test", ...
8787 if (si->label.left(label.length())==label)
8789 si->fileName=rl->listName();
8795 //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8798 // if this section is in a page and the page is in a group, then we
8799 // have to adjust the link file name to point to the group.
8800 if (!si->fileName.isEmpty() &&
8801 (pd=Doxygen::pageSDict->find(si->fileName)) &&
8804 si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8809 // TODO: there should be one function in Definition that returns
8810 // the file to link to, so we can avoid the following tests.
8812 if (si->definition->definitionType()==Definition::TypeMember)
8814 gd = ((MemberDef *)si->definition)->getGroupDef();
8819 si->fileName=gd->getOutputFileBase().copy();
8823 //si->fileName=si->definition->getOutputFileBase().copy();
8824 //printf("Setting si->fileName to %s\n",si->fileName.data());
8828 //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8834 //----------------------------------------------------------------------------
8835 // generate all separate documentation pages
8838 static void generatePageDocs()
8840 //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8841 if (documentedPages==0) return;
8842 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8844 for (pdi.toFirst();(pd=pdi.current());++pdi)
8846 if (!pd->getGroupDef() && !pd->isReference())
8848 msg("Generating docs for page %s...\n",pd->name().data());
8849 Doxygen::insideMainPage=TRUE;
8850 pd->writeDocumentation(*g_outputList);
8851 Doxygen::insideMainPage=FALSE;
8856 //----------------------------------------------------------------------------
8857 // create a (sorted) list & dictionary of example pages
8859 static void buildExampleList(EntryNav *rootNav)
8861 if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty())
8863 rootNav->loadEntry(g_storage);
8864 Entry *root = rootNav->entry();
8866 if (Doxygen::exampleSDict->find(root->name))
8868 warn(root->fileName,root->startLine,
8869 "Example %s was already documented. Ignoring "
8870 "documentation found here.",
8876 PageDef *pd=new PageDef(root->fileName,root->startLine,
8877 root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8878 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8879 pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE),FALSE);
8880 pd->addSectionsToDefinition(root->anchors);
8881 pd->setLanguage(root->lang);
8882 //pi->addSections(root->anchors);
8884 Doxygen::exampleSDict->inSort(root->name,pd);
8885 //we don't add example to groups
8886 //addExampleToGroups(root,pd);
8889 rootNav->releaseEntry();
8891 RECURSE_ENTRYTREE(buildExampleList,rootNav);
8894 //----------------------------------------------------------------------------
8895 // prints the Entry tree (for debugging)
8897 void printNavTree(EntryNav *rootNav,int indent)
8900 indentStr.fill(' ',indent);
8901 msg("%s%s (sec=0x%x)\n",
8902 indentStr.isEmpty()?"":indentStr.data(),
8903 rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8904 rootNav->section());
8905 if (rootNav->children())
8907 EntryNavListIterator eli(*rootNav->children());
8908 for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8913 //----------------------------------------------------------------------------
8914 // generate the example documentation
8916 static void generateExampleDocs()
8918 g_outputList->disable(OutputGenerator::Man);
8919 PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8921 for (pdi.toFirst();(pd=pdi.current());++pdi)
8923 msg("Generating docs for example %s...\n",pd->name().data());
8924 resetCCodeParserState();
8925 QCString n=pd->getOutputFileBase();
8926 startFile(*g_outputList,n,n,pd->name());
8927 startTitle(*g_outputList,n);
8928 g_outputList->docify(pd->name());
8929 endTitle(*g_outputList,n,0);
8930 g_outputList->startContents();
8931 g_outputList->generateDoc(pd->docFile(), // file
8932 pd->docLine(), // startLine
8935 pd->documentation()+"\n\n\\include "+pd->name(), // docs
8936 TRUE, // index words
8940 endFile(*g_outputList); // contains g_outputList->endContents()
8942 g_outputList->enable(OutputGenerator::Man);
8945 //----------------------------------------------------------------------------
8946 // generate module pages
8948 static void generateGroupDocs()
8950 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8952 for (gli.toFirst();(gd=gli.current());++gli)
8954 if (!gd->isReference())
8956 gd->writeDocumentation(*g_outputList);
8961 //----------------------------------------------------------------------------
8963 //static void generatePackageDocs()
8965 // writePackageIndex(*g_outputList);
8967 // if (Doxygen::packageDict.count()>0)
8969 // PackageSDict::Iterator pdi(Doxygen::packageDict);
8971 // for (pdi.toFirst();(pd=pdi.current());++pdi)
8973 // pd->writeDocumentation(*g_outputList);
8978 //----------------------------------------------------------------------------
8979 // generate module pages
8981 static void generateNamespaceDocs()
8983 //writeNamespaceIndex(*g_outputList);
8985 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8987 // for each namespace...
8988 for (;(nd=nli.current());++nli)
8991 if (nd->isLinkableInProject())
8993 msg("Generating docs for namespace %s\n",nd->name().data());
8994 nd->writeDocumentation(*g_outputList);
8997 // for each class in the namespace...
8998 ClassSDict::Iterator cli(*nd->getClassSDict());
8999 for ( ; cli.current() ; ++cli )
9001 ClassDef *cd=cli.current();
9002 if ( ( cd->isLinkableInProject() &&
9003 cd->templateMaster()==0
9004 ) // skip external references, anonymous compounds and
9005 // template instances and nested classes
9006 && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
9009 msg("Generating docs for compound %s...\n",cd->name().data());
9011 cd->writeDocumentation(*g_outputList);
9012 cd->writeMemberList(*g_outputList);
9014 cd->writeDocumentationForInnerClasses(*g_outputList);
9020 static QCString fixSlashes(QCString &s)
9024 for (i=0;i<s.length();i++)
9041 //----------------------------------------------------------------------------
9043 static bool openOutputFile(const char *outFile,QFile &f)
9045 bool fileOpened=FALSE;
9046 bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
9047 if (writeToStdout) // write to stdout
9049 fileOpened = f.open(IO_WriteOnly,stdout);
9051 else // write to file
9053 QFileInfo fi(outFile);
9054 if (fi.exists()) // create a backup
9057 QFileInfo backup(fi.fileName()+".bak");
9058 if (backup.exists()) // remove existing backup
9059 dir.remove(backup.fileName());
9060 dir.rename(fi.fileName(),fi.fileName()+".bak");
9063 fileOpened = f.open(IO_WriteOnly|IO_Translate);
9068 /*! Generate a template version of the configuration file.
9069 * If the \a shortList parameter is TRUE a configuration file without
9070 * comments will be generated.
9072 static void generateConfigFile(const char *configFile,bool shortList,
9073 bool updateOnly=FALSE)
9076 bool fileOpened=openOutputFile(configFile,f);
9077 bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
9081 Config::instance()->writeTemplate(t,shortList,updateOnly);
9086 msg("\n\nConfiguration file `%s' created.\n\n",configFile);
9087 msg("Now edit the configuration file and enter\n\n");
9088 if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
9089 msg(" doxygen %s\n\n",configFile);
9091 msg(" doxygen\n\n");
9092 msg("to generate the documentation for your project\n\n");
9096 msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
9102 err("Cannot open file %s for writing\n",configFile);
9107 //----------------------------------------------------------------------------
9108 // read and parse a tag file
9110 //static bool readLineFromFile(QFile &f,QCString &s)
9114 // while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
9115 // return f.atEnd();
9118 //----------------------------------------------------------------------------
9120 static void readTagFile(Entry *root,const char *tl)
9122 QCString tagLine = tl;
9125 int eqPos = tagLine.find('=');
9126 if (eqPos!=-1) // tag command contains a destination
9128 fileName = tagLine.left(eqPos).stripWhiteSpace();
9129 destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9130 QFileInfo fi(fileName);
9131 Doxygen::tagDestinationDict.insert(fi.absFilePath().utf8(),new QCString(destName));
9132 //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
9139 QFileInfo fi(fileName);
9140 if (!fi.exists() || !fi.isFile())
9142 err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
9147 if (!destName.isEmpty())
9148 msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
9150 msg("Reading tag file `%s'...\n",fileName.data());
9152 parseTagFile(root,fi.absFilePath().utf8());
9155 //----------------------------------------------------------------------------
9156 static void copyStyleSheet()
9158 QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
9159 if (!htmlStyleSheet.isEmpty())
9161 QFileInfo fi(htmlStyleSheet);
9164 err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
9165 htmlStyleSheet.resize(0); // revert to the default
9169 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9170 copyFile(htmlStyleSheet,destFileName);
9173 QStrList htmlExtraStyleSheet = Config_getList("HTML_EXTRA_STYLESHEET");
9174 for (uint i=0; i<htmlExtraStyleSheet.count(); ++i)
9176 QCString fileName(htmlExtraStyleSheet.at(i));
9177 if (!fileName.isEmpty())
9179 QFileInfo fi(fileName);
9182 err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9186 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9187 copyFile(fileName, destFileName);
9193 static void copyLogo()
9195 QCString &projectLogo = Config_getString("PROJECT_LOGO");
9196 if (!projectLogo.isEmpty())
9198 QFileInfo fi(projectLogo);
9201 err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
9202 projectLogo.resize(0); // revert to the default
9206 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9207 copyFile(projectLogo,destFileName);
9208 Doxygen::indexList->addImageFile(fi.fileName().data());
9213 static void copyExtraFiles(const QCString& filesOption,const QCString &outputOption)
9215 QStrList files = Config_getList(filesOption);
9217 for (i=0; i<files.count(); ++i)
9219 QCString fileName(files.at(i));
9221 if (!fileName.isEmpty())
9223 QFileInfo fi(fileName);
9226 err("Extra file '%s' specified in " + filesOption + " does not exist!\n", fileName.data());
9230 QCString destFileName = Config_getString(outputOption)+"/"+fi.fileName().data();
9231 Doxygen::indexList->addImageFile(fi.fileName().utf8());
9232 copyFile(fileName, destFileName);
9238 //----------------------------------------------------------------------------
9240 static ParserInterface *getParserForFile(const char *fn)
9242 QCString fileName=fn;
9244 int ei = fileName.findRev('.');
9247 extension=fileName.right(fileName.length()-ei);
9251 extension = ".no_extension";
9254 return Doxygen::parserManager->getParser(extension);
9257 static void parseFile(ParserInterface *parser,
9258 Entry *root,EntryNav *rootNav,FileDef *fd,const char *fn,
9259 bool sameTu,QStrList &filesInSameTu)
9262 static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
9264 static bool clangAssistedParsing = FALSE;
9266 QCString fileName=fn;
9268 int ei = fileName.findRev('.');
9271 extension=fileName.right(fileName.length()-ei);
9275 extension = ".no_extension";
9278 QFileInfo fi(fileName);
9279 BufStr preBuf(fi.size()+4096);
9281 if (Config_getBool("ENABLE_PREPROCESSING") &&
9282 parser->needsPreprocessing(extension))
9284 BufStr inBuf(fi.size()+4096);
9285 msg("Preprocessing %s...\n",fn);
9286 readInputFile(fileName,inBuf);
9287 preprocessFile(fileName,inBuf,preBuf);
9289 else // no preprocessing
9291 msg("Reading %s...\n",fn);
9292 readInputFile(fileName,preBuf);
9295 BufStr convBuf(preBuf.curPos()+1024);
9297 // convert multi-line C++ comments to C style comments
9298 convertCppComments(&preBuf,&convBuf,fileName);
9300 convBuf.addChar('\0');
9302 if (clangAssistedParsing && !sameTu)
9304 fd->getAllIncludeFilesRecursively(filesInSameTu);
9307 // use language parse to parse the file
9308 parser->parseInput(fileName,convBuf.data(),root,sameTu,filesInSameTu);
9310 // store the Entry tree in a file and create an index to
9311 // navigate/load entries
9312 //printf("root->createNavigationIndex for %s\n",fd->name().data());
9313 root->createNavigationIndex(rootNav,g_storage,fd);
9316 //! parse the list of input files
9317 static void parseFiles(Entry *root,EntryNav *rootNav)
9320 static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
9321 if (clangAssistedParsing)
9323 QDict<void> g_processedFiles(10007);
9325 // create a dictionary with files to process
9326 QDict<void> g_filesToProcess(10007);
9327 StringListIterator it(g_inputFiles);
9329 for (;(s=it.current());++it)
9331 g_filesToProcess.insert(*s,(void*)0x8);
9334 // process source files (and their include dependencies)
9335 for (it.toFirst();(s=it.current());++it)
9338 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9340 if (fd->isSource() && !fd->isReference()) // this is a source file
9342 QStrList filesInSameTu;
9343 ParserInterface * parser = getParserForFile(s->data());
9344 parser->startTranslationUnit(s->data());
9345 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9346 //printf(" got %d extra files in tu\n",filesInSameTu.count());
9348 // Now process any include files in the same translation unit
9349 // first. When libclang is used this is much more efficient.
9350 char *incFile = filesInSameTu.first();
9351 while (incFile && g_filesToProcess.find(incFile))
9353 if (qstrcmp(incFile,s->data()) && !g_processedFiles.find(incFile))
9355 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
9356 if (ifd && !ifd->isReference())
9359 //printf(" Processing %s in same translation unit as %s\n",incFile,s->data());
9360 parseFile(parser,root,rootNav,ifd,incFile,TRUE,moreFiles);
9361 g_processedFiles.insert(incFile,(void*)0x8);
9364 incFile = filesInSameTu.next();
9366 parser->finishTranslationUnit();
9367 g_processedFiles.insert(*s,(void*)0x8);
9370 // process remaining files
9371 for (it.toFirst();(s=it.current());++it)
9373 if (!g_processedFiles.find(*s)) // not yet processed
9376 QStrList filesInSameTu;
9377 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9379 ParserInterface * parser = getParserForFile(s->data());
9380 parser->startTranslationUnit(s->data());
9381 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9382 parser->finishTranslationUnit();
9383 g_processedFiles.insert(*s,(void*)0x8);
9387 else // normal pocessing
9390 StringListIterator it(g_inputFiles);
9392 for (;(s=it.current());++it)
9395 QStrList filesInSameTu;
9396 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9398 ParserInterface * parser = getParserForFile(s->data());
9399 parser->startTranslationUnit(s->data());
9400 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9405 // resolves a path that may include symlinks, if a recursive symlink is
9406 // found an empty string is returned.
9407 static QCString resolveSymlink(QCString path)
9412 QDict<void> nonSymlinks;
9414 QCString result = path;
9415 QCString oldPrefix = "/";
9419 // UNC path, skip server and share name
9420 if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
9421 sepPos = result.find('/',2);
9423 sepPos = result.find('/',sepPos+1);
9425 sepPos = result.find('/',sepPos+1);
9427 QCString prefix = sepPos==-1 ? result : result.left(sepPos);
9428 if (nonSymlinks.find(prefix)==0)
9433 QString target = fi.readLink();
9434 bool isRelative = QFileInfo(target).isRelative();
9437 target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
9441 if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
9445 target+=result.mid(sepPos);
9447 result = QDir::cleanDirPath(target).data();
9449 if (known.find(result)) return QCString(); // recursive symlink!
9450 known.insert(result,(void*)0x8);
9455 else // link to absolute path
9463 nonSymlinks.insert(prefix,(void*)0x8);
9470 return QDir::cleanDirPath(result).data();
9473 static QDict<void> g_pathsVisited(1009);
9475 //----------------------------------------------------------------------------
9476 // Read all files matching at least one pattern in `patList' in the
9477 // directory represented by `fi'.
9478 // The directory is read iff the recusiveFlag is set.
9479 // The contents of all files is append to the input string
9481 int readDir(QFileInfo *fi,
9482 FileNameList *fnList,
9483 FileNameDict *fnDict,
9484 StringDict *exclDict,
9486 QStrList *exclPatList,
9487 StringList *resultList,
9488 StringDict *resultDict,
9489 bool errorIfNotExist,
9491 QDict<void> *killDict,
9495 QCString dirName = fi->absFilePath().utf8();
9496 if (paths && paths->find(dirName)==0)
9498 paths->insert(dirName,(void*)0x8);
9500 if (fi->isSymLink())
9502 dirName = resolveSymlink(dirName.data());
9503 if (dirName.isEmpty()) return 0; // recusive symlink
9504 if (g_pathsVisited.find(dirName)) return 0; // already visited path
9505 g_pathsVisited.insert(dirName,(void*)0x8);
9508 dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
9510 msg("Searching for files in directory %s\n", fi->absFilePath().data());
9511 //printf("killDict=%p count=%d\n",killDict,killDict->count());
9513 const QFileInfoList *list = dir.entryInfoList();
9516 QFileInfoListIterator it( *list );
9519 while ((cfi=it.current()))
9521 if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0)
9522 { // file should not be excluded
9523 //printf("killDict->find(%s)\n",cfi->absFilePath().data());
9524 if (!cfi->exists() || !cfi->isReadable())
9526 if (errorIfNotExist)
9528 warn_uncond("source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
9531 else if (cfi->isFile() &&
9532 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
9533 (patList==0 || patternMatch(*cfi,patList)) &&
9534 !patternMatch(*cfi,exclPatList) &&
9535 (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
9538 totalSize+=cfi->size()+cfi->absFilePath().length()+4;
9539 QCString name=cfi->fileName().utf8();
9540 //printf("New file %s\n",name.data());
9543 FileDef *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
9545 if (!name.isEmpty() && (fn=(*fnDict)[name]))
9551 fn = new FileName(cfi->absFilePath().utf8(),name);
9553 if (fnList) fnList->inSort(fn);
9554 fnDict->insert(name,fn);
9558 if (resultList || resultDict)
9560 rs=new QCString(cfi->absFilePath().utf8());
9562 if (resultList) resultList->append(rs);
9563 if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
9564 if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
9566 else if (recursive &&
9567 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
9569 !patternMatch(*cfi,exclPatList) &&
9570 cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
9572 cfi->setFile(cfi->absFilePath());
9573 totalSize+=readDir(cfi,fnList,fnDict,exclDict,
9574 patList,exclPatList,resultList,resultDict,errorIfNotExist,
9575 recursive,killDict,paths);
9585 //----------------------------------------------------------------------------
9586 // read a file or all files in a directory and append their contents to the
9587 // input string. The names of the files are appended to the `fiList' list.
9589 int readFileOrDirectory(const char *s,
9590 FileNameList *fnList,
9591 FileNameDict *fnDict,
9592 StringDict *exclDict,
9594 QStrList *exclPatList,
9595 StringList *resultList,
9596 StringDict *resultDict,
9598 bool errorIfNotExist,
9599 QDict<void> *killDict,
9603 //printf("killDict=%p count=%d\n",killDict,killDict->count());
9604 // strip trailing slashes
9607 char lc = fs.at(fs.length()-1);
9608 if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9611 //printf("readFileOrDirectory(%s)\n",s);
9614 if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9616 if (!fi.exists() || !fi.isReadable())
9618 if (errorIfNotExist)
9620 warn_uncond("source %s is not a readable file or directory... skipping.\n",s);
9623 else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
9627 QCString dirPath = fi.dirPath(TRUE).utf8();
9628 QCString filePath = fi.absFilePath().utf8();
9629 if (paths && paths->find(dirPath))
9631 paths->insert(dirPath,(void*)0x8);
9633 //printf("killDict->find(%s)\n",fi.absFilePath().data());
9634 if (killDict==0 || killDict->find(filePath)==0)
9636 totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input);
9637 //fiList->inSort(new FileInfo(fi));
9638 QCString name=fi.fileName().utf8();
9639 //printf("New file %s\n",name.data());
9642 FileDef *fd=new FileDef(dirPath+"/",name);
9644 if (!name.isEmpty() && (fn=(*fnDict)[name]))
9650 fn = new FileName(filePath,name);
9652 if (fnList) fnList->inSort(fn);
9653 fnDict->insert(name,fn);
9657 if (resultList || resultDict)
9659 rs=new QCString(filePath);
9660 if (resultList) resultList->append(rs);
9661 if (resultDict) resultDict->insert(filePath,rs);
9664 if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9667 else if (fi.isDir()) // readable dir
9669 totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9670 exclPatList,resultList,resultDict,errorIfNotExist,
9671 recursive,killDict,paths);
9679 //----------------------------------------------------------------------------
9681 void readFormulaRepository()
9683 QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
9684 if (f.open(IO_ReadOnly)) // open repository
9686 msg("Reading formula repository...\n");
9691 line=t.readLine().utf8();
9692 int se=line.find(':'); // find name and text separator.
9695 warn_uncond("formula.repository is corrupted!\n");
9700 QCString formName = line.left(se);
9701 QCString formText = line.right(line.length()-se-1);
9702 Formula *f=new Formula(formText);
9703 Doxygen::formulaList->setAutoDelete(TRUE);
9704 Doxygen::formulaList->append(f);
9705 Doxygen::formulaDict->insert(formText,f);
9706 Doxygen::formulaNameDict->insert(formName,f);
9712 //----------------------------------------------------------------------------
9714 static void expandAliases()
9716 QDictIterator<QCString> adi(Doxygen::aliasDict);
9718 for (adi.toFirst();(s=adi.current());++adi)
9720 *s = expandAlias(adi.currentKey(),*s);
9724 //----------------------------------------------------------------------------
9726 static void escapeAliases()
9728 QDictIterator<QCString> adi(Doxygen::aliasDict);
9730 for (adi.toFirst();(s=adi.current());++adi)
9732 QCString value=*s,newValue;
9734 // for each \n in the alias command value
9735 while ((in=value.find("\\n",p))!=-1)
9737 newValue+=value.mid(p,in-p);
9738 // expand \n's except if \n is part of a built-in command.
9739 if (value.mid(in,5)!="\\note" &&
9740 value.mid(in,5)!="\\name" &&
9741 value.mid(in,10)!="\\namespace" &&
9742 value.mid(in,14)!="\\nosubgrouping"
9745 newValue+="\\_linebr ";
9753 newValue+=value.mid(p,value.length()-p);
9755 //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9759 //----------------------------------------------------------------------------
9763 // add aliases to a dictionary
9764 Doxygen::aliasDict.setAutoDelete(TRUE);
9765 QStrList &aliasList = Config_getList("ALIASES");
9766 const char *s=aliasList.first();
9769 if (Doxygen::aliasDict[s]==0)
9772 int i=alias.find('=');
9775 QCString name=alias.left(i).stripWhiteSpace();
9776 QCString value=alias.right(alias.length()-i-1);
9777 //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
9778 if (!name.isEmpty())
9780 QCString *dn=Doxygen::aliasDict[name];
9781 if (dn==0) // insert new alias
9783 Doxygen::aliasDict.insert(name,new QCString(value));
9785 else // overwrite previous alias
9798 //----------------------------------------------------------------------------
9800 static void dumpSymbol(FTextStream &t,Definition *d)
9803 if (d->definitionType()==Definition::TypeMember)
9805 MemberDef *md = (MemberDef *)d;
9806 anchor=":"+md->anchor();
9809 if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope)
9811 scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
9813 t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9814 << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9816 << d->name() << "','"
9817 << d->getDefFileName() << "','"
9822 static void dumpSymbolMap()
9824 QFile f("symbols.sql");
9825 if (f.open(IO_WriteOnly))
9828 QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9829 DefinitionIntf *intf;
9830 for (;(intf=di.current());++di)
9832 if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9834 DefinitionListIterator dli(*(DefinitionList*)intf);
9837 for (dli.toFirst();(d=dli.current());++dli)
9842 else // single symbol
9844 Definition *d = (Definition *)intf;
9845 if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9851 // print developer options of doxygen
9852 static void devUsage()
9854 msg("Developer parameters:\n");
9855 msg(" -m dump symbol map\n");
9856 msg(" -b output to wizard\n");
9857 msg(" -T activates output generation via Django like template\n");
9858 msg(" -d <level> enable a debug level, such as (multiple invocations of -d are possible):\n");
9859 Debug::printFlags();
9863 //----------------------------------------------------------------------------
9864 // print the usage of doxygen
9866 static void usage(const char *name)
9868 msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2014\n\n",versionString);
9869 msg("You can use doxygen in a number of ways:\n\n");
9870 msg("1) Use doxygen to generate a template configuration file:\n");
9871 msg(" %s [-s] -g [configName]\n\n",name);
9872 msg(" If - is used for configName doxygen will write to standard output.\n\n");
9873 msg("2) Use doxygen to update an old configuration file:\n");
9874 msg(" %s [-s] -u [configName]\n\n",name);
9875 msg("3) Use doxygen to generate documentation using an existing ");
9876 msg("configuration file:\n");
9877 msg(" %s [configName]\n\n",name);
9878 msg(" If - is used for configName doxygen will read from standard input.\n\n");
9879 msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9880 msg(" generated documentation:\n");
9881 msg(" %s -l layoutFileName.xml\n\n",name);
9882 msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9883 msg(" RTF: %s -w rtf styleSheetFile\n",name);
9884 msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9885 msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9886 msg("6) Use doxygen to generate a rtf extensions file\n");
9887 msg(" RTF: %s -e rtf extensionsFile\n\n",name);
9888 msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
9889 msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9890 msg("-v print version string\n");
9893 //----------------------------------------------------------------------------
9894 // read the argument of option `c' from the comment argument list and
9895 // update the option index `optind'.
9897 static const char *getArg(int argc,char **argv,int &optind)
9900 if (qstrlen(&argv[optind][2])>0)
9902 else if (optind+1<argc && argv[optind+1][0]!='-')
9907 //----------------------------------------------------------------------------
9911 const char *lang = portable_getenv("LC_ALL");
9912 if (lang) portable_setenv("LANG",lang);
9913 setlocale(LC_ALL,"");
9914 setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
9915 setlocale(LC_NUMERIC,"C");
9917 Doxygen::runningTime.start();
9920 Doxygen::parserManager = new ParserManager;
9921 Doxygen::parserManager->registerDefaultParser( new FileParser);
9922 Doxygen::parserManager->registerParser("c", new CLanguageScanner);
9923 Doxygen::parserManager->registerParser("python", new PythonLanguageScanner);
9924 Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
9925 Doxygen::parserManager->registerParser("fortranfree", new FortranLanguageScannerFree);
9926 Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed);
9927 Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner);
9928 Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
9929 Doxygen::parserManager->registerParser("tcl", new TclLanguageScanner);
9930 Doxygen::parserManager->registerParser("md", new MarkdownFileParser);
9932 // register any additional parsers here...
9934 initDefaultExtensionMapping();
9935 initClassMemberIndices();
9936 initNamespaceMemberIndices();
9937 initFileMemberIndices();
9939 Doxygen::symbolMap = new QDict<DefinitionIntf>(50177);
9941 Doxygen::clangUsrMap = new QDict<Definition>(50177);
9943 Doxygen::inputNameList = new FileNameList;
9944 Doxygen::inputNameList->setAutoDelete(TRUE);
9945 Doxygen::memberNameSDict = new MemberNameSDict(10000);
9946 Doxygen::memberNameSDict->setAutoDelete(TRUE);
9947 Doxygen::functionNameSDict = new MemberNameSDict(10000);
9948 Doxygen::functionNameSDict->setAutoDelete(TRUE);
9949 Doxygen::groupSDict = new GroupSDict(17);
9950 Doxygen::groupSDict->setAutoDelete(TRUE);
9951 Doxygen::globalScope = new NamespaceDef("<globalScope>",1,1,"<globalScope>");
9952 Doxygen::namespaceSDict = new NamespaceSDict(20);
9953 Doxygen::namespaceSDict->setAutoDelete(TRUE);
9954 Doxygen::classSDict = new ClassSDict(1009);
9955 Doxygen::classSDict->setAutoDelete(TRUE);
9956 Doxygen::hiddenClasses = new ClassSDict(257);
9957 Doxygen::hiddenClasses->setAutoDelete(TRUE);
9958 Doxygen::directories = new DirSDict(17);
9959 Doxygen::directories->setAutoDelete(TRUE);
9960 Doxygen::pageSDict = new PageSDict(1009); // all doc pages
9961 Doxygen::pageSDict->setAutoDelete(TRUE);
9962 Doxygen::exampleSDict = new PageSDict(1009); // all examples
9963 Doxygen::exampleSDict->setAutoDelete(TRUE);
9964 Doxygen::inputNameDict = new FileNameDict(10007);
9965 Doxygen::includeNameDict = new FileNameDict(10007);
9966 Doxygen::exampleNameDict = new FileNameDict(1009);
9967 Doxygen::exampleNameDict->setAutoDelete(TRUE);
9968 Doxygen::imageNameDict = new FileNameDict(257);
9969 Doxygen::imageNameDict->setAutoDelete(TRUE);
9970 Doxygen::dotFileNameDict = new FileNameDict(257);
9971 Doxygen::mscFileNameDict = new FileNameDict(257);
9972 Doxygen::diaFileNameDict = new FileNameDict(257);
9973 Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
9974 Doxygen::tagDestinationDict.setAutoDelete(TRUE);
9975 Doxygen::dirRelations.setAutoDelete(TRUE);
9976 Doxygen::citeDict = new CiteDict(257);
9977 Doxygen::genericsDict = new GenericsSDict;
9978 Doxygen::indexList = new IndexList;
9979 Doxygen::formulaList = new FormulaList;
9980 Doxygen::formulaDict = new FormulaDict(1009);
9981 Doxygen::formulaNameDict = new FormulaDict(1009);
9982 Doxygen::sectionDict = new SectionDict(257);
9983 Doxygen::sectionDict->setAutoDelete(TRUE);
9985 /**************************************************************************
9986 * Initialize some global constants
9987 **************************************************************************/
9989 g_compoundKeywordDict.insert("template class",(void *)8);
9990 g_compoundKeywordDict.insert("template struct",(void *)8);
9991 g_compoundKeywordDict.insert("class",(void *)8);
9992 g_compoundKeywordDict.insert("struct",(void *)8);
9993 g_compoundKeywordDict.insert("union",(void *)8);
9994 g_compoundKeywordDict.insert("interface",(void *)8);
9995 g_compoundKeywordDict.insert("exception",(void *)8);
9999 void cleanUpDoxygen()
10001 delete Doxygen::sectionDict;
10002 delete Doxygen::formulaNameDict;
10003 delete Doxygen::formulaDict;
10004 delete Doxygen::formulaList;
10005 delete Doxygen::indexList;
10006 delete Doxygen::genericsDict;
10007 delete Doxygen::inputNameDict;
10008 delete Doxygen::includeNameDict;
10009 delete Doxygen::exampleNameDict;
10010 delete Doxygen::imageNameDict;
10011 delete Doxygen::dotFileNameDict;
10012 delete Doxygen::mscFileNameDict;
10013 delete Doxygen::diaFileNameDict;
10014 delete Doxygen::mainPage;
10015 delete Doxygen::pageSDict;
10016 delete Doxygen::exampleSDict;
10017 delete Doxygen::globalScope;
10018 delete Doxygen::xrefLists;
10019 delete Doxygen::parserManager;
10020 cleanUpPreprocessor();
10021 delete theTranslator;
10022 delete g_outputList;
10023 Mappers::freeMappers();
10026 if (Doxygen::symbolMap)
10028 // iterate through Doxygen::symbolMap and delete all
10029 // DefinitionList objects, since they have no owner
10030 QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
10031 DefinitionIntf *di;
10032 for (dli.toFirst();(di=dli.current());)
10034 if (di->definitionType()==DefinitionIntf::TypeSymbolList)
10036 DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
10037 delete (DefinitionList *)tmp;
10046 delete Doxygen::inputNameList;
10047 delete Doxygen::memberNameSDict;
10048 delete Doxygen::functionNameSDict;
10049 delete Doxygen::groupSDict;
10050 delete Doxygen::classSDict;
10051 delete Doxygen::hiddenClasses;
10052 delete Doxygen::namespaceSDict;
10053 delete Doxygen::directories;
10055 //delete Doxygen::symbolMap; <- we cannot do this unless all static lists
10056 // (such as Doxygen::namespaceSDict)
10057 // with objects based on Definition are made
10061 static int computeIdealCacheParam(uint v)
10063 //printf("computeIdealCacheParam(v=%u)\n",v);
10066 while (v!=0) v>>=1,r++;
10069 // convert to a valid cache size value
10070 return QMAX(0,QMIN(r-16,9));
10073 void readConfiguration(int argc, char **argv)
10075 /**************************************************************************
10076 * Handle arguments *
10077 **************************************************************************/
10080 const char *configName=0;
10081 const char *layoutName=0;
10082 const char *debugLabel;
10083 const char *formatName;
10084 bool genConfig=FALSE;
10085 bool shortList=FALSE;
10086 bool updateConfig=FALSE;
10087 bool genLayout=FALSE;
10089 while (optind<argc && argv[optind][0]=='-' &&
10090 (isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
10091 argv[optind][1]=='-')
10094 switch(argv[optind][1])
10098 configName=getArg(argc,argv,optind);
10099 if (optind+1<argc && qstrcmp(argv[optind+1],"-")==0)
10100 { configName="-"; optind++; }
10102 { configName="Doxyfile"; }
10106 layoutName=getArg(argc,argv,optind);
10108 { layoutName="DoxygenLayout.xml"; }
10111 debugLabel=getArg(argc,argv,optind);
10114 err("option \"-d\" is missing debug specifier.\n");
10119 retVal = Debug::setFlag(debugLabel);
10122 err("option \"-d\" has unknown debug specifier: \"%s\".\n",debugLabel);
10134 formatName=getArg(argc,argv,optind);
10137 err("option \"-e\" is missing format specifier rtf.\n");
10141 if (qstricmp(formatName,"rtf")==0)
10143 if (optind+1>=argc)
10145 err("option \"-e rtf\" is missing an extensions file name\n");
10150 if (openOutputFile(argv[optind+1],f))
10152 RTFGenerator::writeExtensionsFile(f);
10157 err("option \"-e\" has invalid format specifier.\n");
10162 formatName=getArg(argc,argv,optind);
10165 err("option \"-w\" is missing format specifier rtf, html or latex\n");
10169 if (qstricmp(formatName,"rtf")==0)
10171 if (optind+1>=argc)
10173 err("option \"-w rtf\" is missing a style sheet file name\n");
10178 if (openOutputFile(argv[optind+1],f))
10180 RTFGenerator::writeStyleSheetFile(f);
10185 else if (qstricmp(formatName,"html")==0)
10187 if (optind+4<argc || QFileInfo("Doxyfile").exists())
10189 QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10190 if (!Config::instance()->parse(df))
10192 err("error opening or reading configuration file %s!\n",argv[optind+4]);
10196 Config::instance()->substituteEnvironmentVars();
10197 Config::instance()->convertStrToVal();
10198 // avoid bootstrapping issues when the config file already
10199 // refers to the files that we are supposed to parse.
10200 Config_getString("HTML_HEADER")="";
10201 Config_getString("HTML_FOOTER")="";
10202 Config::instance()->check();
10206 Config::instance()->init();
10208 if (optind+3>=argc)
10210 err("option \"-w html\" does not have enough arguments\n");
10215 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10216 if (!setTranslator(outputLanguage))
10218 warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10222 if (openOutputFile(argv[optind+1],f))
10224 HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
10227 if (openOutputFile(argv[optind+2],f))
10229 HtmlGenerator::writeFooterFile(f);
10232 if (openOutputFile(argv[optind+3],f))
10234 HtmlGenerator::writeStyleSheetFile(f);
10239 else if (qstricmp(formatName,"latex")==0)
10241 if (optind+4<argc) // use config file to get settings
10243 if (!Config::instance()->parse(argv[optind+4]))
10245 err("error opening or reading configuration file %s!\n",argv[optind+4]);
10248 Config::instance()->substituteEnvironmentVars();
10249 Config::instance()->convertStrToVal();
10250 Config_getString("LATEX_HEADER")="";
10251 Config::instance()->check();
10253 else // use default config
10255 Config::instance()->init();
10257 if (optind+3>=argc)
10259 err("option \"-w latex\" does not have enough arguments\n");
10264 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10265 if (!setTranslator(outputLanguage))
10267 warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10271 if (openOutputFile(argv[optind+1],f))
10273 LatexGenerator::writeHeaderFile(f);
10276 if (openOutputFile(argv[optind+2],f))
10278 LatexGenerator::writeFooterFile(f);
10281 if (openOutputFile(argv[optind+3],f))
10283 LatexGenerator::writeStyleSheetFile(f);
10290 err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",formatName);
10296 g_dumpSymbolMap = TRUE;
10299 msg("%s\n",versionString);
10304 if (qstrcmp(&argv[optind][2],"help")==0)
10309 else if (qstrcmp(&argv[optind][2],"version")==0)
10311 msg("%s\n",versionString);
10317 err("Unknown option \"-%s\"\n",&argv[optind][1]);
10323 setvbuf(stdout,NULL,_IONBF,0);
10324 Doxygen::outputToWizard=TRUE;
10327 msg("Warning: this option activates output generation via Django like template files. "
10328 "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
10329 "Only use if you are a doxygen developer\n");
10330 g_useOutputTemplate=TRUE;
10338 err("Unknown option \"-%c\"\n",argv[optind][1]);
10345 /**************************************************************************
10346 * Parse or generate the config file *
10347 **************************************************************************/
10349 Config::instance()->init();
10353 generateConfigFile(configName,shortList);
10359 writeDefaultLayoutFile(layoutName);
10364 QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
10367 if (configFileInfo1.exists())
10369 configName="Doxyfile";
10371 else if (configFileInfo2.exists())
10373 configName="doxyfile";
10377 err("Doxyfile not found and no input file specified!\n");
10384 QFileInfo fi(argv[optind]);
10385 if (fi.exists() || qstrcmp(argv[optind],"-")==0)
10387 configName=argv[optind];
10391 err("configuration file %s not found!\n",argv[optind]);
10398 if (!Config::instance()->parse(configName,updateConfig))
10400 err("could not open or read configuration file %s!\n",configName);
10407 generateConfigFile(configName,shortList,TRUE);
10412 /* Perlmod wants to know the path to the config file.*/
10413 QFileInfo configFileInfo(configName);
10414 setPerlModDoxyfile(configFileInfo.absFilePath().data());
10418 /** check and resolve config options */
10419 void checkConfiguration()
10422 Config::instance()->substituteEnvironmentVars();
10423 Config::instance()->convertStrToVal();
10424 Config::instance()->check();
10426 initWarningFormat();
10429 /** adjust globals that depend on configuration settings. */
10430 void adjustConfiguration()
10432 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10433 if (!setTranslator(outputLanguage))
10435 warn_uncond("Output language %s not supported! Using English instead.\n",
10436 outputLanguage.data());
10438 QStrList &includePath = Config_getList("INCLUDE_PATH");
10439 char *s=includePath.first();
10443 addSearchDir(fi.absFilePath().utf8());
10444 s=includePath.next();
10447 /* Set the global html file extension. */
10448 Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
10451 Doxygen::xrefLists->setAutoDelete(TRUE);
10453 Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") ||
10454 Config_getBool("CALLER_GRAPH") ||
10455 Config_getBool("REFERENCES_RELATION") ||
10456 Config_getBool("REFERENCED_BY_RELATION");
10458 Doxygen::markdownSupport = Config_getBool("MARKDOWN_SUPPORT");
10460 /**************************************************************************
10461 * Add custom extension mappings
10462 **************************************************************************/
10464 QStrList &extMaps = Config_getList("EXTENSION_MAPPING");
10465 char *mapping = extMaps.first();
10468 QCString mapStr = mapping;
10470 if ((i=mapStr.find('='))!=-1)
10472 QCString ext=mapStr.left(i).stripWhiteSpace().lower();
10473 QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
10474 if (!updateLanguageMapping(ext,language))
10476 err("Failed to map file extension '%s' to unsupported language '%s'.\n"
10477 "Check the EXTENSION_MAPPING setting in the config file.\n",
10478 ext.data(),language.data());
10482 msg("Adding custom extension mapping: .%s will be treated as language %s\n",
10483 ext.data(),language.data());
10486 mapping = extMaps.next();
10490 // add predefined macro name to a dictionary
10491 QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
10492 s=expandAsDefinedList.first();
10495 if (Doxygen::expandAsDefinedDict[s]==0)
10497 Doxygen::expandAsDefinedDict.insert(s,(void *)666);
10499 s=expandAsDefinedList.next();
10502 // read aliases and store them in a dictionary
10505 // store number of spaces in a tab into Doxygen::spaces
10506 int &tabSize = Config_getInt("TAB_SIZE");
10507 Doxygen::spaces.resize(tabSize+1);
10508 int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
10509 Doxygen::spaces.at(tabSize)='\0';
10513 static void stopDoxygen(int)
10516 msg("Cleaning up...\n");
10517 if (!Doxygen::entryDBFileName.isEmpty())
10519 thisDir.remove(Doxygen::entryDBFileName);
10521 if (!Doxygen::objDBFileName.isEmpty())
10523 thisDir.remove(Doxygen::objDBFileName);
10530 static void exitDoxygen()
10532 if (!g_successfulRun) // premature exit
10535 msg("Exiting...\n");
10536 if (!Doxygen::entryDBFileName.isEmpty())
10538 thisDir.remove(Doxygen::entryDBFileName);
10540 if (!Doxygen::objDBFileName.isEmpty())
10542 thisDir.remove(Doxygen::objDBFileName);
10547 static QCString createOutputDirectory(const QCString &baseDirName,
10548 const char *formatDirOption,
10549 const char *defaultDirName)
10551 // Note the & on the next line, we modify the formatDirOption!
10552 QCString &formatDirName = Config_getString(formatDirOption);
10553 if (formatDirName.isEmpty())
10555 formatDirName = baseDirName + defaultDirName;
10557 else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
10559 formatDirName.prepend(baseDirName+'/');
10561 QDir formatDir(formatDirName);
10562 if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
10564 err("Could not create output directory %s\n", formatDirName.data());
10568 return formatDirName;
10571 static QCString getQchFileName()
10573 QCString const & qchFile = Config_getString("QCH_FILE");
10574 if (!qchFile.isEmpty())
10579 QCString const & projectName = Config_getString("PROJECT_NAME");
10580 QCString const & versionText = Config_getString("PROJECT_NUMBER");
10582 return QCString("../qch/")
10583 + (projectName.isEmpty() ? QCString("index") : projectName)
10584 + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
10585 + QCString(".qch");
10588 void searchInputFiles()
10590 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10591 bool alwaysRecursive = Config_getBool("RECURSIVE");
10592 StringDict excludeNameDict(1009);
10593 excludeNameDict.setAutoDelete(TRUE);
10595 // gather names of all files in the include path
10596 g_s.begin("Searching for include files...\n");
10597 QStrList &includePathList = Config_getList("INCLUDE_PATH");
10598 char *s=includePathList.first();
10601 QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
10604 pl = Config_getList("FILE_PATTERNS");
10606 readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
10609 s=includePathList.next();
10613 g_s.begin("Searching for example files...\n");
10614 QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
10615 s=examplePathList.first();
10618 readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
10619 &Config_getList("EXAMPLE_PATTERNS"),
10621 (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
10622 s=examplePathList.next();
10626 g_s.begin("Searching for images...\n");
10627 QStrList &imagePathList=Config_getList("IMAGE_PATH");
10628 s=imagePathList.first();
10631 readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
10634 s=imagePathList.next();
10638 g_s.begin("Searching for dot files...\n");
10639 QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
10640 s=dotFileList.first();
10643 readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
10646 s=dotFileList.next();
10650 g_s.begin("Searching for msc files...\n");
10651 QStrList &mscFileList=Config_getList("MSCFILE_DIRS");
10652 s=mscFileList.first();
10655 readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
10658 s=mscFileList.next();
10662 g_s.begin("Searching for dia files...\n");
10663 QStrList &diaFileList=Config_getList("DIAFILE_DIRS");
10664 s=diaFileList.first();
10667 readFileOrDirectory(s,0,Doxygen::diaFileNameDict,0,0,
10670 s=diaFileList.next();
10674 g_s.begin("Searching for files to exclude\n");
10675 QStrList &excludeList = Config_getList("EXCLUDE");
10676 s=excludeList.first();
10679 readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
10680 0,0,&excludeNameDict,
10683 s=excludeList.next();
10687 /**************************************************************************
10688 * Determine Input Files *
10689 **************************************************************************/
10691 g_s.begin("Searching for files to process...\n");
10692 QDict<void> *killDict = new QDict<void>(10007);
10694 QStrList &inputList=Config_getList("INPUT");
10695 g_inputFiles.setAutoDelete(TRUE);
10696 s=inputList.first();
10700 uint l = path.length();
10703 // strip trailing slashes
10704 if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
10706 inputSize+=readFileOrDirectory(
10708 Doxygen::inputNameList,
10709 Doxygen::inputNameDict,
10711 &Config_getList("FILE_PATTERNS"),
10717 &Doxygen::inputPaths);
10719 s=inputList.next();
10728 atexit(exitDoxygen);
10731 /**************************************************************************
10732 * Make sure the output directory exists
10733 **************************************************************************/
10734 QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
10735 if (outputDirectory.isEmpty())
10737 outputDirectory=QDir::currentDirPath().utf8();
10741 QDir dir(outputDirectory);
10744 dir.setPath(QDir::currentDirPath());
10745 if (!dir.mkdir(outputDirectory))
10747 err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
10748 "exist and cannot be created\n",outputDirectory.data());
10754 msg("Notice: Output directory `%s' does not exist. "
10755 "I have created it for you.\n", outputDirectory.data());
10757 dir.cd(outputDirectory);
10759 outputDirectory=dir.absPath().utf8();
10762 /**************************************************************************
10763 * Initialize global lists and dictionaries
10764 **************************************************************************/
10766 Doxygen::symbolStorage = new Store;
10768 // also scale lookup cache with SYMBOL_CACHE_SIZE
10769 int cacheSize = Config_getInt("LOOKUP_CACHE_SIZE");
10770 if (cacheSize<0) cacheSize=0;
10771 if (cacheSize>9) cacheSize=9;
10772 uint lookupSize = 65536 << cacheSize;
10773 Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
10774 Doxygen::lookupCache->setAutoDelete(TRUE);
10777 signal(SIGINT, stopDoxygen);
10780 uint pid = portable_pid();
10781 Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10782 Doxygen::objDBFileName.prepend(outputDirectory+"/");
10783 Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10784 Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10786 if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10788 err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10794 /**************************************************************************
10795 * Check/create output directorties *
10796 **************************************************************************/
10798 QCString htmlOutput;
10799 bool &generateHtml = Config_getBool("GENERATE_HTML");
10801 htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");
10803 QCString docbookOutput;
10804 bool &generateDocbook = Config_getBool("GENERATE_DOCBOOK");
10805 if (generateDocbook)
10806 docbookOutput = createOutputDirectory(outputDirectory,"DOCBOOK_OUTPUT","/docbook");
10808 QCString xmlOutput;
10809 bool &generateXml = Config_getBool("GENERATE_XML");
10811 xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");
10813 QCString latexOutput;
10814 bool &generateLatex = Config_getBool("GENERATE_LATEX");
10816 latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");
10818 QCString rtfOutput;
10819 bool &generateRtf = Config_getBool("GENERATE_RTF");
10821 rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");
10823 QCString manOutput;
10824 bool &generateMan = Config_getBool("GENERATE_MAN");
10826 manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");
10828 //QCString sqlOutput;
10829 //bool &generateSql = Config_getBool("GENERATE_SQLITE3");
10831 // sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3");
10833 if (Config_getBool("HAVE_DOT"))
10835 QCString curFontPath = Config_getString("DOT_FONTPATH");
10836 if (curFontPath.isEmpty())
10838 portable_getenv("DOTFONTPATH");
10839 QCString newFontPath = ".";
10840 if (!curFontPath.isEmpty())
10842 newFontPath+=portable_pathListSeparator();
10843 newFontPath+=curFontPath;
10845 portable_setenv("DOTFONTPATH",newFontPath);
10849 portable_setenv("DOTFONTPATH",curFontPath);
10855 /**************************************************************************
10856 * Handle layout file *
10857 **************************************************************************/
10859 LayoutDocManager::instance().init();
10860 QCString &layoutFileName = Config_getString("LAYOUT_FILE");
10861 bool defaultLayoutUsed = FALSE;
10862 if (layoutFileName.isEmpty())
10864 layoutFileName = "DoxygenLayout.xml";
10865 defaultLayoutUsed = TRUE;
10868 QFile layoutFile(layoutFileName);
10869 if (layoutFile.open(IO_ReadOnly))
10871 msg("Parsing layout file %s...\n",layoutFileName.data());
10872 QTextStream t(&layoutFile);
10873 t.setEncoding(QTextStream::Latin1);
10874 LayoutDocManager::instance().parse(t,layoutFileName);
10876 else if (!defaultLayoutUsed)
10878 warn_uncond("failed to open layout file '%s' for reading!\n",layoutFileName.data());
10881 /**************************************************************************
10882 * Read and preprocess input *
10883 **************************************************************************/
10885 // prevent search in the output directories
10886 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10887 if (generateHtml) exclPatterns.append(htmlOutput);
10888 if (generateDocbook) exclPatterns.append(docbookOutput);
10889 if (generateXml) exclPatterns.append(xmlOutput);
10890 if (generateLatex) exclPatterns.append(latexOutput);
10891 if (generateRtf) exclPatterns.append(rtfOutput);
10892 if (generateMan) exclPatterns.append(manOutput);
10894 searchInputFiles();
10896 // Notice: the order of the function calls below is very important!
10898 if (Config_getBool("GENERATE_HTML"))
10900 readFormulaRepository();
10903 /**************************************************************************
10904 * Handle Tag Files *
10905 **************************************************************************/
10907 g_storage = new FileStorage;
10908 g_storage->setName(Doxygen::entryDBFileName);
10909 if (!g_storage->open(IO_WriteOnly))
10911 err("Failed to create temporary storage file %s\n",
10912 Doxygen::entryDBFileName.data());
10915 Entry *root=new Entry;
10916 EntryNav *rootNav = new EntryNav(0,root);
10917 rootNav->setEntry(root);
10918 msg("Reading and parsing tag files\n");
10920 QStrList &tagFileList = Config_getList("TAGFILES");
10921 char *s=tagFileList.first();
10924 readTagFile(root,s);
10925 root->createNavigationIndex(rootNav,g_storage,0);
10926 s=tagFileList.next();
10929 /**************************************************************************
10930 * Parse source files *
10931 **************************************************************************/
10933 if (Config_getBool("BUILTIN_STL_SUPPORT"))
10935 addSTLClasses(rootNav);
10938 g_s.begin("Parsing files\n");
10939 parseFiles(root,rootNav);
10940 g_storage->close();
10943 // we are done with input scanning now, so free up the buffers used by flex
10944 // (can be around 4MB)
10947 pyscanFreeScanner();
10949 if (!g_storage->open(IO_ReadOnly))
10951 err("Failed to open temporary storage file %s for reading",
10952 Doxygen::entryDBFileName.data());
10956 /**************************************************************************
10957 * Gather information *
10958 **************************************************************************/
10960 g_s.begin("Building group list...\n");
10961 buildGroupList(rootNav);
10962 organizeSubGroups(rootNav);
10965 g_s.begin("Building directory list...\n");
10966 buildDirectories();
10967 findDirDocumentation(rootNav);
10970 g_s.begin("Building namespace list...\n");
10971 buildNamespaceList(rootNav);
10972 findUsingDirectives(rootNav);
10975 g_s.begin("Building file list...\n");
10976 buildFileList(rootNav);
10978 //generateFileTree();
10980 g_s.begin("Building class list...\n");
10981 buildClassList(rootNav);
10984 g_s.begin("Associating documentation with classes...\n");
10985 buildClassDocList(rootNav);
10987 // build list of using declarations here (global list)
10988 buildListOfUsingDecls(rootNav);
10991 g_s.begin("Computing nesting relations for classes...\n");
10992 resolveClassNestingRelations();
10994 // 1.8.2-20121111: no longer add nested classes to the group as well
10995 //distributeClassGroupRelations();
10997 // calling buildClassList may result in cached relations that
10998 // become invalid after resolveClassNestingRelations(), that's why
10999 // we need to clear the cache here
11000 Doxygen::lookupCache->clear();
11001 // we don't need the list of using declaration anymore
11002 g_usingDeclarations.clear();
11004 g_s.begin("Building example list...\n");
11005 buildExampleList(rootNav);
11008 g_s.begin("Searching for enumerations...\n");
11009 findEnums(rootNav);
11012 // Since buildVarList calls isVarWithConstructor
11013 // and this calls getResolvedClass we need to process
11014 // typedefs first so the relations between classes via typedefs
11015 // are properly resolved. See bug 536385 for an example.
11016 g_s.begin("Searching for documented typedefs...\n");
11017 buildTypedefList(rootNav);
11020 g_s.begin("Searching for members imported via using declarations...\n");
11021 findUsingDeclImports(rootNav);
11022 // this should be after buildTypedefList in order to properly import
11024 findUsingDeclarations(rootNav);
11027 g_s.begin("Searching for included using directives...\n");
11028 findIncludedUsingDirectives();
11031 g_s.begin("Searching for documented variables...\n");
11032 buildVarList(rootNav);
11035 g_s.begin("Building interface member list...\n");
11036 buildInterfaceAndServiceList(rootNav); // UNO IDL
11038 g_s.begin("Building member list...\n"); // using class info only !
11039 buildFunctionList(rootNav);
11042 g_s.begin("Searching for friends...\n");
11046 g_s.begin("Searching for documented defines...\n");
11047 findDefineDocumentation(rootNav);
11050 g_s.begin("Computing class inheritance relations...\n");
11051 findClassEntries(rootNav);
11052 findInheritedTemplateInstances();
11055 g_s.begin("Computing class usage relations...\n");
11056 findUsedTemplateInstances();
11059 if (Config_getBool("INLINE_SIMPLE_STRUCTS"))
11061 g_s.begin("Searching for tag less structs...\n");
11062 findTagLessClasses();
11066 g_s.begin("Flushing cached template relations that have become invalid...\n");
11067 flushCachedTemplateRelations();
11070 g_s.begin("Creating members for template instances...\n");
11071 createTemplateInstanceMembers();
11074 g_s.begin("Computing class relations...\n");
11075 computeTemplateClassRelations();
11076 flushUnresolvedRelations();
11077 if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
11079 VhdlDocGen::computeVhdlComponentRelations();
11081 computeClassRelations();
11082 g_classEntries.clear();
11085 g_s.begin("Add enum values to enums...\n");
11086 addEnumValuesToEnums(rootNav);
11087 findEnumDocumentation(rootNav);
11090 g_s.begin("Searching for member function documentation...\n");
11091 findObjCMethodDefinitions(rootNav);
11092 findMemberDocumentation(rootNav); // may introduce new members !
11094 transferRelatedFunctionDocumentation();
11095 transferFunctionDocumentation();
11098 g_s.begin("Building page list...\n");
11099 buildPageList(rootNav);
11102 g_s.begin("Search for main page...\n");
11103 findMainPage(rootNav);
11104 findMainPageTagFiles(rootNav);
11107 g_s.begin("Computing page relations...\n");
11108 computePageRelations(rootNav);
11109 checkPageRelations();
11112 g_s.begin("Determining the scope of groups...\n");
11113 findGroupScope(rootNav);
11116 g_s.begin("Sorting lists...\n");
11117 Doxygen::memberNameSDict->sort();
11118 Doxygen::functionNameSDict->sort();
11119 Doxygen::hiddenClasses->sort();
11120 Doxygen::classSDict->sort();
11123 msg("Freeing entry tree\n");
11125 g_storage->close();
11130 thisDir.remove(Doxygen::entryDBFileName);
11132 g_s.begin("Determining which enums are documented\n");
11133 findDocumentedEnumValues();
11136 g_s.begin("Computing member relations...\n");
11138 computeMemberRelations();
11141 g_s.begin("Building full member lists recursively...\n");
11142 buildCompleteMemberLists();
11145 g_s.begin("Adding members to member groups.\n");
11146 addMembersToMemberGroup();
11149 if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
11151 g_s.begin("Distributing member group documentation.\n");
11152 distributeMemberGroupDocumentation();
11156 g_s.begin("Computing member references...\n");
11157 computeMemberReferences();
11160 if (Config_getBool("INHERIT_DOCS"))
11162 g_s.begin("Inheriting documentation...\n");
11163 inheritDocumentation();
11167 // compute the shortest possible names of all files
11168 // without losing the uniqueness of the file names.
11169 g_s.begin("Generating disk names...\n");
11170 Doxygen::inputNameList->generateDiskNames();
11173 g_s.begin("Adding source references...\n");
11174 addSourceReferences();
11177 g_s.begin("Adding xrefitems...\n");
11178 addListReferences();
11179 generateXRefPages();
11182 g_s.begin("Sorting member lists...\n");
11186 if (Config_getBool("DIRECTORY_GRAPH"))
11188 g_s.begin("Computing dependencies between directories...\n");
11189 computeDirDependencies();
11193 //g_s.begin("Resolving citations...\n");
11194 //Doxygen::citeDict->resolve();
11196 g_s.begin("Generating citations page...\n");
11197 Doxygen::citeDict->generatePage();
11200 g_s.begin("Counting data structures...\n");
11201 countDataStructures();
11204 g_s.begin("Resolving user defined references...\n");
11205 resolveUserReferences();
11208 g_s.begin("Finding anchors and sections in the documentation...\n");
11209 findSectionsInDocumentation();
11212 g_s.begin("Transferring function references...\n");
11213 transferFunctionReferences();
11216 g_s.begin("Combining using relations...\n");
11217 combineUsingRelations();
11220 g_s.begin("Adding members to index pages...\n");
11221 addMembersToIndex();
11225 void generateOutput()
11227 /**************************************************************************
11228 * Initialize output generators *
11229 **************************************************************************/
11231 //// dump all symbols
11232 if (g_dumpSymbolMap)
11238 initSearchIndexer();
11240 bool generateHtml = Config_getBool("GENERATE_HTML");
11241 bool generateLatex = Config_getBool("GENERATE_LATEX");
11242 bool generateMan = Config_getBool("GENERATE_MAN");
11243 bool generateRtf = Config_getBool("GENERATE_RTF");
11246 g_outputList = new OutputList(TRUE);
11249 g_outputList->add(new HtmlGenerator);
11250 HtmlGenerator::init();
11252 // add HTML indexers that are enabled
11253 bool generateHtmlHelp = Config_getBool("GENERATE_HTMLHELP");
11254 bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");
11255 bool generateQhp = Config_getBool("GENERATE_QHP");
11256 bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
11257 bool generateDocSet = Config_getBool("GENERATE_DOCSET");
11258 if (generateEclipseHelp) Doxygen::indexList->addIndex(new EclipseHelp);
11259 if (generateHtmlHelp) Doxygen::indexList->addIndex(new HtmlHelp);
11260 if (generateQhp) Doxygen::indexList->addIndex(new Qhp);
11261 if (generateTreeView) Doxygen::indexList->addIndex(new FTVHelp(TRUE));
11262 if (generateDocSet) Doxygen::indexList->addIndex(new DocSets);
11263 Doxygen::indexList->initialize();
11264 HtmlGenerator::writeTabData();
11266 // copy static stuff
11269 copyExtraFiles("HTML_EXTRA_FILES","HTML_OUTPUT");
11270 FTVHelp::generateTreeViewImages();
11274 g_outputList->add(new LatexGenerator);
11275 LatexGenerator::init();
11277 // copy static stuff
11278 copyExtraFiles("LATEX_EXTRA_FILES","LATEX_OUTPUT");
11282 g_outputList->add(new ManGenerator);
11283 ManGenerator::init();
11287 g_outputList->add(new RTFGenerator);
11288 RTFGenerator::init();
11290 if (Config_getBool("USE_HTAGS"))
11292 Htags::useHtags = TRUE;
11293 QCString htmldir = Config_getString("HTML_OUTPUT");
11294 if (!Htags::execute(htmldir))
11295 err("USE_HTAGS is YES but htags(1) failed. \n");
11296 if (!Htags::loadFilemap(htmldir))
11297 err("htags(1) ended normally but failed to load the filemap. \n");
11300 /**************************************************************************
11301 * Generate documentation *
11302 **************************************************************************/
11305 QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
11306 if (!generateTagFile.isEmpty())
11308 tag=new QFile(generateTagFile);
11309 if (!tag->open(IO_WriteOnly))
11311 err("cannot open tag file %s for writing\n",
11312 generateTagFile.data()
11317 Doxygen::tagFile.setDevice(tag);
11318 Doxygen::tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
11319 Doxygen::tagFile << "<tagfile>" << endl;
11322 if (generateHtml) writeDoxFont(Config_getString("HTML_OUTPUT"));
11323 if (generateLatex) writeDoxFont(Config_getString("LATEX_OUTPUT"));
11324 if (generateRtf) writeDoxFont(Config_getString("RTF_OUTPUT"));
11326 g_s.begin("Generating style sheet...\n");
11327 //printf("writing style info\n");
11328 g_outputList->writeStyleInfo(0); // write first part
11331 static bool searchEngine = Config_getBool("SEARCHENGINE");
11332 static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
11334 // generate search indices (need to do this before writing other HTML
11335 // pages as these contain a drop down menu with options depending on
11336 // what categories we find in this function.
11337 if (generateHtml && searchEngine)
11339 g_s.begin("Generating search indices...\n");
11340 QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
11341 QDir searchDir(searchDirName);
11342 if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
11344 err("Could not create search results directory '%s' $PWD='%s'\n",
11345 searchDirName.data(),QDir::currentDirPath().data());
11348 HtmlGenerator::writeSearchData(searchDirName);
11349 if (!serverBasedSearch) // client side search index
11351 writeJavascriptSearchIndex();
11356 g_s.begin("Generating example documentation...\n");
11357 generateExampleDocs();
11360 if (!Htags::useHtags)
11362 g_s.begin("Generating file sources...\n");
11363 generateFileSources();
11367 g_s.begin("Generating file documentation...\n");
11368 generateFileDocs();
11371 g_s.begin("Generating page documentation...\n");
11372 generatePageDocs();
11375 g_s.begin("Generating group documentation...\n");
11376 generateGroupDocs();
11379 g_s.begin("Generating class documentation...\n");
11380 generateClassDocs();
11383 g_s.begin("Generating namespace index...\n");
11384 generateNamespaceDocs();
11387 if (Config_getBool("GENERATE_LEGEND"))
11389 g_s.begin("Generating graph info page...\n");
11390 writeGraphInfo(*g_outputList);
11394 g_s.begin("Generating directory documentation...\n");
11395 generateDirDocs(*g_outputList);
11398 if (Doxygen::formulaList->count()>0 && generateHtml
11399 && !Config_getBool("USE_MATHJAX"))
11401 g_s.begin("Generating bitmaps for formulas in HTML...\n");
11402 Doxygen::formulaList->generateBitmaps(Config_getString("HTML_OUTPUT"));
11406 if (Config_getBool("SORT_GROUP_NAMES"))
11408 Doxygen::groupSDict->sort();
11409 GroupSDict::Iterator gli(*Doxygen::groupSDict);
11411 for (gli.toFirst();(gd=gli.current());++gli)
11413 gd->sortSubGroups();
11417 writeMainPageTagFileData();
11419 if (g_outputList->count()>0)
11421 writeIndexHierarchy(*g_outputList);
11424 g_s.begin("finalizing index lists...\n");
11425 Doxygen::indexList->finalize();
11428 if (!generateTagFile.isEmpty())
11430 Doxygen::tagFile << "</tagfile>" << endl;
11434 if (Config_getBool("DOT_CLEANUP"))
11437 removeDoxFont(Config_getString("HTML_OUTPUT"));
11439 removeDoxFont(Config_getString("RTF_OUTPUT"));
11441 removeDoxFont(Config_getString("LATEX_OUTPUT"));
11444 if (Config_getBool("GENERATE_XML"))
11446 g_s.begin("Generating XML output...\n");
11447 Doxygen::generatingXmlOutput=TRUE;
11449 Doxygen::generatingXmlOutput=FALSE;
11454 g_s.begin("Generating SQLITE3 output...\n");
11459 if (Config_getBool("GENERATE_DOCBOOK"))
11461 g_s.begin("Generating Docbook output...\n");
11466 if (Config_getBool("GENERATE_AUTOGEN_DEF"))
11468 g_s.begin("Generating AutoGen DEF output...\n");
11472 if (Config_getBool("GENERATE_PERLMOD"))
11474 g_s.begin("Generating Perl module output...\n");
11478 if (generateHtml && searchEngine && serverBasedSearch)
11480 g_s.begin("Generating search index\n");
11481 if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
11483 HtmlGenerator::writeSearchPage();
11484 Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");
11486 else // write data for external search index
11488 HtmlGenerator::writeExternalSearchPage();
11489 QCString searchDataFile = Config_getString("SEARCHDATA_FILE");
11490 if (searchDataFile.isEmpty())
11492 searchDataFile="searchdata.xml";
11494 if (!portable_isAbsolutePath(searchDataFile))
11496 searchDataFile.prepend(Config_getString("OUTPUT_DIRECTORY")+"/");
11498 Doxygen::searchIndex->write(searchDataFile);
11503 if (g_useOutputTemplate) generateOutputViaTemplate();
11507 g_s.begin("Combining RTF output...\n");
11508 if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
11510 err("An error occurred during post-processing the RTF files!\n");
11515 if (Config_getBool("HAVE_DOT"))
11517 g_s.begin("Running dot...\n");
11518 DotManager::instance()->run();
11522 if (generateHtml &&
11523 Config_getBool("GENERATE_HTMLHELP") &&
11524 !Config_getString("HHC_LOCATION").isEmpty())
11526 g_s.begin("Running html help compiler...\n");
11527 QString oldDir = QDir::currentDirPath();
11528 QDir::setCurrent(Config_getString("HTML_OUTPUT"));
11529 portable_sysTimerStart();
11530 if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
11532 err("failed to run html help compiler on index.hhp\n");
11534 portable_sysTimerStop();
11535 QDir::setCurrent(oldDir);
11538 if ( generateHtml &&
11539 Config_getBool("GENERATE_QHP") &&
11540 !Config_getString("QHG_LOCATION").isEmpty())
11542 g_s.begin("Running qhelpgenerator...\n");
11543 QCString const qhpFileName = Qhp::getQhpFileName();
11544 QCString const qchFileName = getQchFileName();
11546 QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
11547 QString const oldDir = QDir::currentDirPath();
11548 QDir::setCurrent(Config_getString("HTML_OUTPUT"));
11549 portable_sysTimerStart();
11550 if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))
11552 err("failed to run qhelpgenerator on index.qhp\n");
11554 portable_sysTimerStop();
11555 QDir::setCurrent(oldDir);
11560 msg("lookup cache used %d/%d hits=%d misses=%d\n",
11561 Doxygen::lookupCache->count(),
11562 Doxygen::lookupCache->size(),
11563 Doxygen::lookupCache->hits(),
11564 Doxygen::lookupCache->misses());
11565 cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
11566 if (cacheParam>Config_getInt("LOOKUP_CACHE_SIZE"))
11568 msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
11571 if (Debug::isFlagSet(Debug::Time))
11573 msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
11574 ((double)Doxygen::runningTime.elapsed())/1000.0,
11575 portable_getSysElapsedTime()
11581 msg("finished...\n");
11585 /**************************************************************************
11586 * Start cleaning up *
11587 **************************************************************************/
11591 finializeSearchIndexer();
11592 Doxygen::symbolStorage->close();
11594 thisDir.remove(Doxygen::objDBFileName);
11595 Config::deleteInstance();
11596 QTextCodec::deleteAllCodecs();
11597 delete Doxygen::symbolMap;
11598 delete Doxygen::clangUsrMap;
11599 delete Doxygen::symbolStorage;
11600 g_successfulRun=TRUE;