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 "vhdlscanner.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"
102 #define RECURSE_ENTRYTREE(func,var) \
103 do { if (var->children()) { \
104 EntryNavListIterator eli(*var->children()); \
105 for (;eli.current();++eli) func(eli.current()); \
109 #if !defined(_WIN32) || defined(__CYGWIN__)
114 // globally accessible variables
115 ClassSDict *Doxygen::classSDict = 0;
116 ClassSDict *Doxygen::hiddenClasses = 0;
117 NamespaceSDict *Doxygen::namespaceSDict = 0;
118 MemberNameSDict *Doxygen::memberNameSDict = 0;
119 MemberNameSDict *Doxygen::functionNameSDict = 0;
120 FileNameList *Doxygen::inputNameList = 0; // all input files
121 FileNameDict *Doxygen::inputNameDict = 0;
122 GroupSDict *Doxygen::groupSDict = 0;
123 FormulaList *Doxygen::formulaList = 0; // all formulas
124 FormulaDict *Doxygen::formulaDict = 0; // all formulas
125 FormulaDict *Doxygen::formulaNameDict = 0; // the label name of all formulas
126 PageSDict *Doxygen::pageSDict = 0;
127 PageSDict *Doxygen::exampleSDict = 0;
128 SectionDict *Doxygen::sectionDict = 0; // all page sections
129 CiteDict *Doxygen::citeDict=0; // database of bibliographic references
130 StringDict Doxygen::aliasDict(257); // aliases
131 QDict<void> Doxygen::inputPaths(1009);
132 FileNameDict *Doxygen::includeNameDict = 0; // include names
133 FileNameDict *Doxygen::exampleNameDict = 0; // examples
134 FileNameDict *Doxygen::imageNameDict = 0; // images
135 FileNameDict *Doxygen::dotFileNameDict = 0; // dot files
136 FileNameDict *Doxygen::mscFileNameDict = 0; // msc files
137 FileNameDict *Doxygen::diaFileNameDict = 0; // dia files
138 StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases
139 StringDict Doxygen::tagDestinationDict(257); // all tag locations
140 QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
141 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
142 PageDef *Doxygen::mainPage = 0;
143 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
144 FTextStream Doxygen::tagFile;
145 NamespaceDef *Doxygen::globalScope = 0;
146 QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
147 bool Doxygen::parseSourcesNeeded = FALSE;
148 QTime Doxygen::runningTime;
149 SearchIndexIntf *Doxygen::searchIndex=0;
150 QDict<DefinitionIntf> *Doxygen::symbolMap = 0;
151 QDict<Definition> *Doxygen::clangUsrMap = 0;
152 bool Doxygen::outputToWizard=FALSE;
153 QDict<int> * Doxygen::htmlDirMap = 0;
154 QCache<LookupInfo> *Doxygen::lookupCache;
155 DirSDict *Doxygen::directories;
156 SDict<DirRelation> Doxygen::dirRelations(257);
157 ParserManager *Doxygen::parserManager = 0;
158 QCString Doxygen::htmlFileExtension;
159 bool Doxygen::suppressDocWarnings = FALSE;
160 Store *Doxygen::symbolStorage;
161 QCString Doxygen::objDBFileName;
162 QCString Doxygen::entryDBFileName;
163 bool Doxygen::gatherDefines = TRUE;
164 IndexList *Doxygen::indexList;
165 int Doxygen::subpageNestingLevel = 0;
166 bool Doxygen::userComments = FALSE;
167 QCString Doxygen::spaces;
168 bool Doxygen::generatingXmlOutput = FALSE;
169 bool Doxygen::markdownSupport = TRUE;
170 GenericsSDict *Doxygen::genericsDict;
172 // locally accessible globals
173 static QDict<EntryNav> g_classEntries(1009);
174 static StringList g_inputFiles;
175 static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds
176 static OutputList *g_outputList = 0; // list of output generating objects
177 static QDict<FileDef> g_usingDeclarations(1009); // used classes
178 static FileStorage *g_storage = 0;
179 static bool g_successfulRun = FALSE;
180 static bool g_dumpSymbolMap = FALSE;
181 static bool g_useOutputTemplate = FALSE;
185 g_inputFiles.clear();
186 //g_excludeNameDict.clear();
187 //delete g_outputList; g_outputList=0;
189 Doxygen::classSDict->clear();
190 Doxygen::namespaceSDict->clear();
191 Doxygen::pageSDict->clear();
192 Doxygen::exampleSDict->clear();
193 Doxygen::inputNameList->clear();
194 Doxygen::formulaList->clear();
195 Doxygen::sectionDict->clear();
196 Doxygen::inputNameDict->clear();
197 Doxygen::includeNameDict->clear();
198 Doxygen::exampleNameDict->clear();
199 Doxygen::imageNameDict->clear();
200 Doxygen::dotFileNameDict->clear();
201 Doxygen::mscFileNameDict->clear();
202 Doxygen::diaFileNameDict->clear();
203 Doxygen::formulaDict->clear();
204 Doxygen::formulaNameDict->clear();
205 Doxygen::tagDestinationDict.clear();
206 delete Doxygen::citeDict;
207 delete Doxygen::mainPage; Doxygen::mainPage=0;
213 Statistics() { stats.setAutoDelete(TRUE); }
214 void begin(const char *name)
217 stat *entry= new stat(name,0);
223 stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
228 if (Debug::isFlagSet(Debug::Time))
230 Debug::clearFlag("time");
233 msg("----------------------\n");
234 QListIterator<stat> sli(stats);
236 for ( sli.toFirst(); (s=sli.current()); ++sli )
238 msg("Spent %.3f seconds in %s",s->elapsed,s->name);
240 if (restore) Debug::setFlag("time");
247 stat() : name(NULL),elapsed(0) {}
248 stat(const char *n, double el) : name(n),elapsed(el) {}
257 fprintf(stderr,"--- inputNameDict stats ----\n");
258 Doxygen::inputNameDict->statistics();
259 fprintf(stderr,"--- includeNameDict stats ----\n");
260 Doxygen::includeNameDict->statistics();
261 fprintf(stderr,"--- exampleNameDict stats ----\n");
262 Doxygen::exampleNameDict->statistics();
263 fprintf(stderr,"--- imageNameDict stats ----\n");
264 Doxygen::imageNameDict->statistics();
265 fprintf(stderr,"--- dotFileNameDict stats ----\n");
266 Doxygen::dotFileNameDict->statistics();
267 fprintf(stderr,"--- mscFileNameDict stats ----\n");
268 Doxygen::mscFileNameDict->statistics();
269 fprintf(stderr,"--- diaFileNameDict stats ----\n");
270 Doxygen::diaFileNameDict->statistics();
271 //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
272 //g_excludeNameDict.statistics();
273 fprintf(stderr,"--- aliasDict stats ----\n");
274 Doxygen::aliasDict.statistics();
275 fprintf(stderr,"--- typedefDict stats ----\n");
276 fprintf(stderr,"--- namespaceAliasDict stats ----\n");
277 Doxygen::namespaceAliasDict.statistics();
278 fprintf(stderr,"--- formulaDict stats ----\n");
279 Doxygen::formulaDict->statistics();
280 fprintf(stderr,"--- formulaNameDict stats ----\n");
281 Doxygen::formulaNameDict->statistics();
282 fprintf(stderr,"--- tagDestinationDict stats ----\n");
283 Doxygen::tagDestinationDict.statistics();
284 fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
285 g_compoundKeywordDict.statistics();
286 fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
287 Doxygen::expandAsDefinedDict.statistics();
288 fprintf(stderr,"--- memGrpInfoDict stats ----\n");
289 Doxygen::memGrpInfoDict.statistics();
294 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
295 ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
296 static void findMember(EntryNav *rootNav,
302 enum FindBaseClassRelation_Mode
309 static bool findClassRelation(
314 QDict<int> *templateNames,
315 /*bool insertUndocumented*/
316 FindBaseClassRelation_Mode mode,
320 /** A struct contained the data for an STL class */
323 const char *className;
324 const char *baseClass1;
325 const char *baseClass2;
326 const char *templType1;
327 const char *templName1;
328 const char *templType2;
329 const char *templName2;
330 bool virtualInheritance;
334 static STLInfo g_stlinfo[] =
336 // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators
337 { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
338 { "array", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, // C++11
339 { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // deprecated
340 { "smart_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
341 { "unique_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
342 { "weak_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
343 { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
344 { "error_code", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
345 { "error_category", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
346 { "system_error", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
347 { "error_condition", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
348 { "thread", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
349 { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE },
350 { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
351 { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
352 { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE },
353 { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
354 { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
355 { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
356 { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
357 { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
358 { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
359 { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
360 { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
361 { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
362 { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
363 { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
364 { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
365 { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
366 { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
367 { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
368 { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
369 { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
370 { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
371 { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
372 { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
373 { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
374 { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
375 { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
376 { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
377 { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE },
378 { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE },
379 { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE },
380 { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
381 { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE },
382 { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
383 { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
384 { "forward_list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, // C++11
385 { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
386 { "unordered_map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
387 { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
388 { "unordered_multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
389 { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
390 { "unordered_set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
391 { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
392 { "unordered_multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
393 { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
394 { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
395 { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
396 { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
397 { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
398 { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
399 { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
400 { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
401 { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
402 { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
403 { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
404 { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
405 { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
406 { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
407 { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
408 { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
409 { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
410 { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
411 { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
412 { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
413 { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE }
416 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
418 Entry *memEntry = new Entry;
419 memEntry->name = name;
420 memEntry->type = type;
421 memEntry->protection = Public;
422 memEntry->section = Entry::VARIABLE_SEC;
423 memEntry->brief = "STL member";
424 memEntry->hidden = FALSE;
425 memEntry->artificial = TRUE;
426 //memEntry->parent = root;
427 //root->addSubEntry(memEntry);
428 EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
429 memEntryNav->setEntry(memEntry);
430 rootNav->addChild(memEntryNav);
433 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
435 Entry *iteratorClassEntry = new Entry;
436 iteratorClassEntry->fileName = "[STL]";
437 iteratorClassEntry->startLine = 1;
438 iteratorClassEntry->name = name;
439 iteratorClassEntry->section = Entry::CLASS_SEC;
440 iteratorClassEntry->brief = "STL iterator class";
441 iteratorClassEntry->hidden = FALSE;
442 iteratorClassEntry->artificial= TRUE;
443 EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
444 iteratorClassEntryNav->setEntry(iteratorClassEntry);
445 classEntryNav->addChild(iteratorClassEntryNav);
449 static void addSTLClasses(EntryNav *rootNav)
451 Entry *namespaceEntry = new Entry;
452 namespaceEntry->fileName = "[STL]";
453 namespaceEntry->startLine = 1;
454 //namespaceEntry->parent = rootNav->entry();
455 namespaceEntry->name = "std";
456 namespaceEntry->section = Entry::NAMESPACE_SEC;
457 namespaceEntry->brief = "STL namespace";
458 namespaceEntry->hidden = FALSE;
459 namespaceEntry->artificial= TRUE;
460 //root->addSubEntry(namespaceEntry);
461 EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
462 namespaceEntryNav->setEntry(namespaceEntry);
463 rootNav->addChild(namespaceEntryNav);
465 STLInfo *info = g_stlinfo;
466 while (info->className)
468 //printf("Adding STL class %s\n",info->className);
469 QCString fullName = info->className;
470 fullName.prepend("std::");
472 // add fake Entry for the class
473 Entry *classEntry = new Entry;
474 classEntry->fileName = "[STL]";
475 classEntry->startLine = 1;
476 classEntry->name = fullName;
477 //classEntry->parent = namespaceEntry;
478 classEntry->section = Entry::CLASS_SEC;
479 classEntry->brief = "STL class";
480 classEntry->hidden = FALSE;
481 classEntry->artificial= TRUE;
482 //namespaceEntry->addSubEntry(classEntry);
483 EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
484 classEntryNav->setEntry(classEntry);
485 namespaceEntryNav->addChild(classEntryNav);
487 // add template arguments to class
488 if (info->templType1)
490 ArgumentList *al = new ArgumentList;
491 Argument *a=new Argument;
493 a->name=info->templType1;
495 if (info->templType2) // another template argument
499 a->name=info->templType2;
502 classEntry->tArgLists = new QList<ArgumentList>;
503 classEntry->tArgLists->setAutoDelete(TRUE);
504 classEntry->tArgLists->append(al);
506 // add member variables
507 if (info->templName1)
509 addSTLMember(classEntryNav,info->templType1,info->templName1);
511 if (info->templName2)
513 addSTLMember(classEntryNav,info->templType2,info->templName2);
515 if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
516 fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
518 Entry *memEntry = new Entry;
519 memEntry->name = "operator->";
520 memEntry->args = "()";
521 memEntry->type = "T*";
522 memEntry->protection = Public;
523 memEntry->section = Entry::FUNCTION_SEC;
524 memEntry->brief = "STL member";
525 memEntry->hidden = FALSE;
526 memEntry->artificial = FALSE;
527 EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
528 memEntryNav->setEntry(memEntry);
529 classEntryNav->addChild(memEntryNav);
531 if (info->baseClass1)
533 classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
535 if (info->baseClass2)
537 classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
541 // add iterator class
542 addSTLIterator(classEntryNav,fullName+"::iterator");
543 addSTLIterator(classEntryNav,fullName+"::const_iterator");
544 addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
545 addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
551 //----------------------------------------------------------------------------
553 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
554 FileDef *fileScope=0);
556 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
558 if (rootNav->parent()) // add the page to it's scope
560 QCString scope = rootNav->parent()->name();
561 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
563 scope=substitute(scope,".","::");
565 scope = stripAnonymousNamespaceScope(scope);
566 scope+="::"+pd->name();
567 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
575 static void addRelatedPage(EntryNav *rootNav)
577 Entry *root = rootNav->entry();
579 QListIterator<Grouping> gli(*root->groups);
581 for (;(g=gli.current());++gli)
583 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
585 //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
587 if (root->brief.isEmpty())
589 doc=root->doc+root->inbodyDocs;
593 doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
595 PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
596 root->docFile,root->docLine,
598 gd,rootNav->tagInfo(),
603 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
604 pd->addSectionsToDefinition(root->anchors);
605 pd->setShowToc(root->stat);
606 addPageToContext(pd,rootNav);
610 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
612 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
613 ((!includeExternal && rootNav->tagInfo()==0) ||
614 ( includeExternal && rootNav->tagInfo()!=0))
617 rootNav->loadEntry(g_storage);
618 Entry *root = rootNav->entry();
620 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
621 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
623 GroupDef *gd = Doxygen::groupSDict->find(root->name);
624 //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
625 // root->type.data(),root->name.data(),additional,includeExternal,gd);
629 if ( !gd->hasGroupTitle() )
631 gd->setGroupTitle( root->type );
633 else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
635 warn( root->fileName,root->startLine,
636 "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
637 qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
639 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
640 gd->setDocumentation( root->doc, root->docFile, root->docLine );
641 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
642 gd->addSectionsToDefinition(root->anchors);
643 gd->setRefItems(root->sli);
644 gd->setLanguage(root->lang);
648 if (rootNav->tagInfo())
650 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
651 gd->setReference(rootNav->tagInfo()->tagName);
655 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
657 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
658 // allow empty docs for group
659 gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
660 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
661 gd->addSectionsToDefinition(root->anchors);
662 Doxygen::groupSDict->append(root->name,gd);
663 gd->setRefItems(root->sli);
664 gd->setLanguage(root->lang);
668 rootNav->releaseEntry();
670 if (rootNav->children())
672 EntryNavListIterator eli(*rootNav->children());
674 for (;(e=eli.current());++eli)
676 buildGroupListFiltered(e,additional,includeExternal);
681 static void buildGroupList(EntryNav *rootNav)
683 // --- first process only local groups
684 // first process the @defgroups blocks
685 buildGroupListFiltered(rootNav,FALSE,FALSE);
686 // then process the @addtogroup, @weakgroup blocks
687 buildGroupListFiltered(rootNav,TRUE,FALSE);
689 // --- then also process external groups
690 // first process the @defgroups blocks
691 buildGroupListFiltered(rootNav,FALSE,TRUE);
692 // then process the @addtogroup, @weakgroup blocks
693 buildGroupListFiltered(rootNav,TRUE,TRUE);
696 static void findGroupScope(EntryNav *rootNav)
698 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
699 rootNav->parent() && !rootNav->parent()->name().isEmpty())
702 if ((gd=Doxygen::groupSDict->find(rootNav->name())))
704 QCString scope = rootNav->parent()->name();
705 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
707 scope=substitute(scope,".","::");
709 scope = stripAnonymousNamespaceScope(scope);
710 scope+="::"+gd->name();
711 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
714 gd->setGroupScope(d);
718 RECURSE_ENTRYTREE(findGroupScope,rootNav);
721 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
723 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
725 rootNav->loadEntry(g_storage);
726 Entry *root = rootNav->entry();
728 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
729 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
732 if ((gd=Doxygen::groupSDict->find(root->name)))
734 //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
735 addGroupToGroups(root,gd);
739 rootNav->releaseEntry();
741 if (rootNav->children())
743 EntryNavListIterator eli(*rootNav->children());
745 for (;(e=eli.current());++eli)
747 organizeSubGroupsFiltered(e,additional);
752 static void organizeSubGroups(EntryNav *rootNav)
754 //printf("Defining groups\n");
755 // first process the @defgroups blocks
756 organizeSubGroupsFiltered(rootNav,FALSE);
757 //printf("Additional groups\n");
758 // then process the @addtogroup, @weakgroup blocks
759 organizeSubGroupsFiltered(rootNav,TRUE);
762 //----------------------------------------------------------------------
764 static void buildFileList(EntryNav *rootNav)
766 if (((rootNav->section()==Entry::FILEDOC_SEC) ||
767 ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
768 !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
771 rootNav->loadEntry(g_storage);
772 Entry *root = rootNav->entry();
775 FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
776 //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
780 if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
781 (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
784 root->fileName,root->startLine,
785 "file %s already documented. "
786 "Skipping documentation.",
793 //printf("Adding documentation!\n");
794 // using FALSE in setDocumentation is small hack to make sure a file
795 // is documented even if a \file command is used without further
797 fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
798 fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
799 fd->addSectionsToDefinition(root->anchors);
800 fd->setRefItems(root->sli);
801 QListIterator<Grouping> gli(*root->groups);
803 for (;(g=gli.current());++gli)
806 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
809 fd->makePartOfGroup(gd);
810 //printf("File %s: in group %s\n",fd->name().data(),s->data());
817 const char *fn = root->fileName.data();
819 text.sprintf("the name `%s' supplied as "
820 "the second argument in the \\file statement ",
822 if (ambig) // name is ambiguous
824 text+="matches the following input files:\n";
825 text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
826 text+="Please use a more specific name by "
827 "including a (larger) part of the path!";
829 else // name is not an input file
831 text+="is not an input file";
833 warn(fn,root->startLine,text);
836 rootNav->releaseEntry();
838 RECURSE_ENTRYTREE(buildFileList,rootNav);
841 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
844 (!root->doc.stripWhiteSpace().isEmpty() ||
845 !root->brief.stripWhiteSpace().isEmpty() ||
846 Config_getBool("EXTRACT_ALL")
847 ) && root->protection!=Private
850 //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
852 bool local=Config_getBool("FORCE_LOCAL_INCLUDES");
853 QCString includeFile = root->includeFile;
854 if (!includeFile.isEmpty() && includeFile.at(0)=='"')
857 includeFile=includeFile.mid(1,includeFile.length()-2);
859 else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
862 includeFile=includeFile.mid(1,includeFile.length()-2);
867 // see if we need to include a verbatim copy of the header file
868 //printf("root->includeFile=%s\n",root->includeFile.data());
869 if (!includeFile.isEmpty() &&
870 (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
872 { // explicit request
874 text.sprintf("the name `%s' supplied as "
875 "the argument of the \\class, \\struct, \\union, or \\include command ",
878 if (ambig) // name is ambiguous
880 text+="matches the following input files:\n";
881 text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
882 text+="Please use a more specific name by "
883 "including a (larger) part of the path!";
885 else // name is not an input file
887 text+="is not an input file";
889 warn(root->fileName,root->startLine,text);
891 else if (includeFile.isEmpty() && ifd &&
892 // see if the file extension makes sense
893 guessSection(ifd->name())==Entry::HEADER_SEC)
894 { // implicit assumption
898 // if a file is found, we mark it as a source file.
901 QCString iName = !root->includeName.isEmpty() ?
902 root->includeName : includeFile;
903 if (!iName.isEmpty()) // user specified include file
905 if (iName.at(0)=='<') local=FALSE; // explicit override
906 else if (iName.at(0)=='"') local=TRUE;
907 if (iName.at(0)=='"' || iName.at(0)=='<')
909 iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
916 else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty())
918 iName=stripFromIncludePath(fd->absFilePath());
920 else // use name of the file containing the class definition
924 if (fd->generateSourceFile()) // generate code for header
926 cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
928 else // put #include in the class documentation without link
930 cd->setIncludeFile(0,iName,local,TRUE);
937 static bool addNamespace(Entry *root,ClassDef *cd)
939 // see if this class is defined inside a namespace
940 if (root->section & Entry::COMPOUND_MASK)
942 Entry *e = root->parent;
945 if (e->section==Entry::NAMESPACE_SEC)
948 QCString nsName = stripAnonymousNamespaceScope(e->name);
949 //printf("addNameSpace() trying: %s\n",nsName.data());
950 if (!nsName.isEmpty() && nsName.at(0)!='@' &&
951 (nd=getResolvedNamespace(nsName))
954 cd->setNamespace(nd);
955 cd->setOuterScope(nd);
968 static Definition *findScope(Entry *root,int level=0)
970 if (root==0) return 0;
971 //printf("start findScope name=%s\n",root->name.data());
972 Definition *result=0;
973 if (root->section&Entry::SCOPE_MASK)
975 result = findScope(root->parent,level+1); // traverse to the root of the tree
978 //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
979 // TODO: look at template arguments
980 result = result->findInnerCompound(root->name);
982 else // reached the global scope
984 // TODO: look at template arguments
985 result = Doxygen::globalScope->findInnerCompound(root->name);
986 //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
989 //printf("end findScope(%s,%d)=%s\n",root->name.data(),
990 // level,result==0 ? "<none>" : result->name().data());
995 /*! returns the Definition object belonging to the first \a level levels of
996 * full qualified name \a name. Creates an artificial scope if the scope is
997 * not found and set the parent/child scope relation if the scope is found.
999 static Definition *buildScopeFromQualifiedName(const QCString name,int level,SrcLangExt lang,TagInfo *tagInfo)
1001 //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
1004 Definition *prevScope=Doxygen::globalScope;
1008 int idx=getScopeFragment(name,p,&l);
1009 QCString nsName = name.mid(idx,l);
1010 if (nsName.isEmpty()) return prevScope;
1011 if (!fullScope.isEmpty()) fullScope+="::";
1013 NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
1014 Definition *innerScope = nd;
1016 if (nd==0) cd = getClass(fullScope);
1017 if (nd==0 && cd) // scope is a class
1021 else if (nd==0 && cd==0) // scope is not known!
1023 // introduce bogus namespace
1024 //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
1025 nd=new NamespaceDef(
1026 "[generated]",1,1,fullScope,
1027 tagInfo?tagInfo->tagName:QCString(),
1028 tagInfo?tagInfo->fileName:QCString());
1029 nd->setLanguage(lang);
1031 // add namespace to the list
1032 Doxygen::namespaceSDict->inSort(fullScope,nd);
1035 else // scope is a namespace
1038 // make the parent/child scope relation
1039 prevScope->addInnerCompound(innerScope);
1040 innerScope->setOuterScope(prevScope);
1041 // proceed to the next scope fragment
1043 prevScope=innerScope;
1049 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
1052 //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
1053 Definition *resultScope=startScope;
1054 if (resultScope==0) resultScope=Doxygen::globalScope;
1055 QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
1057 i1=getScopeFragment(scope,0,&l1);
1060 //printf(">no fragments!\n");
1063 int p=i1+l1,l2=0,i2;
1064 while ((i2=getScopeFragment(scope,p,&l2))!=-1)
1066 QCString nestedNameSpecifier = scope.mid(i1,l1);
1067 Definition *orgScope = resultScope;
1068 //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
1069 resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
1070 //printf(" resultScope=%p\n",resultScope);
1073 NamespaceSDict *usedNamespaces;
1074 if (orgScope==Doxygen::globalScope && fileScope &&
1075 (usedNamespaces = fileScope->getUsedNamespaces()))
1076 // also search for used namespaces
1078 NamespaceSDict::Iterator ni(*usedNamespaces);
1080 for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
1082 // restart search within the used namespace
1083 resultScope = findScopeFromQualifiedName(nd,n,fileScope);
1087 // for a nested class A::I in used namespace N, we get
1088 // N::A::I while looking for A, so we should compare
1089 // resultScope->name() against scope.left(i2+l2)
1090 //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1091 if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1099 // also search for used classes. Complication: we haven't been able
1100 // to put them in the right scope yet, because we are still resolving
1101 // the scope relations!
1102 // Therefore loop through all used classes and see if there is a right
1103 // scope match between the used class and nestedNameSpecifier.
1104 QDictIterator<FileDef> ui(g_usingDeclarations);
1106 for (ui.toFirst();(usedFd=ui.current());++ui)
1108 //printf("Checking using class %s\n",ui.currentKey());
1109 if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1111 // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1112 // so use this instead.
1113 QCString fqn = QCString(ui.currentKey())+
1114 scope.right(scope.length()-p);
1115 resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),startScope->getLanguage(),0);
1116 //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1119 //printf("> Match! resultScope=%s\n",resultScope->name().data());
1125 //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1133 //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1137 ArgumentList *getTemplateArgumentsFromName(
1138 const QCString &name,
1139 const QList<ArgumentList> *tArgLists)
1141 if (tArgLists==0) return 0;
1143 QListIterator<ArgumentList> ali(*tArgLists);
1144 // for each scope fragment, check if it is a template and advance through
1147 while ((i=name.find("::",p))!=-1)
1149 NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1152 ClassDef *cd = getClass(name.left(i));
1155 if (cd->templateArguments())
1163 return ali.current();
1167 ClassDef::CompoundType convertToCompoundType(int section,uint64 specifier)
1169 ClassDef::CompoundType sec=ClassDef::Class;
1170 if (specifier&Entry::Struct)
1171 sec=ClassDef::Struct;
1172 else if (specifier&Entry::Union)
1173 sec=ClassDef::Union;
1174 else if (specifier&Entry::Category)
1175 sec=ClassDef::Category;
1176 else if (specifier&Entry::Interface)
1177 sec=ClassDef::Interface;
1178 else if (specifier&Entry::Protocol)
1179 sec=ClassDef::Protocol;
1180 else if (specifier&Entry::Exception)
1181 sec=ClassDef::Exception;
1182 else if (specifier&Entry::Service)
1183 sec=ClassDef::Service;
1184 else if (specifier&Entry::Singleton)
1185 sec=ClassDef::Singleton;
1189 //case Entry::UNION_SEC:
1190 case Entry::UNIONDOC_SEC:
1191 sec=ClassDef::Union;
1193 //case Entry::STRUCT_SEC:
1194 case Entry::STRUCTDOC_SEC:
1195 sec=ClassDef::Struct;
1197 //case Entry::INTERFACE_SEC:
1198 case Entry::INTERFACEDOC_SEC:
1199 sec=ClassDef::Interface;
1201 //case Entry::PROTOCOL_SEC:
1202 case Entry::PROTOCOLDOC_SEC:
1203 sec=ClassDef::Protocol;
1205 //case Entry::CATEGORY_SEC:
1206 case Entry::CATEGORYDOC_SEC:
1207 sec=ClassDef::Category;
1209 //case Entry::EXCEPTION_SEC:
1210 case Entry::EXCEPTIONDOC_SEC:
1211 sec=ClassDef::Exception;
1213 case Entry::SERVICEDOC_SEC:
1214 sec=ClassDef::Service;
1216 case Entry::SINGLETONDOC_SEC:
1217 sec=ClassDef::Singleton;
1224 static void addClassToContext(EntryNav *rootNav)
1226 //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1227 rootNav->loadEntry(g_storage);
1228 Entry *root = rootNav->entry();
1230 //NamespaceDef *nd = 0;
1231 FileDef *fd = rootNav->fileDef();
1234 if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1236 scName=rootNav->parent()->name();
1238 // name without parent's scope
1239 QCString fullName = root->name;
1241 // strip off any template parameters (but not those for specializations)
1242 fullName=stripTemplateSpecifiersFromScope(fullName);
1244 // name with scope (if not present already)
1245 QCString qualifiedName = fullName;
1246 if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1248 qualifiedName.prepend(scName+"::");
1251 // see if we already found the class before
1252 ClassDef *cd = getClass(qualifiedName);
1254 Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1255 cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);
1259 fullName=cd->name();
1260 Debug::print(Debug::Classes,0," Existing class %s!\n",cd->name().data());
1261 //if (cd->templateArguments()==0)
1263 // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1264 // cd->setTemplateArguments(tArgList);
1267 cd->setDocumentation(root->doc,root->docFile,root->docLine);
1268 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1270 if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1272 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1275 //cd->setName(fullName); // change name to match docs
1277 if (cd->templateArguments()==0)
1279 // this happens if a template class declared with @class is found
1280 // before the actual definition.
1281 ArgumentList *tArgList =
1282 getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1283 cd->setTemplateArguments(tArgList);
1286 cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1290 ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1293 QCString namespaceName;
1294 extractNamespaceName(fullName,className,namespaceName);
1296 //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1297 // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1300 QCString refFileName;
1301 TagInfo *tagInfo = rootNav->tagInfo();
1304 tagName = tagInfo->tagName;
1305 refFileName = tagInfo->fileName;
1307 if ((i=fullName.find("::"))!=-1)
1308 // symbols imported via tag files may come without the parent scope,
1309 // so we artificially create it here
1311 buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1314 cd=new ClassDef(root->fileName,root->startLine,root->startColumn,
1315 fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1316 Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1317 fullName.data(),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
1318 cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1319 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1320 cd->setLanguage(root->lang);
1321 cd->setId(root->id);
1322 cd->setHidden(root->hidden);
1323 cd->setArtificial(root->artificial);
1324 cd->setClassSpecifier(root->spec);
1325 cd->setTypeConstraints(root->typeConstr);
1326 //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1328 ArgumentList *tArgList =
1329 getTemplateArgumentsFromName(fullName,root->tArgLists);
1330 //printf("class %s template args=%s\n",fullName.data(),
1331 // tArgList ? tempArgListToString(tArgList).data() : "<none>");
1332 cd->setTemplateArguments(tArgList);
1333 cd->setProtection(root->protection);
1334 cd->setIsStatic(root->stat);
1336 // file definition containing the class cd
1337 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1340 // see if the class is found inside a namespace
1341 //bool found=addNamespace(root,cd);
1343 cd->insertUsedFile(fd);
1345 // add class to the list
1346 //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
1347 Doxygen::classSDict->append(fullName,cd);
1349 if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1351 Doxygen::genericsDict->insert(fullName,cd);
1355 cd->addSectionsToDefinition(root->anchors);
1356 if (!root->subGrouping) cd->setSubGrouping(FALSE);
1357 if (cd->hasDocumentation())
1359 addIncludeFile(cd,fd,root);
1361 if (fd && (root->section & Entry::COMPOUND_MASK))
1363 //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1364 // cd->name().data(),
1365 // fd->name().data(),
1366 // root->fileName.data()
1369 fd->insertClass(cd);
1371 addClassToGroups(root,cd);
1372 cd->setRefItems(root->sli);
1374 rootNav->releaseEntry();
1377 //----------------------------------------------------------------------
1378 // build a list of all classes mentioned in the documentation
1379 // and all classes that have a documentation block before their definition.
1380 static void buildClassList(EntryNav *rootNav)
1383 ((rootNav->section() & Entry::COMPOUND_MASK) ||
1384 rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1387 addClassToContext(rootNav);
1389 RECURSE_ENTRYTREE(buildClassList,rootNav);
1392 static void buildClassDocList(EntryNav *rootNav)
1395 (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1398 addClassToContext(rootNav);
1400 RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1403 static void resolveClassNestingRelations()
1405 ClassSDict::Iterator cli(*Doxygen::classSDict);
1406 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1415 for (cli.toFirst();(cd=cli.current());++cli)
1419 QCString name = stripAnonymousNamespaceScope(cd->name());
1420 //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1421 // also add class to the correct structural context
1422 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1423 name,cd->getFileDef());
1426 //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1427 d->addInnerCompound(cd);
1428 cd->setOuterScope(d);
1434 // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1440 //give warnings for unresolved compounds
1442 for (cli.toFirst();(cd=cli.current());++cli)
1446 QCString name = stripAnonymousNamespaceScope(cd->name());
1447 //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1448 /// create the scope artificially
1449 // anyway, so we can at least relate scopes properly.
1450 Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1451 if (d!=cd && !cd->getDefFileName().isEmpty())
1452 // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1453 // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1454 // also avoid warning for stuff imported via a tagfile.
1456 d->addInnerCompound(cd);
1457 cd->setOuterScope(d);
1458 warn(cd->getDefFileName(),cd->getDefLine(),
1459 "Internal inconsistency: scope for class %s not "
1460 "found!",name.data()
1467 void distributeClassGroupRelations()
1469 //static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES");
1470 //if (!inlineGroupedClasses) return;
1471 //printf("** distributeClassGroupRelations()\n");
1473 ClassSDict::Iterator cli(*Doxygen::classSDict);
1474 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1477 for (cli.toFirst();(cd=cli.current());++cli)
1479 //printf("Checking %s\n",cd->name().data());
1480 // distribute the group to nested classes as well
1481 if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1483 //printf(" Candidate for merging\n");
1484 ClassSDict::Iterator ncli(*cd->getClassSDict());
1486 GroupDef *gd = cd->partOfGroups()->at(0);
1487 for (ncli.toFirst();(ncd=ncli.current());++ncli)
1489 if (ncd->partOfGroups()==0)
1491 //printf(" Adding %s to group '%s'\n",ncd->name().data(),
1492 // gd->groupTitle());
1493 ncd->makePartOfGroup(gd);
1497 cd->visited=TRUE; // only visit every class once
1502 //----------------------------
1504 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1506 QCString fullName = removeAnonymousScopes(templ->name());
1507 if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1508 fullName+="."+fieldName;
1509 ClassDef *cd = new ClassDef(templ->getDefFileName(),
1510 templ->getDefLine(),
1511 templ->getDefColumn(),
1513 templ->compoundType());
1514 cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1515 cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1516 cd->setLanguage(templ->getLanguage());
1517 cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1518 cd->setBodyDef(templ->getBodyDef());
1520 cd->setOuterScope(rootCd->getOuterScope());
1521 if (rootCd->getOuterScope()!=Doxygen::globalScope)
1523 rootCd->getOuterScope()->addInnerCompound(cd);
1526 FileDef *fd = templ->getFileDef();
1530 fd->insertClass(cd);
1532 GroupList *groups = rootCd->partOfGroups();
1535 GroupListIterator gli(*groups);
1537 for (gli.toFirst();(gd=gli.current());++gli)
1539 cd->makePartOfGroup(gd);
1543 //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1544 Doxygen::classSDict->append(fullName,cd);
1546 MemberList *ml = templ->getMemberList(MemberListType_pubAttribs);
1549 MemberListIterator li(*ml);
1551 for (li.toFirst();(md=li.current());++li)
1553 //printf(" Member %s type=%s\n",md->name().data(),md->typeString());
1554 MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1555 md->typeString(),md->name(),md->argsString(),md->excpString(),
1556 md->protection(),md->virtualness(),md->isStatic(),Member,
1559 imd->setMemberClass(cd);
1560 imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1561 imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1562 imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1563 imd->setMemberSpecifiers(md->getMemberSpecifiers());
1564 imd->setMemberGroupId(md->getMemberGroupId());
1565 imd->setInitializer(md->initializer());
1566 imd->setMaxInitLines(md->initializerLines());
1567 imd->setBitfields(md->bitfieldString());
1568 imd->setLanguage(md->getLanguage());
1569 cd->insertMember(imd);
1575 /** Look through the members of class \a cd and its public members.
1576 * If there is a member m of a tag less struct/union,
1577 * then we create a duplicate of the struct/union with the name of the
1578 * member to identify it.
1579 * So if cd has name S, then the tag less struct/union will get name S.m
1580 * Since tag less structs can be nested we need to call this function
1581 * recursively. Later on we need to patch the member types so we keep
1582 * track of the hierarchy of classes we create.
1584 static void processTagLessClasses(ClassDef *rootCd,
1586 ClassDef *tagParentCd,
1587 const QCString &prefix,int count)
1589 //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1590 //printf("checking members for %s\n",cd->name().data());
1591 if (cd->getClassSDict())
1593 MemberList *ml = cd->getMemberList(MemberListType_pubAttribs);
1596 MemberListIterator li(*ml);
1598 for (li.toFirst();(md=li.current());++li)
1600 QCString type = md->typeString();
1601 if (type.find("::@")!=-1) // member of tag less struct/union
1603 ClassSDict::Iterator it(*cd->getClassSDict());
1605 for (it.toFirst();(icd=it.current());++it)
1607 //printf(" member %s: type='%s'\n",md->name().data(),type.data());
1608 //printf(" comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1609 if (type.find(icd->name())!=-1) // matching tag less struct/union
1611 QCString name = md->name();
1612 if (name.at(0)=='@') name = "__unnamed__";
1613 if (!prefix.isEmpty()) name.prepend(prefix+".");
1614 //printf(" found %s for class %s\n",name.data(),cd->name().data());
1615 ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1616 processTagLessClasses(rootCd,icd,ncd,name,count+1);
1617 //printf(" addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1618 tagParentCd->addTaggedInnerClass(ncd);
1619 ncd->setTagLessReference(icd);
1621 // replace tag-less type for generated/original member
1622 // by newly created class name.
1623 // note the difference between changing cd and tagParentCd.
1624 // for the initial call this is the same pointer, but for
1625 // recursive calls cd is the original tag-less struct (of which
1626 // there is only one instance) and tagParentCd is the newly
1627 // generated tagged struct of which there can be multiple instances!
1628 MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1631 MemberListIterator pli(*pml);
1633 for (pli.toFirst();(pmd=pli.current());++pli)
1635 if (pmd->name()==md->name())
1637 pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1638 //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1650 static void writeMainPageTagFileData()
1652 if (Doxygen::mainPage && !Config_getString("GENERATE_TAGFILE").isEmpty())
1654 Doxygen::tagFile << " <compound kind=\"page\">" << endl
1656 << convertToXML(Doxygen::mainPage->name())
1657 << "</name>" << endl
1659 << convertToXML(Doxygen::mainPage->title())
1660 << "</title>" << endl
1662 << convertToXML(Doxygen::mainPage->getOutputFileBase())
1663 << "</filename>" << endl;
1665 Doxygen::mainPage->writeDocAnchorsToTagFile();
1666 Doxygen::tagFile << " </compound>" << endl;
1670 static void findTagLessClasses(ClassDef *cd)
1672 if (cd->getClassSDict())
1674 ClassSDict::Iterator it(*cd->getClassSDict());
1676 for (it.toFirst();(icd=it.current());++it)
1678 if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1680 findTagLessClasses(icd);
1685 processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1688 static void findTagLessClasses()
1690 ClassSDict::Iterator cli(*Doxygen::classSDict);
1692 for (cli.toFirst();(cd=cli.current());++cli) // for each class
1694 Definition *scope = cd->getOuterScope();
1695 if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1697 findTagLessClasses(cd);
1703 //----------------------------------------------------------------------
1704 // build a list of all namespaces mentioned in the documentation
1705 // and all namespaces that have a documentation block before their definition.
1706 static void buildNamespaceList(EntryNav *rootNav)
1709 (rootNav->section()==Entry::NAMESPACE_SEC ||
1710 rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1711 rootNav->section()==Entry::PACKAGEDOC_SEC
1713 !rootNav->name().isEmpty()
1716 rootNav->loadEntry(g_storage);
1717 Entry *root = rootNav->entry();
1719 //printf("** buildNamespaceList(%s)\n",root->name.data());
1721 QCString fName = root->name;
1722 if (root->section==Entry::PACKAGEDOC_SEC)
1724 fName=substitute(fName,".","::");
1727 QCString fullName = stripAnonymousNamespaceScope(fName);
1728 if (!fullName.isEmpty())
1730 //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1731 // root->fileName.data(), root->startLine);
1733 if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1735 nd->setDocumentation(root->doc,root->docFile,root->docLine);
1736 nd->setName(fullName); // change name to match docs
1737 nd->addSectionsToDefinition(root->anchors);
1738 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1739 if (nd->getLanguage()==SrcLangExt_Unknown)
1741 nd->setLanguage(root->lang);
1744 // file definition containing the namespace nd
1745 FileDef *fd=rootNav->fileDef();
1746 // insert the namespace in the file definition
1747 if (fd) fd->insertNamespace(nd);
1748 addNamespaceToGroups(root,nd);
1749 nd->setRefItems(root->sli);
1751 else // fresh namespace
1754 QCString tagFileName;
1755 TagInfo *tagInfo = rootNav->tagInfo();
1758 tagName = tagInfo->tagName;
1759 tagFileName = tagInfo->fileName;
1761 //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1762 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,
1763 root->startColumn,fullName,tagName,tagFileName,
1764 root->type,root->spec&Entry::Published);
1765 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1766 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1767 nd->addSectionsToDefinition(root->anchors);
1768 nd->setHidden(root->hidden);
1769 nd->setArtificial(root->artificial);
1770 nd->setLanguage(root->lang);
1771 nd->setId(root->id);
1773 //printf("Adding namespace to group\n");
1774 addNamespaceToGroups(root,nd);
1775 nd->setRefItems(root->sli);
1777 // file definition containing the namespace nd
1778 FileDef *fd=rootNav->fileDef();
1779 // insert the namespace in the file definition
1780 if (fd) fd->insertNamespace(nd);
1782 // the empty string test is needed for extract all case
1783 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1784 nd->insertUsedFile(fd);
1785 nd->setBodySegment(root->bodyLine,root->endBodyLine);
1787 // add class to the list
1788 Doxygen::namespaceSDict->inSort(fullName,nd);
1790 // also add namespace to the correct structural context
1791 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName);
1792 //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1793 if (d==0) // we didn't find anything, create the scope artificially
1794 // anyway, so we can at least relate scopes properly.
1796 Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1797 d->addInnerCompound(nd);
1798 nd->setOuterScope(d);
1799 // TODO: Due to the order in which the tag file is written
1800 // a nested class can be found before its parent!
1804 d->addInnerCompound(nd);
1805 nd->setOuterScope(d);
1810 rootNav->releaseEntry();
1812 RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1815 //----------------------------------------------------------------------
1817 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1818 const QCString &name)
1820 NamespaceDef *usingNd =0;
1823 //printf("Found namespace dict %d\n",unl->count());
1824 NamespaceSDict::Iterator unli(*unl);
1826 for (unli.toFirst();(und=unli.current());++unli)
1828 QCString uScope=und->name()+"::";
1829 usingNd = getResolvedNamespace(uScope+name);
1830 //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1836 static void findUsingDirectives(EntryNav *rootNav)
1838 if (rootNav->section()==Entry::USINGDIR_SEC)
1840 rootNav->loadEntry(g_storage);
1841 Entry *root = rootNav->entry();
1843 //printf("Found using directive %s at line %d of %s\n",
1844 // root->name.data(),root->startLine,root->fileName.data());
1845 QCString name=substitute(root->name,".","::");
1846 if (name.right(2)=="::")
1848 name=name.left(name.length()-2);
1850 if (!name.isEmpty())
1852 NamespaceDef *usingNd = 0;
1853 NamespaceDef *nd = 0;
1854 FileDef *fd = rootNav->fileDef();
1857 // see if the using statement was found inside a namespace or inside
1858 // the global file scope.
1859 if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1860 (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1863 nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1864 if (!nsName.isEmpty())
1866 nd = getResolvedNamespace(nsName);
1870 // find the scope in which the `using' namespace is defined by prepending
1871 // the possible scopes in which the using statement was found, starting
1872 // with the most inner scope and going to the most outer scope (i.e.
1874 int scopeOffset = nsName.length();
1877 QCString scope=scopeOffset>0 ?
1878 nsName.left(scopeOffset)+"::" : QCString();
1879 usingNd = getResolvedNamespace(scope+name);
1880 //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1885 else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1889 } while (scopeOffset>=0 && usingNd==0);
1891 if (usingNd==0 && nd) // not found, try used namespaces in this scope
1892 // or in one of the parent namespace scopes
1894 NamespaceDef *pnd = nd;
1895 while (pnd && usingNd==0)
1897 // also try with one of the used namespaces found earlier
1898 usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1901 Definition *s = pnd->getOuterScope();
1902 if (s && s->definitionType()==Definition::TypeNamespace)
1904 pnd = (NamespaceDef*)s;
1912 if (usingNd==0 && fd) // still nothing, also try used namespace in the
1915 usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1918 //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1920 // add the namespace the correct scope
1923 //printf("using fd=%p nd=%p\n",fd,nd);
1926 //printf("Inside namespace %s\n",nd->name().data());
1927 nd->addUsingDirective(usingNd);
1931 //printf("Inside file %s\n",fd->name().data());
1932 fd->addUsingDirective(usingNd);
1935 else // unknown namespace, but add it anyway.
1937 //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1938 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1939 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1940 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1941 nd->addSectionsToDefinition(root->anchors);
1942 //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1943 nd->setHidden(root->hidden);
1944 nd->setArtificial(TRUE);
1945 nd->setLanguage(root->lang);
1946 nd->setId(root->id);
1948 QListIterator<Grouping> gli(*root->groups);
1950 for (;(g=gli.current());++gli)
1953 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1954 gd->addNamespace(nd);
1957 // insert the namespace in the file definition
1960 fd->insertNamespace(nd);
1961 fd->addUsingDirective(nd);
1964 // the empty string test is needed for extract all case
1965 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1966 nd->insertUsedFile(fd);
1967 // add class to the list
1968 Doxygen::namespaceSDict->inSort(name,nd);
1969 nd->setRefItems(root->sli);
1973 rootNav->releaseEntry();
1975 RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
1978 //----------------------------------------------------------------------
1980 static void buildListOfUsingDecls(EntryNav *rootNav)
1982 if (rootNav->section()==Entry::USINGDECL_SEC &&
1983 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1986 rootNav->loadEntry(g_storage);
1987 Entry *root = rootNav->entry();
1989 QCString name = substitute(root->name,".","::");
1991 if (g_usingDeclarations.find(name)==0)
1993 FileDef *fd = rootNav->fileDef();
1996 g_usingDeclarations.insert(name,fd);
2000 rootNav->releaseEntry();
2002 RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
2006 static void findUsingDeclarations(EntryNav *rootNav)
2008 if (rootNav->section()==Entry::USINGDECL_SEC &&
2009 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2012 rootNav->loadEntry(g_storage);
2013 Entry *root = rootNav->entry();
2015 //printf("Found using declaration %s at line %d of %s inside section %x\n",
2016 // root->name.data(),root->startLine,root->fileName.data(),
2017 // rootNav->parent()->section());
2018 if (!root->name.isEmpty())
2020 ClassDef *usingCd = 0;
2021 NamespaceDef *nd = 0;
2022 FileDef *fd = rootNav->fileDef();
2025 // see if the using statement was found inside a namespace or inside
2026 // the global file scope.
2027 if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
2029 scName=rootNav->parent()->name();
2030 if (!scName.isEmpty())
2032 nd = getResolvedNamespace(scName);
2036 // Assume the using statement was used to import a class.
2037 // Find the scope in which the `using' namespace is defined by prepending
2038 // the possible scopes in which the using statement was found, starting
2039 // with the most inner scope and going to the most outer scope (i.e.
2042 QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2043 usingCd = getClass(name);
2046 usingCd = Doxygen::hiddenClasses->find(name);
2049 //printf("%s -> %p\n",root->name.data(),usingCd);
2050 if (usingCd==0) // definition not in the input => add an artificial class
2052 Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
2053 name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
2054 usingCd = new ClassDef(
2058 Doxygen::hiddenClasses->append(root->name,usingCd);
2059 usingCd->setArtificial(TRUE);
2060 usingCd->setLanguage(root->lang);
2064 Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",
2065 usingCd->name().data(),nd?nd->name().data():fd->name().data());
2068 if (usingCd) // add the class to the correct scope
2072 //printf("Inside namespace %s\n",nd->name().data());
2073 nd->addUsingDeclaration(usingCd);
2077 //printf("Inside file %s\n",fd->name().data());
2078 fd->addUsingDeclaration(usingCd);
2083 rootNav->releaseEntry();
2085 RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
2088 //----------------------------------------------------------------------
2090 static void findUsingDeclImports(EntryNav *rootNav)
2092 if (rootNav->section()==Entry::USINGDECL_SEC &&
2093 (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
2096 //printf("Found using declaration %s at line %d of %s inside section %x\n",
2097 // root->name.data(),root->startLine,root->fileName.data(),
2098 // root->parent->section);
2099 QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
2100 fullName=stripAnonymousNamespaceScope(fullName);
2101 fullName=stripTemplateSpecifiersFromScope(fullName);
2102 ClassDef *cd = getClass(fullName);
2105 //printf("found class %s\n",cd->name().data());
2106 int i=rootNav->name().find("::");
2109 QCString scope=rootNav->name().left(i);
2110 QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
2111 ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2114 //printf("found class %s\n",bcd->name().data());
2115 MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2118 MemberNameInfo *mni = mndict->find(memName);
2121 MemberNameInfoIterator mnii(*mni);
2123 for ( ; (mi=mnii.current()) ; ++mnii )
2125 MemberDef *md = mi->memberDef;
2126 if (md && md->protection()!=Private)
2129 rootNav->loadEntry(g_storage);
2130 Entry *root = rootNav->entry();
2132 //printf("found member %s\n",mni->memberName());
2133 MemberDef *newMd = 0;
2135 ArgumentList *templAl = md->templateArguments();
2136 ArgumentList *al = md->templateArguments();
2137 newMd = new MemberDef(
2138 root->fileName,root->startLine,root->startColumn,
2139 md->typeString(),memName,md->argsString(),
2140 md->excpString(),root->protection,root->virt,
2141 md->isStatic(),Member,md->memberType(),
2145 newMd->setMemberClass(cd);
2146 cd->insertMember(newMd);
2147 if (!root->doc.isEmpty() || !root->brief.isEmpty())
2149 newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2150 newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2151 newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2155 newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2156 newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2157 newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2159 newMd->setDefinition(md->definition());
2160 newMd->enableCallGraph(root->callGraph);
2161 newMd->enableCallerGraph(root->callerGraph);
2162 newMd->setBitfields(md->bitfieldString());
2163 newMd->addSectionsToDefinition(root->anchors);
2164 newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2165 newMd->setBodyDef(md->getBodyDef());
2166 newMd->setInitializer(md->initializer());
2167 newMd->setMaxInitLines(md->initializerLines());
2168 newMd->setMemberGroupId(root->mGrpId);
2169 newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2170 newMd->setLanguage(root->lang);
2171 newMd->setId(root->id);
2173 rootNav->releaseEntry();
2183 RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2186 //----------------------------------------------------------------------
2188 static void findIncludedUsingDirectives()
2190 // first mark all files as not visited
2191 FileNameListIterator fnli(*Doxygen::inputNameList);
2193 for (fnli.toFirst();(fn=fnli.current());++fnli)
2195 FileNameIterator fni(*fn);
2197 for (;(fd=fni.current());++fni)
2202 // then recursively add using directives found in #include files
2203 // to files that have not been visited.
2204 for (fnli.toFirst();(fn=fnli.current());++fnli)
2206 FileNameIterator fni(*fn);
2208 for (fni.toFirst();(fd=fni.current());++fni)
2212 //printf("----- adding using directives for file %s\n",fd->name().data());
2213 fd->addIncludedUsingDirectives();
2219 //----------------------------------------------------------------------
2221 static MemberDef *addVariableToClass(
2225 const QCString &name,
2227 MemberDef *fromAnnMemb,
2229 Relationship related)
2231 Entry *root = rootNav->entry();
2233 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2234 QCString scopeSeparator="::";
2235 SrcLangExt lang = cd->getLanguage();
2236 if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2238 qualScope = substitute(qualScope,"::",".");
2241 Debug::print(Debug::Variables,0,
2242 " class variable:\n"
2243 " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2250 root->initializer.data()
2254 if (!root->type.isEmpty())
2256 if (related || mtype==MemberType_Friend || Config_getBool("HIDE_SCOPE_NAMES"))
2258 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2260 def="using "+name+" = "+root->type.mid(7);
2264 def=root->type+" "+name+root->args;
2269 if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2271 def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2275 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2281 if (Config_getBool("HIDE_SCOPE_NAMES"))
2283 def=name+root->args;
2287 def=qualScope+scopeSeparator+name+root->args;
2290 def.stripPrefix("static ");
2292 // see if the member is already found in the same scope
2293 // (this may be the case for a static member that is initialized
2294 // outside the class)
2295 MemberName *mn=Doxygen::memberNameSDict->find(name);
2298 MemberNameIterator mni(*mn);
2300 for (mni.toFirst();(md=mni.current());++mni)
2302 //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2303 // md->getClassDef(),cd,root->type.data(),md->typeString());
2304 if (md->getClassDef()==cd &&
2305 removeRedundantWhiteSpace(root->type)==md->typeString())
2306 // member already in the scope
2309 if (root->lang==SrcLangExt_ObjC &&
2310 root->mtype==Property &&
2311 md->memberType()==MemberType_Variable)
2312 { // Objective-C 2.0 property
2313 // turn variable into a property
2314 md->setProtection(root->protection);
2315 cd->reclassifyMember(md,MemberType_Property);
2317 addMemberDocs(rootNav,md,def,0,FALSE);
2318 //printf(" Member already found!\n");
2324 // new member variable, typedef or enum value
2325 MemberDef *md=new MemberDef(
2326 root->fileName,root->startLine,root->startColumn,
2327 root->type,name,root->args,root->exception,
2328 prot,Normal,root->stat,related,
2329 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2330 md->setTagInfo(rootNav->tagInfo());
2331 md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2332 //md->setDefFile(root->fileName);
2333 //md->setDefLine(root->startLine);
2334 md->setDocumentation(root->doc,root->docFile,root->docLine);
2335 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2336 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2337 md->setDefinition(def);
2338 md->setBitfields(root->bitfields);
2339 md->addSectionsToDefinition(root->anchors);
2340 md->setFromAnonymousScope(fromAnnScope);
2341 md->setFromAnonymousMember(fromAnnMemb);
2342 //md->setIndentDepth(indentDepth);
2343 md->setBodySegment(root->bodyLine,root->endBodyLine);
2344 md->setInitializer(root->initializer);
2345 md->setMaxInitLines(root->initLines);
2346 md->setMemberGroupId(root->mGrpId);
2347 md->setMemberSpecifiers(root->spec);
2348 md->setReadAccessor(root->read);
2349 md->setWriteAccessor(root->write);
2350 md->enableCallGraph(root->callGraph);
2351 md->enableCallerGraph(root->callerGraph);
2352 md->setHidden(root->hidden);
2353 md->setArtificial(root->artificial);
2354 md->setLanguage(root->lang);
2355 md->setId(root->id);
2356 addMemberToGroups(root,md);
2357 //if (root->mGrpId!=-1)
2359 // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2360 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
2362 md->setBodyDef(rootNav->fileDef());
2364 //printf(" Adding member=%s\n",md->name().data());
2365 // add the member to the global list
2370 else // new variable name
2372 mn = new MemberName(name);
2374 //printf("Adding memberName=%s\n",mn->memberName());
2375 //Doxygen::memberNameDict.insert(name,mn);
2376 //Doxygen::memberNameList.append(mn);
2377 Doxygen::memberNameSDict->append(name,mn);
2378 // add the member to the class
2380 //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd);
2381 cd->insertMember(md);
2382 md->setRefItems(root->sli);
2384 //TODO: insert FileDef instead of filename strings.
2385 cd->insertUsedFile(rootNav->fileDef());
2386 rootNav->changeSection(Entry::EMPTY_SEC);
2390 //----------------------------------------------------------------------
2392 static MemberDef *addVariableToFile(
2395 const QCString &scope,
2396 const QCString &name,
2398 /*int indentDepth,*/
2399 MemberDef *fromAnnMemb)
2401 Entry *root = rootNav->entry();
2402 Debug::print(Debug::Variables,0,
2403 " global variable:\n"
2404 " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2414 FileDef *fd = rootNav->fileDef();
2416 // see if we have a typedef that should hide a struct or union
2417 if (mtype==MemberType_Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))
2419 QCString type = root->type;
2420 type.stripPrefix("typedef ");
2421 if (type.left(7)=="struct " || type.left(6)=="union ")
2423 type.stripPrefix("struct ");
2424 type.stripPrefix("union ");
2425 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2427 s = re.match(type,0,&l);
2430 QCString typeValue = type.mid(s,l);
2431 ClassDef *cd = getClass(typeValue);
2434 // this typedef should hide compound name cd, so we
2435 // change the name that is displayed from cd.
2436 cd->setClassName(name);
2437 cd->setDocumentation(root->doc,root->docFile,root->docLine);
2438 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2445 // see if the function is inside a namespace
2446 NamespaceDef *nd = 0;
2448 if (!scope.isEmpty())
2450 if (scope.find('@')!=-1) return 0; // anonymous scope!
2451 //nscope=removeAnonymousScopes(scope);
2452 //if (!nscope.isEmpty())
2454 nd = getResolvedNamespace(scope);
2459 // determine the definition of the global variable
2460 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' &&
2461 !Config_getBool("HIDE_SCOPE_NAMES")
2463 // variable is inside a namespace, so put the scope before the name
2465 SrcLangExt lang = nd->getLanguage();
2466 QCString sep=getLanguageSpecificSeparator(lang);
2468 if (!root->type.isEmpty())
2470 if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2472 def="using "+nd->name()+sep+name+" = "+root->type;
2474 else // normal member
2476 def=root->type+" "+nd->name()+sep+name+root->args;
2481 def=nd->name()+sep+name+root->args;
2486 if (!root->type.isEmpty() && !root->name.isEmpty())
2488 if (name.at(0)=='@') // dummy variable representing anonymous union
2494 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2496 def="using "+root->name+" = "+root->type.mid(7);
2498 else // normal member
2500 def=root->type+" "+name+root->args;
2506 def=name+root->args;
2509 def.stripPrefix("static ");
2511 MemberName *mn=Doxygen::functionNameSDict->find(name);
2514 //QCString nscope=removeAnonymousScopes(scope);
2515 //NamespaceDef *nd=0;
2516 //if (!nscope.isEmpty())
2517 if (!scope.isEmpty())
2519 nd = getResolvedNamespace(scope);
2521 MemberNameIterator mni(*mn);
2523 for (mni.toFirst();(md=mni.current());++mni)
2526 ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2527 root->fileName==md->getFileDef()->absFilePath()
2528 ) // both variable names in the same file
2529 || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2531 && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2532 && !md->isEnumerate() // in C# an enum value and enum can have the same name
2534 // variable already in the scope
2536 bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2537 md->argsString()!=root->args &&
2538 root->args.find('[')!=-1;
2539 bool staticsInDifferentFiles =
2540 root->stat && md->isStatic() &&
2541 root->fileName!=md->getDefFileName();
2543 if (md->getFileDef() &&
2544 !isPHPArray && // not a php array
2545 !staticsInDifferentFiles
2547 // not a php array variable
2550 Debug::print(Debug::Variables,0,
2551 " variable already found: scope=%s\n",md->getOuterScope()->name().data());
2552 addMemberDocs(rootNav,md,def,0,FALSE);
2553 md->setRefItems(root->sli);
2559 Debug::print(Debug::Variables,0,
2560 " new variable, nd=%s!\n",nd?nd->name().data():"<global>");
2561 // new global variable, enum value or typedef
2562 MemberDef *md=new MemberDef(
2563 root->fileName,root->startLine,root->startColumn,
2564 root->type,name,root->args,0,
2565 Public, Normal,root->stat,Member,
2566 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2567 md->setTagInfo(rootNav->tagInfo());
2568 md->setMemberSpecifiers(root->spec);
2569 md->setDocumentation(root->doc,root->docFile,root->docLine);
2570 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2571 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2572 md->addSectionsToDefinition(root->anchors);
2573 md->setFromAnonymousScope(fromAnnScope);
2574 md->setFromAnonymousMember(fromAnnMemb);
2575 md->setInitializer(root->initializer);
2576 md->setMaxInitLines(root->initLines);
2577 md->setMemberGroupId(root->mGrpId);
2578 md->setDefinition(def);
2579 md->setLanguage(root->lang);
2580 md->setId(root->id);
2581 md->enableCallGraph(root->callGraph);
2582 md->enableCallerGraph(root->callerGraph);
2583 md->setExplicitExternal(root->explicitExternal);
2584 //md->setOuterScope(fd);
2585 if (!root->explicitExternal)
2587 md->setBodySegment(root->bodyLine,root->endBodyLine);
2590 addMemberToGroups(root,md);
2592 md->setRefItems(root->sli);
2593 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2595 md->setNamespace(nd);
2596 nd->insertMember(md);
2599 // add member to the file (we do this even if we have already inserted
2600 // it into the namespace.
2604 fd->insertMember(md);
2607 // add member definition to the list of globals
2614 mn = new MemberName(name);
2616 Doxygen::functionNameSDict->append(name,mn);
2618 rootNav->changeSection(Entry::EMPTY_SEC);
2622 /*! See if the return type string \a type is that of a function pointer
2623 * \returns -1 if this is not a function pointer variable or
2624 * the index at which the closing brace of (...*name) was found.
2626 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2628 if (lang == SrcLangExt_Fortran) return -1; // Fortran does not have function pointers
2629 static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2631 int bb=type.find('<');
2632 int be=type.findRev('>');
2633 if (!type.isEmpty() && // return type is non-empty
2634 (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2635 type.find("operator")==-1 && // not an operator
2636 (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2637 // not a function pointer return type
2638 !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2641 if (pLength) *pLength=l;
2642 //printf("findFunctionPtr=%d\n",i);
2647 //printf("findFunctionPtr=%d\n",-1);
2653 /*! Returns TRUE iff \a type is a class within scope \a context.
2654 * Used to detect variable declarations that look like function prototypes.
2656 static bool isVarWithConstructor(EntryNav *rootNav)
2658 static QRegExp initChars("[0-9\"'&*!^]+");
2659 static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2663 Definition *ctx = 0;
2667 //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2668 rootNav->loadEntry(g_storage);
2669 Entry *root = rootNav->entry();
2671 if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2676 else if ((fd = rootNav->fileDef()) &&
2677 (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2679 { // inside a .c file
2683 if (root->type.isEmpty())
2688 if (!rootNav->parent()->name().isEmpty())
2690 ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2693 // remove qualifiers
2694 findAndRemoveWord(type,"const");
2695 findAndRemoveWord(type,"static");
2696 findAndRemoveWord(type,"volatile");
2697 //if (type.left(6)=="const ") type=type.right(type.length()-6);
2698 typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2699 if (!typeIsClass && (ti=type.find('<'))!=-1)
2701 typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2703 if (typeIsClass) // now we still have to check if the arguments are
2704 // types or values. Since we do not have complete type info
2705 // we need to rely on heuristics :-(
2707 //printf("typeIsClass\n");
2708 ArgumentList *al = root->argList;
2709 if (al==0 || al->isEmpty())
2711 result=FALSE; // empty arg list -> function prototype.
2714 ArgumentListIterator ali(*al);
2716 for (ali.toFirst();(a=ali.current());++ali)
2718 if (!a->name.isEmpty() || !a->defval.isEmpty())
2720 if (a->name.find(initChars)==0)
2726 result=FALSE; // arg has (type,name) pair -> function prototype
2730 if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0)
2732 result=FALSE; // arg type is a known type
2735 if (checkIfTypedef(ctx,fd,a->type))
2737 //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2738 result=FALSE; // argument is a typedef
2741 if (a->type.at(a->type.length()-1)=='*' ||
2742 a->type.at(a->type.length()-1)=='&')
2743 // type ends with * or & => pointer or reference
2748 if (a->type.find(initChars)==0)
2750 result=TRUE; // argument type starts with typical initializer char
2753 QCString resType=resolveTypeDef(ctx,a->type);
2754 if (resType.isEmpty()) resType=a->type;
2756 if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2758 resType=resType.left(len);
2759 //printf("resType=%s\n",resType.data());
2760 if (resType=="int" || resType=="long" || resType=="float" ||
2761 resType=="double" || resType=="char" || resType=="signed" ||
2762 resType=="const" || resType=="unsigned" || resType=="void")
2764 result=FALSE; // type keyword -> function prototype
2773 //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2774 // root->type.data(),result);
2775 rootNav->releaseEntry();
2779 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2781 rootNav->loadEntry(g_storage);
2782 Entry *root = rootNav->entry();
2784 Debug::print(Debug::Variables,0,
2786 " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2792 root->relates.data()
2794 //printf("root->parent->name=%s\n",root->parent->name.data());
2796 if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2797 (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2799 // recover from parse error caused by redundant braces
2800 // like in "int *(var[10]);", which is parsed as
2801 // type="" name="int *" args="(var[10])"
2803 root->type=root->name;
2804 static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2806 int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2809 root->name=root->args.mid(i,l);
2810 root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2812 //printf("new: type=`%s' name=`%s' args=`%s'\n",
2813 // root->type.data(),root->name.data(),root->args.data());
2818 if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2819 Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no");
2820 if (i!=-1) // function pointer
2822 int ai = root->type.find('[',i);
2823 if (ai>i) // function pointer array
2825 root->args.prepend(root->type.right(root->type.length()-ai));
2826 root->type=root->type.left(ai);
2828 else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2830 root->type=root->type.left(root->type.length()-1);
2831 root->args.prepend(")");
2832 //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2835 else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
2837 root->type=root->type.left(root->type.length()-1);
2838 root->args.prepend(")");
2842 QCString scope,name=removeRedundantWhiteSpace(root->name);
2844 // find the scope of this variable
2845 EntryNav *p = rootNav->parent();
2846 while ((p->section() & Entry::SCOPE_MASK))
2848 QCString scopeName = p->name();
2849 if (!scopeName.isEmpty())
2851 scope.prepend(scopeName);
2858 QCString type=root->type.stripWhiteSpace();
2860 bool isRelated=FALSE;
2861 bool isMemberOf=FALSE;
2863 QCString classScope=stripAnonymousNamespaceScope(scope);
2864 classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2865 QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2867 if (root->name.findRev("::")!=-1)
2869 if (root->type=="friend class" || root->type=="friend struct" ||
2870 root->type=="friend union")
2875 addVariableToClass(rootNav, // entry
2876 cd, // class to add member to
2877 MemberType_Friend, // type of member
2878 name, // name of the member
2879 FALSE, // from Anonymous scope
2880 0, // anonymous member
2881 Public, // protection
2882 Member // related to a class
2887 /* skip this member, because it is a
2888 * static variable definition (always?), which will be
2889 * found in a class scope as well, but then we know the
2890 * correct protection level, so only then it will be
2891 * inserted in the correct list!
2896 mtype=MemberType_EnumValue;
2897 else if (type.left(8)=="typedef ")
2898 mtype=MemberType_Typedef;
2899 else if (type.left(7)=="friend ")
2900 mtype=MemberType_Friend;
2901 else if (root->mtype==Property)
2902 mtype=MemberType_Property;
2903 else if (root->mtype==Event)
2904 mtype=MemberType_Event;
2906 mtype=MemberType_Variable;
2908 if (!root->relates.isEmpty()) // related variable
2911 isMemberOf=(root->relatesType == MemberOf);
2912 if (getClass(root->relates)==0 && !scope.isEmpty())
2913 scope=mergeScopes(scope,root->relates);
2915 scope=root->relates;
2919 if (cd==0 && classScope!=scope) cd=getClass(classScope);
2924 // if cd is an anonymous (=tag less) scope we insert the member
2925 // into a non-anonymous parent scope as well. This is needed to
2926 // be able to refer to it using \var or \fn
2928 //int indentDepth=0;
2929 int si=scope.find('@');
2930 //int anonyScopes = 0;
2933 static bool inlineSimpleStructs = Config_getBool("INLINE_SIMPLE_STRUCTS");
2934 if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2938 pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2939 if (!pScope.isEmpty())
2940 pScope.prepend(annScopePrefix);
2941 else if (annScopePrefix.length()>2)
2942 pScope=annScopePrefix.left(annScopePrefix.length()-2);
2943 if (name.at(0)!='@')
2945 if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2947 md=addVariableToClass(rootNav, // entry
2948 pcd, // class to add member to
2949 mtype, // member type
2950 name, // member name
2951 TRUE, // from anonymous scope
2952 0, // from anonymous member
2954 isMemberOf ? Foreign : isRelated ? Related : Member
2958 else // anonymous scope inside namespace or file => put variable in the global scope
2960 if (mtype==MemberType_Variable)
2962 md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0);
2969 //printf("name=`%s' scope=%s scope.right=%s\n",
2970 // name.data(),scope.data(),
2971 // scope.right(scope.length()-si).data());
2972 addVariableToClass(rootNav, // entry
2973 cd, // class to add member to
2974 mtype, // member type
2975 name, // name of the member
2976 FALSE, // from anonymous scope
2977 md, // from anonymous member
2979 isMemberOf ? Foreign : isRelated ? Related : Member);
2981 else if (!name.isEmpty()) // global variable
2983 //printf("Inserting member in global scope %s!\n",scope.data());
2984 addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
2988 rootNav->releaseEntry();
2991 //----------------------------------------------------------------------
2992 // Searches the Entry tree for typedef documentation sections.
2993 // If found they are stored in their class or in the global list.
2994 static void buildTypedefList(EntryNav *rootNav)
2996 //printf("buildVarList(%s)\n",rootNav->name().data());
2997 if (!rootNav->name().isEmpty() &&
2998 rootNav->section()==Entry::VARIABLE_SEC &&
2999 rootNav->type().find("typedef ")!=-1 // its a typedef
3002 addVariable(rootNav);
3004 if (rootNav->children())
3006 EntryNavListIterator eli(*rootNav->children());
3008 for (;(e=eli.current());++eli)
3010 if (e->section()!=Entry::ENUM_SEC)
3012 buildTypedefList(e);
3018 //----------------------------------------------------------------------
3019 // Searches the Entry tree for Variable documentation sections.
3020 // If found they are stored in their class or in the global list.
3022 static void buildVarList(EntryNav *rootNav)
3024 //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
3026 if (!rootNav->name().isEmpty() &&
3027 (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
3029 (rootNav->section()==Entry::VARIABLE_SEC // it's a variable
3031 (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable
3032 (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
3034 (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
3035 isVarWithConstructor(rootNav)
3038 ) // documented variable
3040 addVariable(rootNav,isFuncPtr);
3042 if (rootNav->children())
3044 EntryNavListIterator eli(*rootNav->children());
3046 for (;(e=eli.current());++eli)
3048 if (e->section()!=Entry::ENUM_SEC)
3056 //----------------------------------------------------------------------
3057 // Searches the Entry tree for Interface sections (UNO IDL only).
3058 // If found they are stored in their service or in the global list.
3061 static void addInterfaceOrServiceToServiceOrSingleton(
3062 EntryNav *const rootNav,
3064 QCString const& rname)
3066 Entry *const root = rootNav->entry();
3067 FileDef *const fd = rootNav->fileDef();
3068 enum MemberType const type = (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC)
3069 ? MemberType_Interface
3070 : MemberType_Service;
3071 MemberDef *const md = new MemberDef(
3072 root->fileName, root->startLine, root->startColumn, root->type, rname,
3073 "", "", root->protection, root->virt, root->stat, Member,
3074 type, 0, root->argList);
3075 md->setTagInfo(rootNav->tagInfo());
3076 md->setMemberClass(cd);
3077 md->setDocumentation(root->doc,root->docFile,root->docLine);
3078 md->setDocsForDefinition(false);
3079 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3080 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3081 md->setBodySegment(root->bodyLine,root->endBodyLine);
3082 md->setMemberSpecifiers(root->spec);
3083 md->setMemberGroupId(root->mGrpId);
3084 md->setTypeConstraints(root->typeConstr);
3085 md->setLanguage(root->lang);
3088 md->addSectionsToDefinition(root->anchors);
3089 QCString const def = root->type + " " + rname;
3090 md->setDefinition(def);
3091 md->enableCallGraph(root->callGraph);
3092 md->enableCallerGraph(root->callerGraph);
3094 Debug::print(Debug::Functions,0,
3095 " Interface Member:\n"
3096 " `%s' `%s' proto=%d\n"
3104 // add member to the global list of all members
3106 if ((mn=Doxygen::memberNameSDict->find(rname)))
3112 mn = new MemberName(rname);
3114 Doxygen::memberNameSDict->append(rname,mn);
3117 // add member to the class cd
3118 cd->insertMember(md);
3119 // also add the member as a "base" (to get nicer diagrams)
3120 // "optional" interface/service get Protected which turns into dashed line
3121 BaseInfo base(rname,
3122 (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3123 findClassRelation(rootNav,cd,cd,&base,0,DocumentedOnly,true)
3124 || findClassRelation(rootNav,cd,cd,&base,0,Undocumented,true);
3125 // add file to list of used files
3126 cd->insertUsedFile(fd);
3128 addMemberToGroups(root,md);
3129 rootNav->changeSection(Entry::EMPTY_SEC);
3130 md->setRefItems(root->sli);
3133 static void buildInterfaceAndServiceList(EntryNav *const rootNav)
3135 if (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
3136 rootNav->section()==Entry::INCLUDED_SERVICE_SEC)
3138 rootNav->loadEntry(g_storage);
3139 Entry *const root = rootNav->entry();
3141 Debug::print(Debug::Functions,0,
3142 "EXPORTED_INTERFACE_SEC:\n"
3143 " `%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",
3145 rootNav->parent()->name().data(),
3148 root->relates.data(),
3150 root->fileName.data(),
3153 root->tArgLists ? (int)root->tArgLists->count() : -1,
3157 root->docFile.data()
3160 QCString const rname = removeRedundantWhiteSpace(root->name);
3162 if (!rname.isEmpty())
3164 QCString const scope = rootNav->parent()->name();
3165 ClassDef *const cd = getClass(scope);
3167 if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3168 (ClassDef::Service == cd->compoundType()) ||
3169 (ClassDef::Singleton == cd->compoundType())))
3171 addInterfaceOrServiceToServiceOrSingleton(rootNav,cd,rname);
3175 assert(false); // was checked by scanner.l
3178 else if (rname.isEmpty())
3180 warn(root->fileName,root->startLine,
3181 "Illegal member name found.");
3184 rootNav->releaseEntry();
3186 // can only have these in IDL anyway
3187 switch (rootNav->lang())
3189 case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3190 case SrcLangExt_IDL:
3191 RECURSE_ENTRYTREE(buildInterfaceAndServiceList,rootNav);
3194 return; // nothing to do here
3199 //----------------------------------------------------------------------
3200 // Searches the Entry tree for Function sections.
3201 // If found they are stored in their class or in the global list.
3203 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
3204 const QCString &rname,bool isFriend)
3206 Entry *root = rootNav->entry();
3207 FileDef *fd=rootNav->fileDef();
3210 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3211 int ts=root->type.find('<');
3212 int te=root->type.findRev('>');
3213 int i=re.match(root->type,0,&l);
3214 if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
3219 if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3220 !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3222 root->args+=root->type.right(root->type.length()-i-l);
3223 root->type=root->type.left(i+l);
3226 QCString name=removeRedundantWhiteSpace(rname);
3227 if (name.left(2)=="::") name=name.right(name.length()-2);
3230 if (isFriend) mtype=MemberType_Friend;
3231 else if (root->mtype==Signal) mtype=MemberType_Signal;
3232 else if (root->mtype==Slot) mtype=MemberType_Slot;
3233 else if (root->mtype==DCOP) mtype=MemberType_DCOP;
3234 else mtype=MemberType_Function;
3236 // strip redundant template specifier for constructors
3237 if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3238 name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3243 //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
3244 // root->name.data(),root->args.data(),argListToString(root->argList).data()
3247 // adding class member
3248 MemberDef *md=new MemberDef(
3249 root->fileName,root->startLine,root->startColumn,
3250 root->type,name,root->args,root->exception,
3251 root->protection,root->virt,
3252 root->stat && root->relatesType != MemberOf,
3253 root->relates.isEmpty() ? Member :
3254 root->relatesType == MemberOf ? Foreign : Related,
3255 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,root->argList);
3256 md->setTagInfo(rootNav->tagInfo());
3257 md->setMemberClass(cd);
3258 md->setDocumentation(root->doc,root->docFile,root->docLine);
3259 md->setDocsForDefinition(!root->proto);
3260 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3261 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3262 md->setBodySegment(root->bodyLine,root->endBodyLine);
3263 md->setMemberSpecifiers(root->spec);
3264 md->setMemberGroupId(root->mGrpId);
3265 md->setTypeConstraints(root->typeConstr);
3266 md->setLanguage(root->lang);
3267 md->setId(root->id);
3270 //md->setScopeTemplateArguments(root->tArgList);
3271 md->addSectionsToDefinition(root->anchors);
3273 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3274 SrcLangExt lang = cd->getLanguage();
3275 QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3276 if (scopeSeparator!="::")
3278 qualScope = substitute(qualScope,"::",scopeSeparator);
3280 if (lang==SrcLangExt_PHP)
3282 // for PHP we use Class::method and Namespace\method
3283 scopeSeparator="::";
3285 if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
3287 if (!root->type.isEmpty())
3291 def=root->type+" "+name;
3295 def=root->type+" "+name+root->args;
3306 def=name+root->args;
3312 if (!root->type.isEmpty())
3316 def=root->type+" "+qualScope+scopeSeparator+name;
3320 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3327 def=qualScope+scopeSeparator+name;
3331 def=qualScope+scopeSeparator+name+root->args;
3335 if (def.left(7)=="friend ") def=def.right(def.length()-7);
3336 md->setDefinition(def);
3337 md->enableCallGraph(root->callGraph);
3338 md->enableCallerGraph(root->callerGraph);
3340 Debug::print(Debug::Functions,0,
3342 " `%s' `%s'::`%s' `%s' proto=%d\n"
3352 // add member to the global list of all members
3353 //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3355 if ((mn=Doxygen::memberNameSDict->find(name)))
3361 mn = new MemberName(name);
3363 Doxygen::memberNameSDict->append(name,mn);
3366 // add member to the class cd
3367 cd->insertMember(md);
3368 // add file to list of used files
3369 cd->insertUsedFile(fd);
3371 addMemberToGroups(root,md);
3372 rootNav->changeSection(Entry::EMPTY_SEC);
3373 md->setRefItems(root->sli);
3377 static void buildFunctionList(EntryNav *rootNav)
3379 if (rootNav->section()==Entry::FUNCTION_SEC)
3381 rootNav->loadEntry(g_storage);
3382 Entry *root = rootNav->entry();
3384 Debug::print(Debug::Functions,0,
3386 " `%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",
3388 rootNav->parent()->name().data(),
3391 root->relates.data(),
3393 root->fileName.data(),
3396 root->tArgLists ? (int)root->tArgLists->count() : -1,
3400 root->docFile.data()
3403 bool isFriend=root->type.find("friend ")!=-1;
3404 QCString rname = removeRedundantWhiteSpace(root->name);
3405 //printf("rname=%s\n",rname.data());
3407 QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3408 if (!rname.isEmpty() && scope.find('@')==-1)
3411 // check if this function's parent is a class
3412 scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3414 FileDef *rfd=rootNav->fileDef();
3416 int memIndex=rname.findRev("::");
3419 if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3421 // strip scope from name
3422 rname=rname.right(rname.length()-rootNav->parent()->name().length()-2);
3425 NamespaceDef *nd = 0;
3426 bool isMember=FALSE;
3429 int ts=rname.find('<');
3430 int te=rname.find('>');
3431 if (memIndex>0 && (ts==-1 || te==-1))
3433 // note: the following code was replaced by inMember=TRUE to deal with a
3434 // function rname='X::foo' of class X inside a namespace also called X...
3436 //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3440 // // strip namespace scope from name
3441 // scope=rname.left(memIndex);
3442 // rname=rname.right(rname.length()-memIndex-2);
3448 isMember=memIndex<ts || memIndex>te;
3452 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3453 int ts=root->type.find('<');
3454 int te=root->type.findRev('>');
3456 if (!rootNav->parent()->name().isEmpty() &&
3457 (rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
3459 // do some fuzzy things to exclude function pointers
3460 (root->type.isEmpty() ||
3461 ((ti=root->type.find(re,0))==-1 || // type does not contain ..(..*
3462 (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3463 root->args.find(")[")!=-1) || // and args not )[.. -> function pointer
3464 root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3465 cd->getLanguage()!=SrcLangExt_Cpp // language other than C
3469 Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
3470 rname.data(),cd->name().data());
3471 addMethodToClass(rootNav,cd,rname,isFriend);
3473 else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK)
3474 || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3477 (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3478 root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3480 // no member => unrelated function
3482 /* check the uniqueness of the function name in the file.
3483 * A file could contain a function prototype and a function definition
3484 * or even multiple function prototypes.
3489 if ((mn=Doxygen::functionNameSDict->find(rname)))
3491 Debug::print(Debug::Functions,0," --> function %s already found!\n",rname.data());
3492 MemberNameIterator mni(*mn);
3493 for (mni.toFirst();(!found && (md=mni.current()));++mni)
3495 NamespaceDef *mnd = md->getNamespaceDef();
3496 NamespaceDef *rnd = 0;
3497 //printf("root namespace=%s\n",rootNav->parent()->name().data());
3498 QCString fullScope = scope;
3499 QCString parentScope = rootNav->parent()->name();
3500 if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3502 if (!scope.isEmpty()) fullScope.prepend("::");
3503 fullScope.prepend(parentScope);
3505 //printf("fullScope=%s\n",fullScope.data());
3506 rnd = getResolvedNamespace(fullScope);
3507 FileDef *mfd = md->getFileDef();
3508 QCString nsName,rnsName;
3509 if (mnd) nsName = mnd->name().copy();
3510 if (rnd) rnsName = rnd->name().copy();
3511 //printf("matching arguments for %s%s %s%s\n",
3512 // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3513 ArgumentList *mdAl = md->argumentList();
3514 ArgumentList *mdTempl = md->templateArguments();
3516 // in case of template functions, we need to check if the
3517 // functions have the same number of template parameters
3518 bool sameNumTemplateArgs = TRUE;
3519 bool matchingReturnTypes = TRUE;
3520 if (mdTempl!=0 && root->tArgLists)
3522 if (mdTempl->count()!=root->tArgLists->getLast()->count())
3524 sameNumTemplateArgs = FALSE;
3526 if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3528 matchingReturnTypes = FALSE;
3532 bool staticsInDifferentFiles =
3533 root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3536 matchArguments2(md->getOuterScope(),mfd,mdAl,
3537 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3539 sameNumTemplateArgs &&
3540 matchingReturnTypes &&
3541 !staticsInDifferentFiles
3545 if (root->groups->getFirst()!=0)
3547 gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
3549 //printf("match!\n");
3550 //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3551 // see if we need to create a new member
3552 found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace
3553 ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and
3554 mfd->absFilePath()==root->fileName // prototype in the same file
3557 // otherwise, allow a duplicate global member with the same argument list
3558 if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3560 // member is already in the group, so we don't want to add it again.
3564 //printf("combining function with prototype found=%d in namespace %s\n",
3565 // found,nsName.data());
3569 // merge argument lists
3570 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
3571 // merge documentation
3572 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3574 ArgumentList *argList = new ArgumentList;
3575 stringToArgumentList(root->args,argList);
3578 //printf("setDeclArgumentList to %p\n",argList);
3579 md->setDeclArgumentList(argList);
3583 md->setArgumentList(argList);
3587 md->setDocumentation(root->doc,root->docFile,root->docLine);
3588 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3589 md->setDocsForDefinition(!root->proto);
3590 if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3592 md->setBodySegment(root->bodyLine,root->endBodyLine);
3593 md->setBodyDef(rfd);
3596 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3598 md->setArgsString(root->args);
3600 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3602 md->addSectionsToDefinition(root->anchors);
3604 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3605 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3607 // merge ingroup specifiers
3608 if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
3610 addMemberToGroups(root,md);
3612 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3614 //printf("existing member is grouped, new member not\n");
3615 root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3617 else if (md->getGroupDef()!=0 && root->groups->getFirst()!=0)
3619 //printf("both members are grouped\n");
3622 // if md is a declaration and root is the corresponding
3623 // definition, then turn md into a definition.
3624 if (md->isPrototype() && !root->proto)
3626 md->setPrototype(FALSE);
3632 if (!found) /* global function is unique with respect to the file */
3634 Debug::print(Debug::Functions,0," --> new function %s found!\n",rname.data());
3635 //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3636 // root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3638 // new global function
3639 ArgumentList *tArgList = root->tArgLists ? root->tArgLists->getLast() : 0;
3640 QCString name=removeRedundantWhiteSpace(rname);
3642 root->fileName,root->startLine,root->startColumn,
3643 root->type,name,root->args,root->exception,
3644 root->protection,root->virt,root->stat,Member,
3645 MemberType_Function,tArgList,root->argList);
3647 md->setTagInfo(rootNav->tagInfo());
3648 md->setLanguage(root->lang);
3649 md->setId(root->id);
3650 //md->setDefFile(root->fileName);
3651 //md->setDefLine(root->startLine);
3652 md->setDocumentation(root->doc,root->docFile,root->docLine);
3653 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3654 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3655 md->setPrototype(root->proto);
3656 md->setDocsForDefinition(!root->proto);
3657 md->setTypeConstraints(root->typeConstr);
3658 //md->setBody(root->body);
3659 md->setBodySegment(root->bodyLine,root->endBodyLine);
3660 FileDef *fd=rootNav->fileDef();
3662 md->addSectionsToDefinition(root->anchors);
3663 md->setMemberSpecifiers(root->spec);
3664 md->setMemberGroupId(root->mGrpId);
3666 // see if the function is inside a namespace that was not part of
3667 // the name already (in that case nd should be non-zero already)
3668 if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3670 //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3671 QCString nscope=rootNav->parent()->name();
3672 if (!nscope.isEmpty())
3674 nd = getResolvedNamespace(nscope);
3678 if (!scope.isEmpty())
3680 QCString sep = getLanguageSpecificSeparator(root->lang);
3683 scope = substitute(scope,"::",sep);
3689 if (!root->type.isEmpty())
3693 def=root->type+" "+scope+name;
3697 def=root->type+" "+scope+name+root->args;
3704 def=scope+name.copy();
3708 def=scope+name+root->args;
3711 Debug::print(Debug::Functions,0,
3712 " Global Function:\n"
3713 " `%s' `%s'::`%s' `%s' proto=%d\n"
3716 rootNav->parent()->name().data(),
3722 md->setDefinition(def);
3723 md->enableCallGraph(root->callGraph);
3724 md->enableCallerGraph(root->callerGraph);
3725 //if (root->mGrpId!=-1)
3727 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
3730 md->setRefItems(root->sli);
3731 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3733 // add member to namespace
3734 md->setNamespace(nd);
3735 nd->insertMember(md);
3739 // add member to the file (we do this even if we have already
3740 // inserted it into the namespace)
3742 fd->insertMember(md);
3745 // add member to the list of file members
3746 //printf("Adding member=%s\n",md->name().data());
3748 if ((mn=Doxygen::functionNameSDict->find(name)))
3754 mn = new MemberName(name);
3756 Doxygen::functionNameSDict->append(name,mn);
3758 addMemberToGroups(root,md);
3759 if (root->relatesType == Simple) // if this is a relatesalso command,
3760 // allow find Member to pick it up
3762 rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished
3769 FileDef *fd=rootNav->fileDef();
3772 // add member to the file (we do this even if we have already
3773 // inserted it into the namespace)
3774 fd->insertMember(md);
3778 //printf("unrelated function %d `%s' `%s' `%s'\n",
3779 // root->parent->section,root->type.data(),rname.data(),root->args.data());
3783 Debug::print(Debug::Functions,0," --> %s not processed!\n",rname.data());
3786 else if (rname.isEmpty())
3788 warn(root->fileName,root->startLine,
3789 "Illegal member name found."
3793 rootNav->releaseEntry();
3795 RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3798 //----------------------------------------------------------------------
3800 static void findFriends()
3802 //printf("findFriends()\n");
3803 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3805 for (;(fn=fnli.current());++fnli) // for each global function name
3807 //printf("Function name=`%s'\n",fn->memberName());
3809 if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3810 { // there are members with the same name
3811 //printf("Function name is also a member name\n");
3812 MemberNameIterator fni(*fn);
3814 for (;(fmd=fni.current());++fni) // for each function with that name
3816 MemberNameIterator mni(*mn);
3818 for (;(mmd=mni.current());++mni) // for each member with that name
3820 //printf("Checking for matching arguments
3821 // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3822 // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3823 ArgumentList *mmdAl = mmd->argumentList();
3824 ArgumentList *fmdAl = fmd->argumentList();
3825 if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3826 matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl,
3827 fmd->getOuterScope(), fmd->getFileDef(), fmdAl,
3831 ) // if the member is related and the arguments match then the
3832 // function is actually a friend.
3834 mergeArguments(mmdAl,fmdAl);
3835 if (!fmd->documentation().isEmpty())
3837 mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3839 else if (!mmd->documentation().isEmpty())
3841 fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3843 if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3845 mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3847 else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3849 fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3851 if (!fmd->inbodyDocumentation().isEmpty())
3853 mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3855 else if (!mmd->inbodyDocumentation().isEmpty())
3857 fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3859 //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3860 if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3862 mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3863 mmd->setBodyDef(fmd->getBodyDef());
3864 //mmd->setBodyMember(fmd);
3866 else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3868 fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3869 fmd->setBodyDef(mmd->getBodyDef());
3870 //fmd->setBodyMember(mmd);
3872 mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3874 mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3875 mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3876 fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3877 fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3885 //----------------------------------------------------------------------
3887 static void transferFunctionDocumentation()
3889 //printf("---- transferFunctionDocumentation()\n");
3891 // find matching function declaration and definitions.
3892 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3894 for (;(mn=mnli.current());++mnli)
3896 //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3897 MemberDef *mdef=0,*mdec=0;
3898 MemberNameIterator mni1(*mn);
3899 /* find a matching function declaration and definition for this function */
3900 for (;(mdec=mni1.current());++mni1)
3902 if (mdec->isPrototype() ||
3903 (mdec->isVariable() && mdec->isExternal())
3906 MemberNameIterator mni2(*mn);
3907 for (;(mdef=mni2.current());++mni2)
3909 combineDeclarationAndDefinition(mdec,mdef);
3916 //----------------------------------------------------------------------
3918 static void transferFunctionReferences()
3920 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3922 for (;(mn=mnli.current());++mnli)
3924 MemberDef *md,*mdef=0,*mdec=0;
3925 MemberNameIterator mni(*mn);
3926 /* find a matching function declaration and definition for this function */
3927 for (;(md=mni.current());++mni)
3929 if (md->isPrototype())
3931 else if (md->isVariable() && md->isExternal())
3934 if (md->isFunction() && !md->isStatic() && !md->isPrototype())
3936 else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3941 ArgumentList *mdefAl = mdef->argumentList();
3942 ArgumentList *mdecAl = mdec->argumentList();
3944 matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
3945 mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
3950 MemberSDict *defDict = mdef->getReferencesMembers();
3951 MemberSDict *decDict = mdec->getReferencesMembers();
3954 MemberSDict::IteratorDict msdi(*defDict);
3956 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3958 if (decDict==0 || decDict->find(rmd->name())==0)
3960 mdec->addSourceReferences(rmd);
3966 MemberSDict::IteratorDict msdi(*decDict);
3968 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3970 if (defDict==0 || defDict->find(rmd->name())==0)
3972 mdef->addSourceReferences(rmd);
3977 defDict = mdef->getReferencedByMembers();
3978 decDict = mdec->getReferencedByMembers();
3981 MemberSDict::IteratorDict msdi(*defDict);
3983 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3985 if (decDict==0 || decDict->find(rmd->name())==0)
3987 mdec->addSourceReferencedBy(rmd);
3993 MemberSDict::IteratorDict msdi(*decDict);
3995 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3997 if (defDict==0 || defDict->find(rmd->name())==0)
3999 mdef->addSourceReferencedBy(rmd);
4008 //----------------------------------------------------------------------
4010 static void transferRelatedFunctionDocumentation()
4012 // find match between function declaration and definition for
4013 // related functions
4014 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4016 for (mnli.toFirst();(mn=mnli.current());++mnli)
4019 MemberNameIterator mni(*mn);
4020 /* find a matching function declaration and definition for this function */
4021 for (mni.toFirst();(md=mni.current());++mni) // for each global function
4023 //printf(" Function `%s'\n",md->name().data());
4025 if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
4027 //printf(" Member name found\n");
4029 MemberNameIterator rmni(*rmn);
4030 for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
4032 ArgumentList *mdAl = md->argumentList();
4033 ArgumentList *rmdAl = rmd->argumentList();
4034 //printf(" Member found: related=`%d'\n",rmd->isRelated());
4035 if ((rmd->isRelated() || rmd->isForeign()) && // related function
4036 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4037 rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
4042 //printf(" Found related member `%s'\n",md->name().data());
4043 if (rmd->relatedAlso())
4044 md->setRelatedAlso(rmd->relatedAlso());
4045 else if (rmd->isForeign())
4056 //----------------------------------------------------------------------
4058 /*! make a dictionary of all template arguments of class cd
4059 * that are part of the base class name.
4060 * Example: A template class A with template arguments <R,S,T>
4061 * that inherits from B<T,T,S> will have T and S in the dictionary.
4063 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
4065 QDict<int> *templateNames = new QDict<int>(17);
4066 templateNames->setAutoDelete(TRUE);
4067 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
4068 if (templateArguments)
4070 ArgumentListIterator ali(*templateArguments);
4073 for (ali.toFirst();(arg=ali.current());++ali,count++)
4076 while ((i=re.match(name,p,&l))!=-1)
4078 QCString n = name.mid(i,l);
4081 if (templateNames->find(n)==0)
4083 templateNames->insert(n,new int(count));
4090 return templateNames;
4093 /*! Searches a class from within \a context and \a cd and returns its
4094 * definition if found (otherwise 0 is returned).
4096 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
4098 FileDef *fd=cd->getFileDef();
4100 if (context && cd!=context)
4102 result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
4106 result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
4108 if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4110 result = getClass(name);
4112 if (result==0 && cd && cd->getLanguage()==SrcLangExt_CSharp && name.find('<')!=-1)
4114 result = Doxygen::genericsDict->find(name);
4116 //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4118 // context ? context->name().data() : "<none>",
4119 // cd ? cd->name().data() : "<none>",
4120 // result ? result->name().data() : "<none>",
4121 // Doxygen::classSDict->find(name)
4127 static void findUsedClassesForClass(EntryNav *rootNav,
4128 Definition *context,
4130 ClassDef *instanceCd,
4132 ArgumentList *actualArgs=0,
4133 QDict<int> *templateNames=0
4136 masterCd->visited=TRUE;
4137 ArgumentList *formalArgs = masterCd->templateArguments();
4138 if (masterCd->memberNameInfoSDict())
4140 MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
4141 MemberNameInfo *mni;
4142 for (;(mni=mnili.current());++mnili)
4144 MemberNameInfoIterator mnii(*mni);
4146 for (mnii.toFirst();(mi=mnii.current());++mnii)
4148 MemberDef *md=mi->memberDef;
4149 if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4151 //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
4152 QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4153 QCString typedefValue = resolveTypeDef(masterCd,type);
4154 if (!typedefValue.isEmpty())
4156 type = typedefValue;
4159 QCString usedClassName;
4162 // the type can contain template variables, replace them if present
4165 type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4168 //printf(" template substitution gives=%s\n",type.data());
4169 while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
4171 // find the type (if any) that matches usedClassName
4172 ClassDef *typeCd = getResolvedClass(masterCd,
4173 masterCd->getFileDef(),
4178 //printf("====> usedClassName=%s -> typeCd=%s\n",
4179 // usedClassName.data(),typeCd?typeCd->name().data():"<none>");
4182 usedClassName = typeCd->name();
4185 int sp=usedClassName.find('<');
4187 int si=usedClassName.findRev("::",sp);
4190 // replace any namespace aliases
4191 replaceNamespaceAliases(usedClassName,si);
4193 // add any template arguments to the class
4194 QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4195 //printf(" usedName=%s\n",usedName.data());
4197 bool delTempNames=FALSE;
4198 if (templateNames==0)
4200 templateNames = getTemplateArgumentsInName(formalArgs,usedName);
4203 BaseInfo bi(usedName,Public,Normal);
4204 findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
4206 if (masterCd->templateArguments())
4208 ArgumentListIterator ali(*masterCd->templateArguments());
4211 for (ali.toFirst();(arg=ali.current());++ali,++count)
4213 if (arg->name==usedName) // type is a template argument
4216 Debug::print(Debug::Classes,0," New used class `%s'\n", usedName.data());
4218 ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
4221 usedCd = new ClassDef(
4222 masterCd->getDefFileName(),masterCd->getDefLine(),
4223 masterCd->getDefColumn(),
4226 //printf("making %s a template argument!!!\n",usedCd->name().data());
4227 usedCd->makeTemplateArgument();
4228 usedCd->setUsedOnly(TRUE);
4229 usedCd->setLanguage(masterCd->getLanguage());
4230 Doxygen::hiddenClasses->append(usedName,usedCd);
4234 if (isArtificial) usedCd->setArtificial(TRUE);
4235 Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", usedCd->name().data());
4236 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4237 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4245 ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4246 //printf("Looking for used class %s: result=%s master=%s\n",
4247 // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
4252 Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", usedCd->name().data());
4253 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
4254 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4259 delete templateNames;
4263 if (!found && !type.isEmpty()) // used class is not documented in any scope
4265 ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4266 if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
4268 if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4270 type+=md->argsString();
4272 Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", type.data());
4273 usedCd = new ClassDef(
4274 masterCd->getDefFileName(),masterCd->getDefLine(),
4275 masterCd->getDefColumn(),
4276 type,ClassDef::Class);
4277 usedCd->setUsedOnly(TRUE);
4278 usedCd->setLanguage(masterCd->getLanguage());
4279 Doxygen::hiddenClasses->append(type,usedCd);
4283 if (isArtificial) usedCd->setArtificial(TRUE);
4284 Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", usedCd->name().data());
4285 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4286 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4295 //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4299 static void findBaseClassesForClass(
4301 Definition *context,
4303 ClassDef *instanceCd,
4304 FindBaseClassRelation_Mode mode,
4306 ArgumentList *actualArgs=0,
4307 QDict<int> *templateNames=0
4310 Entry *root = rootNav->entry();
4311 //if (masterCd->visited) return;
4312 masterCd->visited=TRUE;
4313 // The base class could ofcouse also be a non-nested class
4314 ArgumentList *formalArgs = masterCd->templateArguments();
4315 QListIterator<BaseInfo> bii(*root->extends);
4317 for (bii.toFirst();(bi=bii.current());++bii)
4319 //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4320 // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4321 bool delTempNames=FALSE;
4322 if (templateNames==0)
4324 templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4327 BaseInfo tbi(bi->name,bi->prot,bi->virt);
4328 if (actualArgs) // substitute the formal template arguments of the base class
4330 tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4332 //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4334 if (mode==DocumentedOnly)
4336 // find a documented base class in the correct scope
4337 if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4339 // 1.8.2: decided to show inheritance relations even if not documented,
4340 // we do make them artificial, so they do not appear in the index
4341 //if (!Config_getBool("HIDE_UNDOC_RELATIONS"))
4342 bool b = Config_getBool("HIDE_UNDOC_RELATIONS") ? TRUE : isArtificial;
4344 // no documented base class -> try to find an undocumented one
4345 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4349 else if (mode==TemplateInstances)
4351 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4355 delete templateNames;
4361 //----------------------------------------------------------------------
4363 static bool findTemplateInstanceRelation(Entry *root,
4364 Definition *context,
4365 ClassDef *templateClass,const QCString &templSpec,
4366 QDict<int> *templateNames,
4369 Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n",
4370 templateClass->name().data(),templSpec.data());
4371 //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4372 // templateClass->name().data(),templSpec.data());
4373 //if (templateNames)
4375 // QDictIterator<int> qdi(*templateNames);
4376 // int *tempArgIndex;
4377 // for (;(tempArgIndex=qdi.current());++qdi)
4379 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4384 bool existingClass = (templSpec ==
4385 tempArgListToString(templateClass->templateArguments())
4387 if (existingClass) return TRUE;
4389 bool freshInstance=FALSE;
4390 ClassDef *instanceClass = templateClass->insertTemplateInstance(
4391 root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4392 if (isArtificial) instanceClass->setArtificial(TRUE);
4393 instanceClass->setLanguage(root->lang);
4397 Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",instanceClass->name().data());
4398 Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4399 instanceClass->setTemplateBaseClassNames(templateNames);
4401 // search for new template instances caused by base classes of
4403 EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4404 if (templateRootNav)
4406 bool unloadNeeded=FALSE;
4407 Entry *templateRoot = templateRootNav->entry();
4408 if (templateRoot==0) // not yet loaded
4410 templateRootNav->loadEntry(g_storage);
4411 templateRoot = templateRootNav->entry();
4412 ASSERT(templateRoot!=0); // now it should really be loaded
4416 Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",
4417 templateRoot->name.data(),templSpec.data());
4418 ArgumentList *templArgs = new ArgumentList;
4419 stringToArgumentList(templSpec,templArgs);
4420 findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4421 TemplateInstances,isArtificial,templArgs,templateNames);
4423 findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4424 isArtificial,templArgs,templateNames);
4427 if (unloadNeeded) // still cleanup to do
4429 templateRootNav->releaseEntry();
4434 Debug::print(Debug::Classes,0," no template root entry found!\n");
4435 // TODO: what happened if we get here?
4438 //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data());
4439 //ArgumentList *tl = templateClass->templateArguments();
4443 Debug::print(Debug::Classes,0," instance already exists!\n");
4448 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4451 int index=n.find('<');
4456 bool result = rightScopeMatch(scope,n);
4460 /*! Searches for the end of a template in prototype \a s starting from
4461 * character position \a startPos. If the end was found the position
4462 * of the closing \> is returned, otherwise -1 is returned.
4464 * Handles exotic cases such as
4473 static int findEndOfTemplate(const QCString &s,int startPos)
4475 // locate end of template
4479 int len = s.length();
4480 bool insideString=FALSE;
4481 bool insideChar=FALSE;
4483 while (e<len && brCount!=0)
4489 if (!insideString && !insideChar)
4491 if (e<len-1 && s.at(e+1)=='<')
4493 else if (roundCount==0)
4498 if (!insideString && !insideChar)
4500 if (e<len-1 && s.at(e+1)=='>')
4502 else if (roundCount==0)
4507 if (!insideString && !insideChar)
4511 if (!insideString && !insideChar)
4517 if (insideString && pc!='\\')
4526 if (insideChar && pc!='\\')
4536 return brCount==0 ? e : -1;
4539 static bool findClassRelation(
4541 Definition *context,
4544 QDict<int> *templateNames,
4545 FindBaseClassRelation_Mode mode,
4549 //printf("findClassRelation(class=%s base=%s templateNames=",
4550 // cd->name().data(),bi->name.data());
4551 //if (templateNames)
4553 // QDictIterator<int> qdi(*templateNames);
4554 // int *tempArgIndex;
4555 // for (;(tempArgIndex=qdi.current());++qdi)
4557 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4562 Entry *root = rootNav->entry();
4564 QCString biName=bi->name;
4565 bool explicitGlobalScope=FALSE;
4566 //printf("findClassRelation: biName=`%s'\n",biName.data());
4567 if (biName.left(2)=="::") // explicit global scope
4569 biName=biName.right(biName.length()-2);
4570 explicitGlobalScope=TRUE;
4573 EntryNav *parentNode=rootNav->parent();
4574 bool lastParent=FALSE;
4575 do // for each parent scope, starting with the largest scope
4576 // (in case of nested classes)
4578 QCString scopeName= parentNode ? parentNode->name().data() : "";
4579 int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4580 do // try all parent scope prefixes, starting with the largest scope
4582 //printf("scopePrefix=`%s' biName=`%s'\n",
4583 // scopeName.left(scopeOffset).data(),biName.data());
4585 QCString baseClassName=biName;
4588 baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4590 //QCString stripped;
4591 //baseClassName=stripTemplateSpecifiersFromScope
4592 // (removeRedundantWhiteSpace(baseClassName),TRUE,
4594 MemberDef *baseClassTypeDef=0;
4596 ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4604 //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4605 // baseClassName.data(),baseClass,cd,explicitGlobalScope);
4606 //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4607 // cd ? cd->name().data():"<none>",
4608 // baseClassName.data(),
4609 // baseClass?baseClass->name().data():"<none>",
4612 //if (baseClassName.left(root->name.length())!=root->name ||
4613 // baseClassName.at(root->name.length())!='<'
4614 // ) // Check for base class with the same name.
4615 // // If found then look in the outer scope for a match
4616 // // and prevent recursion.
4617 if (!isRecursiveBaseClass(rootNav->name(),baseClassName)
4618 || explicitGlobalScope
4619 // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4620 // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4621 || (rootNav->lang()==SrcLangExt_IDL &&
4622 (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
4623 rootNav->section()==Entry::INCLUDED_SERVICE_SEC)))
4626 Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4627 baseClassName.data(),
4628 rootNav->name().data(),
4629 (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4630 (bi->virt==Normal)?"normal":"virtual",
4634 int i=baseClassName.find('<');
4635 int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4637 if (baseClass==0 && i!=-1)
4638 // base class has template specifiers
4640 if (root->lang == SrcLangExt_CSharp)
4642 baseClass = Doxygen::genericsDict->find(baseClassName);
4646 // TODO: here we should try to find the correct template specialization
4647 // but for now, we only look for the unspecializated base class.
4648 int e=findEndOfTemplate(baseClassName,i+1);
4649 //printf("baseClass==0 i=%d e=%d\n",i,e);
4650 if (e!=-1) // end of template was found at e
4652 templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4653 baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4654 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4662 //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4663 // baseClass,baseClassName.data(),templSpec.data());
4667 else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4668 // know it is a template, so see if
4669 // we can also link to the explicit
4670 // instance (for instance if a class
4671 // derived from a template argument)
4673 //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4674 ClassDef *templClass=getClass(baseClass->name()+templSpec);
4677 // use the template instance instead of the template base.
4678 baseClass = templClass;
4679 templSpec.resize(0);
4683 //printf("cd=%p baseClass=%p\n",cd,baseClass);
4684 bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4685 //printf("1. found=%d\n",found);
4686 if (!found && si!=-1)
4688 QCString tmpTemplSpec;
4689 // replace any namespace aliases
4690 replaceNamespaceAliases(baseClassName,si);
4691 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4699 found=baseClass!=0 && baseClass!=cd;
4700 if (found) templSpec = tmpTemplSpec;
4702 //printf("2. found=%d\n",found);
4704 //printf("root->name=%s biName=%s baseClassName=%s\n",
4705 // root->name.data(),biName.data(),baseClassName.data());
4706 //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4708 // baseClassName+="-g";
4713 baseClass=findClassWithinClassContext(context,cd,baseClassName);
4714 //printf("findClassWithinClassContext(%s,%s)=%p\n",
4715 // cd->name().data(),baseClassName.data(),baseClass);
4716 found = baseClass!=0 && baseClass!=cd;
4721 // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4722 // the class name also in the alias mapping.
4723 QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4724 if (aliasName) // see if it is indeed a class.
4726 baseClass=getClass(*aliasName);
4727 found = baseClass!=0 && baseClass!=cd;
4730 bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4731 // make templSpec canonical
4732 // warning: the following line doesn't work for Mixin classes (see bug 560623)
4733 // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4735 //printf("3. found=%d\n",found);
4738 Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
4739 // add base class to this class
4741 // if templSpec is not empty then we should "instantiate"
4742 // the template baseClass. A new ClassDef should be created
4743 // to represent the instance. To be able to add the (instantiated)
4744 // members and documentation of a template class
4745 // (inserted in that template class at a later stage),
4746 // the template should know about its instances.
4747 // the instantiation process, should be done in a recursive way,
4748 // since instantiating a template may introduce new inheritance
4750 if (!templSpec.isEmpty() && mode==TemplateInstances)
4752 // if baseClass is actually a typedef then we should not
4753 // instantiate it, since typedefs are in a different namespace
4754 // see bug531637 for an example where this would otherwise hang
4756 if (baseClassTypeDef==0)
4758 //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4759 findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4762 else if (mode==DocumentedOnly || mode==Undocumented)
4764 //printf(" => insert base class\n");
4766 if (baseClassTypeDef || cd->isCSharp())
4769 //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4771 static bool sipSupport = Config_getBool("SIP_SUPPORT");
4772 if (sipSupport) bi->prot=Public;
4773 if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4775 cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4776 // add this class as super class to the base class
4777 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4781 warn(root->fileName,root->startLine,
4782 "Detected potential recursive class relation "
4783 "between class %s and base class %s!",
4784 cd->name().data(),baseClass->name().data()
4790 else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4792 Debug::print(Debug::Classes,0,
4793 " New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4794 biName.data(),baseClassName.data(),templSpec.data(),isArtificial
4797 if (isATemplateArgument)
4799 baseClass=Doxygen::hiddenClasses->find(baseClassName);
4802 baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4805 Doxygen::hiddenClasses->append(baseClassName,baseClass);
4806 if (isArtificial) baseClass->setArtificial(TRUE);
4807 baseClass->setLanguage(root->lang);
4812 baseClass=Doxygen::classSDict->find(baseClassName);
4813 //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4814 // baseClassName.data(),baseClass,biName.data(),templSpec.data());
4817 baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4820 Doxygen::classSDict->append(baseClassName,baseClass);
4821 if (isArtificial) baseClass->setArtificial(TRUE);
4822 baseClass->setLanguage(root->lang);
4823 int si = baseClassName.findRev("::");
4824 if (si!=-1) // class is nested
4826 Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si));
4827 if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4829 baseClass->setArtificial(TRUE); // see bug678139
4834 if (biName.right(2)=="-p")
4836 biName="<"+biName.left(biName.length()-2)+">";
4838 // add base class to this class
4839 cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4840 // add this class as super class to the base class
4841 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4842 // the undocumented base was found in this file
4843 baseClass->insertUsedFile(rootNav->fileDef());
4844 baseClass->setOuterScope(Doxygen::globalScope);
4845 if (baseClassName.right(2)=="-p")
4847 baseClass->setCompoundType(ClassDef::Protocol);
4853 Debug::print(Debug::Classes,0," Base class `%s' not found\n",biName.data());
4858 if (mode!=TemplateInstances)
4860 warn(root->fileName,root->startLine,
4861 "Detected potential recursive class relation "
4862 "between class %s and base class %s!\n",
4863 root->name.data(),baseClassName.data()
4866 // for mode==TemplateInstance this case is quite common and
4867 // indicates a relation between a template class and a template
4868 // instance with the same name.
4874 else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4878 //printf("new scopeOffset=`%d'",scopeOffset);
4879 } while (scopeOffset>=0);
4887 parentNode=parentNode->parent();
4889 } while (lastParent);
4894 //----------------------------------------------------------------------
4895 // Computes the base and super classes for each class in the tree
4897 static bool isClassSection(EntryNav *rootNav)
4899 if ( !rootNav->name().isEmpty() )
4901 if (rootNav->section() & Entry::COMPOUND_MASK)
4902 // is it a compound (class, struct, union, interface ...)
4906 else if (rootNav->section() & Entry::COMPOUNDDOC_MASK)
4907 // is it a documentation block with inheritance info.
4909 rootNav->loadEntry(g_storage);
4910 Entry *root = rootNav->entry();
4911 bool extends = root->extends->count()>0;
4912 rootNav->releaseEntry();
4913 if (extends) return TRUE;
4920 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
4922 static void findClassEntries(EntryNav *rootNav)
4924 if (isClassSection(rootNav))
4926 g_classEntries.insert(rootNav->name(),rootNav);
4928 RECURSE_ENTRYTREE(findClassEntries,rootNav);
4931 /*! Using the dictionary build by findClassEntries(), this
4932 * function will look for additional template specialization that
4933 * exists as inheritance relations only. These instances will be
4934 * added to the template they are derived from.
4936 static void findInheritedTemplateInstances()
4938 ClassSDict::Iterator cli(*Doxygen::classSDict);
4939 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4940 QDictIterator<EntryNav> edi(g_classEntries);
4942 for (;(rootNav=edi.current());++edi)
4945 // strip any anonymous scopes first
4946 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4947 bName=stripTemplateSpecifiersFromScope(bName);
4948 Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",bName.data());
4949 if ((cd=getClass(bName)))
4951 rootNav->loadEntry(g_storage);
4952 //printf("Class %s %d\n",cd->name().data(),root->extends->count());
4953 findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
4954 rootNav->releaseEntry();
4959 static void findUsedTemplateInstances()
4961 ClassSDict::Iterator cli(*Doxygen::classSDict);
4962 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4963 QDictIterator<EntryNav> edi(g_classEntries);
4965 for (;(rootNav=edi.current());++edi)
4968 // strip any anonymous scopes first
4969 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4970 bName=stripTemplateSpecifiersFromScope(bName);
4971 Debug::print(Debug::Classes,0," Usage: Class %s : \n",bName.data());
4972 if ((cd=getClass(bName)))
4974 rootNav->loadEntry(g_storage);
4975 findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
4976 rootNav->releaseEntry();
4981 static void computeClassRelations()
4983 ClassSDict::Iterator cli(*Doxygen::classSDict);
4984 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4985 QDictIterator<EntryNav> edi(g_classEntries);
4987 for (;(rootNav=edi.current());++edi)
4991 rootNav->loadEntry(g_storage);
4992 Entry *root = rootNav->entry();
4994 // strip any anonymous scopes first
4995 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4996 bName=stripTemplateSpecifiersFromScope(bName);
4997 Debug::print(Debug::Classes,0," Relations: Class %s : \n",bName.data());
4998 if ((cd=getClass(bName)))
5000 findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
5002 int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
5003 if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
5004 bName.right(2)!="::")
5006 if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
5007 (guessSection(root->fileName)==Entry::HEADER_SEC ||
5008 Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
5009 protectionLevelVisible(root->protection) && // hidden by protection
5010 !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
5013 root->fileName,root->startLine,
5014 "Compound %s is not documented.",
5019 rootNav->releaseEntry();
5023 static void computeTemplateClassRelations()
5025 QDictIterator<EntryNav> edi(g_classEntries);
5027 for (;(rootNav=edi.current());++edi)
5029 rootNav->loadEntry(g_storage);
5030 Entry *root = rootNav->entry();
5032 QCString bName=stripAnonymousNamespaceScope(root->name);
5033 bName=stripTemplateSpecifiersFromScope(bName);
5034 ClassDef *cd=getClass(bName);
5035 // strip any anonymous scopes first
5036 QDict<ClassDef> *templInstances = 0;
5037 if (cd && (templInstances=cd->getTemplateInstances()))
5039 Debug::print(Debug::Classes,0," Template class %s : \n",cd->name().data());
5040 QDictIterator<ClassDef> tdi(*templInstances);
5042 for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
5044 Debug::print(Debug::Classes,0," Template instance %s : \n",tcd->name().data());
5045 QCString templSpec = tdi.currentKey();
5046 ArgumentList *templArgs = new ArgumentList;
5047 stringToArgumentList(templSpec,templArgs);
5048 QList<BaseInfo> *baseList=root->extends;
5049 QListIterator<BaseInfo> it(*baseList);
5051 for (;(bi=it.current());++it) // for each base class of the template
5053 // check if the base class is a template argument
5054 BaseInfo tbi(bi->name,bi->prot,bi->virt);
5055 ArgumentList *tl = cd->templateArguments();
5058 QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
5059 QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
5060 // for each template name that we inherit from we need to
5061 // substitute the formal with the actual arguments
5062 QDict<int> *actualTemplateNames = new QDict<int>(17);
5063 actualTemplateNames->setAutoDelete(TRUE);
5064 QDictIterator<int> qdi(*templateNames);
5065 for (qdi.toFirst();qdi.current();++qdi)
5067 int templIndex = *qdi.current();
5068 Argument *actArg = 0;
5069 if (templIndex<(int)templArgs->count())
5071 actArg=templArgs->at(templIndex);
5074 baseClassNames!=0 &&
5075 baseClassNames->find(actArg->type)!=0 &&
5076 actualTemplateNames->find(actArg->type)==0
5079 actualTemplateNames->insert(actArg->type,new int(templIndex));
5082 delete templateNames;
5084 tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
5085 // find a documented base class in the correct scope
5086 if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
5088 // no documented base class -> try to find an undocumented one
5089 findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
5091 delete actualTemplateNames;
5095 } // class has no base classes
5098 rootNav->releaseEntry();
5102 //-----------------------------------------------------------------------
5103 // compute the references (anchors in HTML) for each function in the file
5105 static void computeMemberReferences()
5107 ClassSDict::Iterator cli(*Doxygen::classSDict);
5109 for (cli.toFirst();(cd=cli.current());++cli)
5111 cd->computeAnchors();
5113 FileNameListIterator fnli(*Doxygen::inputNameList);
5115 for (fnli.toFirst();(fn=fnli.current());++fnli)
5117 FileNameIterator fni(*fn);
5119 for (;(fd=fni.current());++fni)
5121 fd->computeAnchors();
5124 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5126 for (nli.toFirst();(nd=nli.current());++nli)
5128 nd->computeAnchors();
5130 GroupSDict::Iterator gli(*Doxygen::groupSDict);
5132 for (gli.toFirst();(gd=gli.current());++gli)
5134 gd->computeAnchors();
5138 //----------------------------------------------------------------------
5140 static void addListReferences()
5142 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
5144 for (mnli.toFirst();(mn=mnli.current());++mnli)
5146 MemberNameIterator mni(*mn);
5148 for (mni.toFirst();(md=mni.current());++mni)
5153 MemberNameSDict::Iterator fmnli(*Doxygen::functionNameSDict);
5154 for (fmnli.toFirst();(mn=fmnli.current());++fmnli)
5156 MemberNameIterator mni(*mn);
5158 for (mni.toFirst();(md=mni.current());++mni)
5164 ClassSDict::Iterator cli(*Doxygen::classSDict);
5166 for (cli.toFirst();(cd=cli.current());++cli)
5168 cd->addListReferences();
5171 FileNameListIterator fnli(*Doxygen::inputNameList);
5173 for (fnli.toFirst();(fn=fnli.current());++fnli)
5175 FileNameIterator fni(*fn);
5177 for (;(fd=fni.current());++fni)
5179 fd->addListReferences();
5183 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5185 for (nli.toFirst();(nd=nli.current());++nli)
5187 nd->addListReferences();
5190 GroupSDict::Iterator gli(*Doxygen::groupSDict);
5192 for (gli.toFirst();(gd=gli.current());++gli)
5194 gd->addListReferences();
5197 PageSDict::Iterator pdi(*Doxygen::pageSDict);
5199 for (pdi.toFirst();(pd=pdi.current());++pdi)
5201 QCString name = pd->getOutputFileBase();
5202 if (pd->getGroupDef())
5204 name = pd->getGroupDef()->getOutputFileBase();
5207 QList<ListItemInfo> *xrefItems = pd->xrefListItems();
5208 addRefItem(xrefItems,
5210 theTranslator->trPage(TRUE,TRUE),
5211 name,pd->title(),0);
5215 DirSDict::Iterator ddi(*Doxygen::directories);
5217 for (ddi.toFirst();(dd=ddi.current());++ddi)
5219 QCString name = dd->getOutputFileBase();
5220 //if (dd->getGroupDef())
5222 // name = dd->getGroupDef()->getOutputFileBase();
5224 QList<ListItemInfo> *xrefItems = dd->xrefListItems();
5225 addRefItem(xrefItems,
5227 theTranslator->trDir(TRUE,TRUE),
5228 name,dd->displayName(),0);
5232 //----------------------------------------------------------------------
5234 static void generateXRefPages()
5236 QDictIterator<RefList> di(*Doxygen::xrefLists);
5238 for (di.toFirst();(rl=di.current());++di)
5244 //----------------------------------------------------------------------
5245 // Copy the documentation in entry `root' to member definition `md' and
5246 // set the function declaration of the member to `funcDecl'. If the boolean
5247 // over_load is set the standard overload text is added.
5249 static void addMemberDocs(EntryNav *rootNav,
5250 MemberDef *md, const char *funcDecl,
5256 Entry *root = rootNav->entry();
5257 //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
5258 // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
5259 QCString fDecl=funcDecl;
5260 // strip extern specifier
5261 fDecl.stripPrefix("extern ");
5262 md->setDefinition(fDecl);
5263 md->enableCallGraph(root->callGraph);
5264 md->enableCallerGraph(root->callerGraph);
5265 ClassDef *cd=md->getClassDef();
5266 NamespaceDef *nd=md->getNamespaceDef();
5269 fullName = cd->name();
5271 fullName = nd->name();
5273 if (!fullName.isEmpty()) fullName+="::";
5274 fullName+=md->name();
5275 FileDef *rfd=rootNav->fileDef();
5277 // TODO determine scope based on root not md
5278 Definition *rscope = md->getOuterScope();
5280 ArgumentList *mdAl = md->argumentList();
5283 //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5284 mergeArguments(mdAl,al,!root->doc.isEmpty());
5289 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
5290 rscope,rfd,root->argList,
5295 //printf("merging arguments (2)\n");
5296 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
5299 if (over_load) // the \overload keyword was used
5301 QCString doc=getOverloadDocs();
5302 if (!root->doc.isEmpty())
5307 md->setDocumentation(doc,root->docFile,root->docLine);
5308 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5309 md->setDocsForDefinition(!root->proto);
5313 //printf("overwrite!\n");
5314 md->setDocumentation(root->doc,root->docFile,root->docLine);
5315 md->setDocsForDefinition(!root->proto);
5317 //printf("overwrite!\n");
5318 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5321 (md->inbodyDocumentation().isEmpty() ||
5322 !rootNav->parent()->name().isEmpty()
5323 ) && !root->inbodyDocs.isEmpty()
5326 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5330 //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5331 // md->initializer().data(),md->initializer().isEmpty(),
5332 // root->initializer.data(),root->initializer.isEmpty()
5334 if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5336 //printf("setInitializer\n");
5337 md->setInitializer(root->initializer);
5340 md->setMaxInitLines(root->initLines);
5344 if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5347 //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5348 md->setBodySegment(root->bodyLine,root->endBodyLine);
5349 md->setBodyDef(rfd);
5352 md->setRefItems(root->sli);
5355 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5356 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5358 md->mergeMemberSpecifiers(root->spec);
5359 md->addSectionsToDefinition(root->anchors);
5360 addMemberToGroups(root,md);
5361 if (cd) cd->insertUsedFile(rfd);
5362 //printf("root->mGrpId=%d\n",root->mGrpId);
5363 if (root->mGrpId!=-1)
5365 if (md->getMemberGroupId()!=-1)
5367 if (md->getMemberGroupId()!=root->mGrpId)
5370 root->fileName,root->startLine,
5371 "member %s belongs to two different groups. The second "
5372 "one found here will be ignored.",
5377 else // set group id
5379 //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5380 md->setMemberGroupId(root->mGrpId);
5385 //----------------------------------------------------------------------
5386 // find a class definition given the scope name and (optionally) a
5387 // template list specifier
5389 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5390 const char *scopeName)
5392 ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5397 //----------------------------------------------------------------------
5398 // Adds the documentation contained in `root' to a global function
5399 // with name `name' and argument list `args' (for overloading) and
5400 // function declaration `decl' to the corresponding member definition.
5402 static bool findGlobalMember(EntryNav *rootNav,
5403 const QCString &namespaceName,
5406 const char *tempArg,
5410 Entry *root = rootNav->entry();
5411 Debug::print(Debug::FindMembers,0,
5412 "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5413 namespaceName.data(),type,name,tempArg,decl);
5415 if (n.isEmpty()) return FALSE;
5416 if (n.find("::")!=-1) return FALSE; // skip undefined class members
5417 MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5420 mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5422 if (mn) // function name defined
5424 Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5426 MemberNameIterator mni(*mn);
5429 for (mni.toFirst();(md=mni.current()) && !found;++mni)
5431 NamespaceDef *nd=md->getNamespaceDef();
5433 //printf("Namespace namespaceName=%s nd=%s\n",
5434 // namespaceName.data(),nd ? nd->name().data() : "<none>");
5436 FileDef *fd=rootNav->fileDef();
5437 //printf("File %s\n",fd ? fd->name().data() : "<none>");
5438 NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5439 //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0;
5440 //printf("NamespaceList %p\n",nl);
5442 // search in the list of namespaces that are imported via a
5443 // using declaration
5444 bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5446 if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
5447 (nd && nd->name()==namespaceName) || // or in the same namespace
5448 viaUsingDirective // member in `using' namespace
5451 Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5452 md->name().data(),namespaceName.data());
5453 QCString nsName = nd ? nd->name().data() : "";
5455 NamespaceDef *rnd = 0;
5456 if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5458 ArgumentList *mdAl = md->argumentList();
5460 (mdAl==0 && root->argList->count()==0) ||
5461 md->isVariable() || md->isTypedef() || /* in case of function pointers */
5462 matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl,
5463 rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5466 // for template members we need to check if the number of
5467 // template arguments is the same, otherwise we are dealing with
5468 // different functions.
5469 if (matching && root->tArgLists)
5471 ArgumentList *mdTempl = md->templateArguments();
5474 if (root->tArgLists->getLast()->count()!=mdTempl->count())
5481 //printf("%s<->%s\n",
5482 // argListToString(md->argumentList()).data(),
5483 // argListToString(root->argList).data());
5485 // for static members we also check if the comment block was found in
5486 // the same file. This is needed because static members with the same
5487 // name can be in different files. Thus it would be wrong to just
5488 // put the comment block at the first syntactically matching member.
5489 if (matching && md->isStatic() &&
5490 md->getDefFileName()!=root->fileName &&
5496 // for template member we also need to check the return type
5497 if (md->templateArguments()!=0 && root->tArgLists!=0)
5499 //printf("Comparing return types '%s'<->'%s'\n",
5500 // md->typeString(),type);
5501 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
5502 qstrcmp(md->typeString(),type)!=0)
5504 //printf(" ---> no matching\n");
5509 if (matching) // add docs to the member
5511 Debug::print(Debug::FindMembers,0,"5. Match found\n");
5512 addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5517 if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5519 QCString fullFuncDecl=decl;
5520 if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5522 QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5525 warnMsg+="\nPossible candidates:\n";
5526 for (mni.toFirst();(md=mni.current());++mni)
5529 warnMsg+=substitute(md->declaration(),"%","%%");
5530 warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5531 " of file"+md->getDefFileName()+"\n";
5534 warn(root->fileName,root->startLine,warnMsg);
5537 else // got docs for an undefined member!
5539 if (root->type!="friend class" &&
5540 root->type!="friend struct" &&
5541 root->type!="friend union" &&
5542 (!Config_getBool("TYPEDEF_HIDES_STRUCT") ||
5543 root->type.find("typedef ")==-1)
5546 warn(root->fileName,root->startLine,
5547 "documented symbol `%s' was not declared or defined.",decl
5554 static bool isSpecialization(
5555 const QList<ArgumentList> &srcTempArgLists,
5556 const QList<ArgumentList> &dstTempArgLists
5559 QListIterator<ArgumentList> srclali(srcTempArgLists);
5560 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5561 for (;srclali.current();++srclali,++dstlali)
5563 ArgumentList *sal = srclali.current();
5564 ArgumentList *dal = dstlali.current();
5565 if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5570 static bool scopeIsTemplate(Definition *d)
5573 if (d && d->definitionType()==Definition::TypeClass)
5575 result = ((ClassDef*)d)->templateArguments() || scopeIsTemplate(d->getOuterScope());
5580 static QCString substituteTemplatesInString(
5581 const QList<ArgumentList> &srcTempArgLists,
5582 const QList<ArgumentList> &dstTempArgLists,
5583 ArgumentList *funcTempArgList, // can be used to match template specializations
5588 QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5589 //printf("type=%s\n",sa->type.data());
5591 while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5594 dst+=src.mid(p,i-p);
5595 QCString name=src.mid(i,l);
5597 QListIterator<ArgumentList> srclali(srcTempArgLists);
5598 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5599 for (;srclali.current() && !found;++srclali,++dstlali)
5601 ArgumentListIterator tsali(*srclali.current());
5602 ArgumentListIterator tdali(*dstlali.current());
5603 ArgumentListIterator *fali=0;
5604 Argument *tsa =0,*tda=0, *fa=0;
5605 if (funcTempArgList)
5607 fali = new ArgumentListIterator(*funcTempArgList);
5608 fa = fali->current();
5611 for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5613 tda = tdali.current();
5614 //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5615 // tsa->type.data(),tsa->name.data(),
5616 // tda->type.data(),tda->name.data());
5617 if (name==tsa->name)
5619 if (tda && tda->name.isEmpty())
5622 if (tda->type.left(6)=="class ") vc=6;
5623 else if (tda->type.left(9)=="typename ") vc=9;
5624 if (vc>0) // convert type=="class T" to type=="class" name=="T"
5626 tda->name = tda->type.mid(vc);
5627 tda->type = tda->type.left(vc-1);
5630 if (tda && !tda->name.isEmpty())
5632 name=tda->name; // substitute
5644 { ++(*fali); fa=fali->current(); }
5648 //printf(" srcList='%s' dstList='%s faList='%s'\n",
5649 // argListToString(srclali.current()).data(),
5650 // argListToString(dstlali.current()).data(),
5651 // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5656 dst+=src.right(src.length()-p);
5657 //printf(" substituteTemplatesInString(%s)=%s\n",
5658 // src.data(),dst.data());
5662 static void substituteTemplatesInArgList(
5663 const QList<ArgumentList> &srcTempArgLists,
5664 const QList<ArgumentList> &dstTempArgLists,
5667 ArgumentList *funcTempArgs = 0
5670 ArgumentListIterator sali(*src);
5671 ArgumentListIterator dali(*dst);
5673 Argument *da=dali.current();
5675 for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5677 QCString dstType = substituteTemplatesInString(
5678 srcTempArgLists,dstTempArgLists,funcTempArgs,
5680 QCString dstArray = substituteTemplatesInString(
5681 srcTempArgLists,dstTempArgLists,funcTempArgs,
5685 da=new Argument(*sa);
5699 dst->constSpecifier = src->constSpecifier;
5700 dst->volatileSpecifier = src->volatileSpecifier;
5701 dst->pureSpecifier = src->pureSpecifier;
5702 dst->trailingReturnType = substituteTemplatesInString(
5703 srcTempArgLists,dstTempArgLists,
5704 funcTempArgs,src->trailingReturnType);
5705 //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5706 // argListToString(src).data(),argListToString(dst).data()
5712 /*! This function tries to find a member (in a documented class/file/namespace)
5713 * that corresponds to the function/variable declaration given in \a funcDecl.
5715 * The boolean \a overloaded is used to specify whether or not a standard
5716 * overload documentation line should be generated.
5718 * The boolean \a isFunc is a hint that indicates that this is a function
5719 * instead of a variable or typedef.
5721 static void findMember(EntryNav *rootNav,
5727 Entry *root = rootNav->entry();
5729 Debug::print(Debug::FindMembers,0,
5730 "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5731 "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5732 "spec=%lld lang=%x\n",
5733 root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
5734 root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5735 root->spec,root->lang
5740 QCString namespaceName;
5744 QCString funcTempList;
5745 QCString exceptions;
5747 bool isRelated=FALSE;
5748 bool isMemberOf=FALSE;
5749 bool isFriend=FALSE;
5754 if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5759 if (funcDecl.stripPrefix("inline "))
5761 root->spec|=Entry::Inline;
5764 if (funcDecl.stripPrefix("explicit "))
5766 root->spec|=Entry::Explicit;
5769 if (funcDecl.stripPrefix("mutable "))
5771 root->spec|=Entry::Mutable;
5774 if (funcDecl.stripPrefix("virtual "))
5780 // delete any ; from the function declaration
5782 while ((sep=funcDecl.find(';'))!=-1)
5784 funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5787 // make sure the first character is a space to simplify searching.
5788 if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5790 // remove some superfluous spaces
5791 funcDecl= substitute(
5793 substitute(funcDecl,"~ ","~"),
5797 ).stripWhiteSpace();
5799 //printf("funcDecl=`%s'\n",funcDecl.data());
5800 if (isFriend && funcDecl.left(6)=="class ")
5802 //printf("friend class\n");
5803 funcDecl=funcDecl.right(funcDecl.length()-6);
5804 funcName = funcDecl.copy();
5806 else if (isFriend && funcDecl.left(7)=="struct ")
5808 funcDecl=funcDecl.right(funcDecl.length()-7);
5809 funcName = funcDecl.copy();
5813 // extract information from the declarations
5814 parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5815 funcArgs,funcTempList,exceptions
5818 //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5819 // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5821 // the class name can also be a namespace name, we decide this later.
5822 // if a related class name is specified and the class name could
5823 // not be derived from the function declaration, then use the
5825 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5826 // scopeName.data(),className.data(),namespaceName.data());
5827 if (!root->relates.isEmpty())
5828 { // related member, prefix user specified scope
5830 isMemberOf=(root->relatesType == MemberOf);
5831 if (getClass(root->relates)==0 && !scopeName.isEmpty())
5833 scopeName= mergeScopes(scopeName,root->relates);
5837 scopeName = root->relates;
5841 if (root->relates.isEmpty() && rootNav->parent() &&
5842 ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5843 (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5845 !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName
5846 // with the scope in which it was found
5848 QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5849 if (!scopeName.isEmpty() &&
5850 (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5852 scopeName = joinedName;
5856 scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5859 else // see if we can prefix a namespace or class that is used from the file
5861 FileDef *fd=rootNav->fileDef();
5864 NamespaceSDict *fnl = fd->getUsedNamespaces();
5867 QCString joinedName;
5869 NamespaceSDict::Iterator nsdi(*fnl);
5870 for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5872 joinedName = fnd->name()+"::"+scopeName;
5873 if (Doxygen::namespaceSDict->find(joinedName))
5875 scopeName=joinedName;
5882 scopeName=stripTemplateSpecifiersFromScope(
5883 removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
5885 // funcSpec contains the last template specifiers of the given scope.
5886 // If this method does not have any template arguments or they are
5887 // empty while funcSpec is not empty we assume this is a
5888 // specialization of a method. If not, we clear the funcSpec and treat
5889 // this as a normal method of a template class.
5890 if (!(root->tArgLists &&
5891 root->tArgLists->count()>0 &&
5892 root->tArgLists->getFirst()->count()==0
5899 // split scope into a namespace and a class part
5900 extractNamespaceName(scopeName,className,namespaceName,TRUE);
5901 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5902 // scopeName.data(),className.data(),namespaceName.data());
5904 //namespaceName=removeAnonymousScopes(namespaceName);
5905 if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5907 //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5908 // merge class and namespace scopes again
5909 scopeName.resize(0);
5910 if (!namespaceName.isEmpty())
5912 if (className.isEmpty())
5914 scopeName=namespaceName;
5916 else if (!root->relates.isEmpty() || // relates command with explicit scope
5917 !getClass(className)) // class name only exists in a namespace
5919 scopeName=namespaceName+"::"+className;
5923 scopeName=className;
5926 else if (!className.isEmpty())
5928 scopeName=className;
5930 //printf("new scope=`%s'\n",scopeName.data());
5932 QCString tempScopeName=scopeName;
5933 ClassDef *cd=getClass(scopeName);
5936 if (funcSpec.isEmpty())
5939 tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists,&argListIndex);
5943 tempScopeName=scopeName+funcSpec;
5946 //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
5947 // scopeName.data(),cd,root->tArgLists,tempScopeName.data());
5949 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
5950 // rebuild the function declaration (needed to get the scope right).
5951 if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
5953 if (!funcType.isEmpty())
5955 if (isFunc) // a function -> we use argList for the arguments
5957 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
5961 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
5966 if (isFunc) // a function => we use argList for the arguments
5968 funcDecl=tempScopeName+"::"+funcName+funcTempList;
5970 else // variable => add `argument' list
5972 funcDecl=tempScopeName+"::"+funcName+funcArgs;
5976 else // build declaration without scope
5978 if (!funcType.isEmpty()) // but with a type
5980 if (isFunc) // function => omit argument list
5982 funcDecl=funcType+" "+funcName+funcTempList;
5984 else // variable => add `argument' list
5986 funcDecl=funcType+" "+funcName+funcArgs;
5993 funcDecl=funcName+funcTempList;
5997 funcDecl=funcName+funcArgs;
6002 if (funcType=="template class" && !funcTempList.isEmpty())
6003 return; // ignore explicit template instantiations
6005 Debug::print(Debug::FindMembers,0,
6006 "findMember() Parse results:\n"
6007 " namespaceName=`%s'\n"
6013 " funcTempList=`%s'\n"
6016 " exceptions=`%s'\n"
6021 namespaceName.data(),className.data(),
6022 funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
6023 funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,
6028 if (!funcName.isEmpty()) // function name is valid
6030 Debug::print(Debug::FindMembers,0,
6031 "1. funcName=`%s'\n",funcName.data());
6032 if (funcName.left(9)=="operator ") // strip class scope from cast operator
6034 funcName = substitute(funcName,className+"::","");
6036 if (!funcTempList.isEmpty()) // try with member specialization
6038 mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
6040 if (mn==0) // try without specialization
6042 mn=Doxygen::memberNameSDict->find(funcName);
6044 if (!isRelated && mn) // function name already found
6046 Debug::print(Debug::FindMembers,0,
6047 "2. member name exists (%d members with this name)\n",mn->count());
6048 if (!className.isEmpty()) // class name is valid
6050 if (funcSpec.isEmpty()) // not a member specialization
6054 MemberNameIterator mni(*mn);
6056 bool memFound=FALSE;
6057 for (mni.toFirst();!memFound && (md=mni.current());++mni)
6059 ClassDef *cd=md->getClassDef();
6060 Debug::print(Debug::FindMembers,0,
6061 "3. member definition found, "
6062 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
6063 scopeName.data(),cd ? cd->name().data() : "<none>",
6065 root->fileName.data());
6066 //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
6067 FileDef *fd=rootNav->fileDef();
6069 if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
6071 //printf("scopeName %s->%s\n",scopeName.data(),
6072 // stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
6074 ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
6075 if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
6077 // don't be fooled by anonymous scopes
6080 //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
6081 // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
6083 if (cd && tcd==cd) // member's classes match
6085 Debug::print(Debug::FindMembers,0,
6086 "4. class definition %s found\n",cd->name().data());
6088 // get the template parameter lists found at the member declaration
6089 QList<ArgumentList> declTemplArgs;
6090 cd->getTemplateParameterLists(declTemplArgs);
6091 ArgumentList *templAl = md->templateArguments();
6094 declTemplArgs.append(templAl);
6097 // get the template parameter lists found at the member definition
6098 QList<ArgumentList> *defTemplArgs = root->tArgLists;
6099 //printf("defTemplArgs=%p\n",defTemplArgs);
6101 // do we replace the decl argument lists with the def argument lists?
6102 bool substDone=FALSE;
6103 ArgumentList *argList=0;
6105 /* substitute the occurrences of class template names in the
6106 * argument list before matching
6108 ArgumentList *mdAl = md->argumentList();
6109 if (declTemplArgs.count()>0 && defTemplArgs &&
6110 declTemplArgs.count()==defTemplArgs->count() &&
6114 /* the function definition has template arguments
6115 * and the class definition also has template arguments, so
6116 * we must substitute the template names of the class by that
6117 * of the function definition before matching.
6119 argList = new ArgumentList;
6120 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
6125 else /* no template arguments, compare argument lists directly */
6130 Debug::print(Debug::FindMembers,0,
6131 "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
6132 argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
6133 className.data(),namespaceName.data()
6137 md->isVariable() || md->isTypedef() || // needed for function pointers
6138 (mdAl==0 && root->argList->count()==0) ||
6140 md->getClassDef(),md->getFileDef(),argList,
6141 cd,fd,root->argList,
6144 if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
6146 matching = FALSE; // don't match methods and attributes with the same name
6149 // for template member we also need to check the return type
6150 if (md->templateArguments()!=0 && root->tArgLists!=0)
6152 QCString memType = md->typeString();
6153 memType.stripPrefix("static "); // see bug700696
6154 funcType=substitute(funcType,className+"::",""); // see bug700693
6155 Debug::print(Debug::FindMembers,0,
6156 "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
6157 md->typeString(),funcType.data(),
6158 md->templateArguments()->count(),root->tArgLists->getLast()->count());
6159 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
6160 qstrcmp(memType,funcType))
6162 //printf(" ---> no matching\n");
6166 bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
6167 bool classIsTemplate = scopeIsTemplate(md->getClassDef());
6168 bool mdIsTemplate = md->templateArguments()!=0;
6169 bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
6170 bool rootIsTemplate = root->tArgLists!=0;
6171 //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
6172 if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
6173 (mdIsTemplate || rootIsTemplate) && // either md or root is a template
6174 ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
6177 // Method with template return type does not match method without return type
6178 // even if the parameters are the same. See also bug709052
6179 Debug::print(Debug::FindMembers,0,
6180 "5b. Comparing return types: template v.s. non-template\n");
6185 Debug::print(Debug::FindMembers,0,
6186 "6. match results of matchArguments2 = %d\n",matching);
6188 if (substDone) // found a new argument list
6190 if (matching) // replace member's argument list
6192 md->setDefinitionTemplateParameterLists(root->tArgLists);
6193 md->setArgumentList(argList); // new owner of the list => no delete
6197 if (!funcTempList.isEmpty() &&
6198 isSpecialization(declTemplArgs,*defTemplArgs))
6200 // check if we are dealing with a partial template
6201 // specialization. In this case we add it to the class
6202 // even though the member arguments do not match.
6204 // TODO: copy other aspects?
6205 root->protection=md->protection(); // copy protection level
6206 addMethodToClass(rootNav,cd,md->name(),isFriend);
6214 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
6219 else if (cd && cd!=tcd) // we did find a class with the same name as cd
6220 // but in a different namespace
6225 if (count==0 && rootNav->parent() &&
6226 rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6228 goto localObjCMethod;
6230 if (count==0 && !(isFriend && funcType=="class"))
6233 ClassDef *ecd = 0, *ucd = 0;
6234 MemberDef *emd = 0, *umd = 0;
6237 //printf("Assume template class\n");
6238 for (mni.toFirst();(md=mni.current());++mni)
6240 ClassDef *ccd=md->getClassDef();
6242 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
6243 if (ccd!=0 && rightScopeMatch(ccd->name(),className))
6245 ArgumentList *templAl = md->templateArguments();
6246 if (root->tArgLists && templAl!=0 &&
6247 root->tArgLists->getLast()->count()<=templAl->count())
6249 addMethodToClass(rootNav,ccd,md->name(),isFriend);
6252 if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
6253 { // exact argument list match -> remember
6256 Debug::print(Debug::FindMembers,0,
6257 "7. new candidate className=%s scope=%s args=%s exact match\n",
6258 className.data(),ccd->name().data(),md->argsString());
6260 else // arguments do not match, but member name and scope do -> remember
6264 Debug::print(Debug::FindMembers,0,
6265 "7. new candidate className=%s scope=%s args=%s no match\n",
6266 className.data(),ccd->name().data(),md->argsString());
6272 static bool strictProtoMatching = Config_getBool("STRICT_PROTO_MATCHING");
6273 if (!strictProtoMatching)
6275 if (candidates==1 && ucd && umd)
6277 // we didn't find an actual match on argument lists, but there is only 1 member with this
6278 // name in the same scope, so that has to be the one.
6279 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
6282 else if (candidates>1 && ecd && emd)
6284 // we didn't find a unique match using type resolution,
6285 // but one of the matches has the exact same signature so
6286 // we take that one.
6287 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
6292 QCString warnMsg = "no ";
6293 if (noMatchCount>1) warnMsg+="uniquely ";
6294 warnMsg+="matching class member found for \n";
6296 if (root->tArgLists)
6298 QListIterator<ArgumentList> alli(*root->tArgLists);
6300 for (;(al=alli.current());++alli)
6302 warnMsg+=" template ";
6303 warnMsg+=tempArgListToString(al);
6307 QCString fullFuncDecl=funcDecl.copy();
6308 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6311 warnMsg+=fullFuncDecl;
6316 warnMsg+="Possible candidates:\n";
6317 for (mni.toFirst();(md=mni.current());++mni)
6319 ClassDef *cd=md->getClassDef();
6320 if (cd!=0 && rightScopeMatch(cd->name(),className))
6322 ArgumentList *templAl = md->templateArguments();
6325 warnMsg+=" 'template ";
6326 warnMsg+=tempArgListToString(templAl);
6330 if (md->typeString())
6332 warnMsg+=md->typeString();
6335 QCString qScope = cd->qualifiedNameWithTemplateParameters();
6336 if (!qScope.isEmpty())
6337 warnMsg+=qScope+"::"+md->name();
6338 if (md->argsString())
6339 warnMsg+=md->argsString();
6342 warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6343 " of file "+md->getDefFileName();
6350 warn_simple(root->fileName,root->startLine,warnMsg);
6353 else if (cd) // member specialization
6355 MemberNameIterator mni(*mn);
6356 MemberDef *declMd=0;
6358 for (mni.toFirst();(md=mni.current());++mni)
6360 if (md->getClassDef()==cd)
6362 // TODO: we should probably also check for matching arguments
6367 MemberType mtype=MemberType_Function;
6368 ArgumentList *tArgList = new ArgumentList;
6369 // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6371 root->fileName,root->startLine,root->startColumn,
6372 funcType,funcName,funcArgs,exceptions,
6373 declMd ? declMd->protection() : root->protection,
6374 root->virt,root->stat,Member,
6375 mtype,tArgList,root->argList);
6376 //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6377 md->setTagInfo(rootNav->tagInfo());
6378 md->setLanguage(root->lang);
6379 md->setId(root->id);
6380 md->setMemberClass(cd);
6381 md->setTemplateSpecialization(TRUE);
6382 md->setTypeConstraints(root->typeConstr);
6383 md->setDefinition(funcDecl);
6384 md->enableCallGraph(root->callGraph);
6385 md->enableCallerGraph(root->callerGraph);
6386 md->setDocumentation(root->doc,root->docFile,root->docLine);
6387 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6388 md->setDocsForDefinition(!root->proto);
6389 md->setPrototype(root->proto);
6390 md->addSectionsToDefinition(root->anchors);
6391 md->setBodySegment(root->bodyLine,root->endBodyLine);
6392 FileDef *fd=rootNav->fileDef();
6394 md->setMemberSpecifiers(root->spec);
6395 md->setMemberGroupId(root->mGrpId);
6397 cd->insertMember(md);
6398 md->setRefItems(root->sli);
6403 //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6404 // scopeName.data(),funcName.data(),funcArgs.data());
6407 else if (overloaded) // check if the function belongs to only one class
6409 // for unique overloaded member we allow the class to be
6410 // omitted, this is to be Qt compatible. Using this should
6411 // however be avoided, because it is error prone
6412 MemberNameIterator mni(*mn);
6413 MemberDef *md=mni.toFirst();
6415 ClassDef *cd=md->getClassDef();
6417 QCString className=cd->name().copy();
6420 for (;(md=mni.current());++mni)
6422 ClassDef *cd=md->getClassDef();
6423 if (className!=cd->name()) unique=FALSE;
6428 if (root->mtype==Signal) mtype=MemberType_Signal;
6429 else if (root->mtype==Slot) mtype=MemberType_Slot;
6430 else if (root->mtype==DCOP) mtype=MemberType_DCOP;
6431 else mtype=MemberType_Function;
6433 // new overloaded member function
6434 ArgumentList *tArgList =
6435 getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6436 //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6437 MemberDef *md=new MemberDef(
6438 root->fileName,root->startLine,root->startColumn,
6439 funcType,funcName,funcArgs,exceptions,
6440 root->protection,root->virt,root->stat,Related,
6441 mtype,tArgList,root->argList);
6442 md->setTagInfo(rootNav->tagInfo());
6443 md->setLanguage(root->lang);
6444 md->setId(root->id);
6445 md->setTypeConstraints(root->typeConstr);
6446 md->setMemberClass(cd);
6447 md->setDefinition(funcDecl);
6448 md->enableCallGraph(root->callGraph);
6449 md->enableCallerGraph(root->callerGraph);
6450 QCString doc=getOverloadDocs();
6453 md->setDocumentation(doc,root->docFile,root->docLine);
6454 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6455 md->setDocsForDefinition(!root->proto);
6456 md->setPrototype(root->proto);
6457 md->addSectionsToDefinition(root->anchors);
6458 md->setBodySegment(root->bodyLine,root->endBodyLine);
6459 FileDef *fd=rootNav->fileDef();
6461 md->setMemberSpecifiers(root->spec);
6462 md->setMemberGroupId(root->mGrpId);
6464 cd->insertMember(md);
6465 cd->insertUsedFile(fd);
6466 md->setRefItems(root->sli);
6469 else // unrelated function with the same name as a member
6471 if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6473 QCString fullFuncDecl=funcDecl.copy();
6474 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6475 warn(root->fileName,root->startLine,
6476 "Cannot determine class for function\n%s",
6482 else if (isRelated && !root->relates.isEmpty())
6484 Debug::print(Debug::FindMembers,0,"2. related function\n"
6485 " scopeName=%s className=%s\n",scopeName.data(),className.data());
6486 if (className.isEmpty()) className=root->relates;
6488 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6489 if ((cd=getClass(scopeName)))
6491 bool newMember=TRUE; // assume we have a new member
6492 bool newMemberName=FALSE;
6493 MemberDef *mdDefine=0;
6494 bool isDefine=FALSE;
6496 MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6499 MemberNameIterator mni(*mn);
6500 mdDefine = mni.current();
6501 while (mdDefine && !isDefine)
6503 isDefine = isDefine || mdDefine->isDefine();
6504 if (!isDefine) { ++mni; mdDefine=mni.current(); }
6509 FileDef *fd=rootNav->fileDef();
6511 if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6513 mn=new MemberName(funcName);
6514 newMemberName=TRUE; // we create a new member name
6518 MemberNameIterator mni(*mn);
6520 while ((rmd=mni.current()) && newMember) // see if we got another member with matching arguments
6522 ArgumentList *rmdAl = rmd->argumentList();
6525 className!=rmd->getOuterScope()->name() ||
6526 !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6527 cd,fd,root->argList,
6529 if (newMember) ++mni;
6531 if (!newMember && rmd) // member already exists as rmd -> add docs
6533 //printf("addMemberDocs for related member %s\n",root->name.data());
6534 //rmd->setMemberDefTemplateArguments(root->mtArgList);
6535 addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6539 if (newMember) // need to create a new member
6543 mtype=MemberType_Define;
6544 else if (root->mtype==Signal)
6545 mtype=MemberType_Signal;
6546 else if (root->mtype==Slot)
6547 mtype=MemberType_Slot;
6548 else if (root->mtype==DCOP)
6549 mtype=MemberType_DCOP;
6551 mtype=MemberType_Function;
6553 if (isDefine && mdDefine)
6555 mdDefine->setHidden(TRUE);
6557 funcArgs=mdDefine->argsString();
6558 funcDecl=funcType + " " + funcName;
6561 //printf("New related name `%s' `%d'\n",funcName.data(),
6562 // root->argList ? (int)root->argList->count() : -1);
6564 // first note that we pass:
6565 // (root->tArgLists ? root->tArgLists->last() : 0)
6566 // for the template arguments fo the new "member."
6567 // this accurately reflects the template arguments of
6568 // the related function, which don't have to do with
6569 // those of the related class.
6570 MemberDef *md=new MemberDef(
6571 root->fileName,root->startLine,root->startColumn,
6572 funcType,funcName,funcArgs,exceptions,
6573 root->protection,root->virt,
6574 root->stat && !isMemberOf,
6575 isMemberOf ? Foreign : isRelated ? Related : Member,
6577 (root->tArgLists ? root->tArgLists->getLast() : 0),
6578 funcArgs.isEmpty() ? 0 : root->argList);
6580 if (isDefine && mdDefine)
6582 md->setInitializer(mdDefine->initializer());
6586 // we still have the problem that
6587 // MemberDef::writeDocumentation() in memberdef.cpp
6588 // writes the template argument list for the class,
6589 // as if this member is a member of the class.
6590 // fortunately, MemberDef::writeDocumentation() has
6591 // a special mechanism that allows us to totally
6592 // override the set of template argument lists that
6593 // are printed. We use that and set it to the
6594 // template argument lists of the related function.
6596 md->setDefinitionTemplateParameterLists(root->tArgLists);
6598 md->setTagInfo(rootNav->tagInfo());
6602 //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6603 // funcName.data(),funcDecl.data(),root->bodyLine);
6605 // try to find the matching line number of the body from the
6606 // global function list
6608 if (root->bodyLine==-1)
6610 MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6613 MemberNameIterator rmni(*rmn);
6615 while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
6617 ArgumentList *rmdAl = rmd->argumentList();
6618 // check for matching argument lists
6620 matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6621 cd,fd,root->argList,
6629 if (rmd) // member found -> copy line number info
6631 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6632 md->setBodyDef(rmd->getBodyDef());
6633 //md->setBodyMember(rmd);
6637 if (!found) // line number could not be found or is available in this
6640 md->setBodySegment(root->bodyLine,root->endBodyLine);
6644 //if (root->mGrpId!=-1)
6646 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
6648 md->setMemberClass(cd);
6649 md->setMemberSpecifiers(root->spec);
6650 md->setDefinition(funcDecl);
6651 md->enableCallGraph(root->callGraph);
6652 md->enableCallerGraph(root->callerGraph);
6653 md->setDocumentation(root->doc,root->docFile,root->docLine);
6654 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6655 md->setDocsForDefinition(!root->proto);
6656 md->setPrototype(root->proto);
6657 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6658 md->addSectionsToDefinition(root->anchors);
6659 md->setMemberGroupId(root->mGrpId);
6660 md->setLanguage(root->lang);
6661 md->setId(root->id);
6662 //md->setMemberDefTemplateArguments(root->mtArgList);
6664 cd->insertMember(md);
6665 cd->insertUsedFile(fd);
6666 md->setRefItems(root->sli);
6667 if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6670 addMemberToGroups(root,md);
6672 //printf("Adding member=%s\n",md->name().data());
6675 //Doxygen::memberNameList.append(mn);
6676 //Doxygen::memberNameDict.insert(funcName,mn);
6677 Doxygen::memberNameSDict->append(funcName,mn);
6680 if (root->relatesType == Duplicate)
6682 if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6684 QCString fullFuncDecl=funcDecl.copy();
6685 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6686 warn(root->fileName,root->startLine,
6687 "Cannot determine file/namespace for relatedalso function\n%s",
6695 warn_undoc(root->fileName,root->startLine,
6696 "class `%s' for related function `%s' is not "
6698 className.data(),funcName.data()
6702 else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6706 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6707 if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
6709 Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6710 " scopeName=%s className=%s\n",root->name.data(),scopeName.data(),className.data());
6711 //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6712 MemberDef *md=new MemberDef(
6713 root->fileName,root->startLine,root->startColumn,
6714 funcType,funcName,funcArgs,exceptions,
6715 root->protection,root->virt,root->stat,Member,
6716 MemberType_Function,0,root->argList);
6717 md->setTagInfo(rootNav->tagInfo());
6718 md->setLanguage(root->lang);
6719 md->setId(root->id);
6720 md->makeImplementationDetail();
6721 md->setMemberClass(cd);
6722 md->setDefinition(funcDecl);
6723 md->enableCallGraph(root->callGraph);
6724 md->enableCallerGraph(root->callerGraph);
6725 md->setDocumentation(root->doc,root->docFile,root->docLine);
6726 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6727 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6728 md->setDocsForDefinition(!root->proto);
6729 md->setPrototype(root->proto);
6730 md->addSectionsToDefinition(root->anchors);
6731 md->setBodySegment(root->bodyLine,root->endBodyLine);
6732 FileDef *fd=rootNav->fileDef();
6734 md->setMemberSpecifiers(root->spec);
6735 md->setMemberGroupId(root->mGrpId);
6736 cd->insertMember(md);
6737 cd->insertUsedFile(fd);
6738 md->setRefItems(root->sli);
6739 if ((mn=Doxygen::memberNameSDict->find(root->name)))
6745 mn = new MemberName(root->name);
6747 Doxygen::memberNameSDict->append(root->name,mn);
6752 // local objective C method found for class without interface
6755 else // unrelated not overloaded member found
6757 bool globMem = findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl);
6758 if (className.isEmpty() && !globMem)
6760 warn(root->fileName,root->startLine,
6761 "class for member `%s' cannot "
6762 "be found.", funcName.data()
6765 else if (!className.isEmpty() && !globMem)
6767 warn(root->fileName,root->startLine,
6768 "member `%s' of class `%s' cannot be found",
6769 funcName.data(),className.data());
6775 // this should not be called
6776 warn(root->fileName,root->startLine,
6777 "member with no name found.");
6782 //----------------------------------------------------------------------
6783 // find the members corresponding to the different documentation blocks
6784 // that are extracted from the sources.
6786 static void filterMemberDocumentation(EntryNav *rootNav)
6788 Entry *root = rootNav->entry();
6790 Debug::print(Debug::FindMembers,0,
6791 "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6792 root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
6794 //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6797 if (root->relatesType == Duplicate && !root->relates.isEmpty())
6799 QCString tmp = root->relates;
6800 root->relates.resize(0);
6801 filterMemberDocumentation(rootNav);
6802 root->relates = tmp;
6805 if ( // detect func variable/typedef to func ptr
6806 (i=findFunctionPtr(root->type,root->lang,&l))!=-1
6809 //printf("Fixing function pointer!\n");
6810 // fix type and argument
6811 root->args.prepend(root->type.right(root->type.length()-i-l));
6812 root->type=root->type.left(i+l);
6813 //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6816 else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1))
6817 // detect function types marked as functions
6822 //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6823 if (root->section==Entry::MEMBERDOC_SEC)
6825 //printf("Documentation for inline member `%s' found args=`%s'\n",
6826 // root->name.data(),root->args.data());
6827 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6828 if (root->type.isEmpty())
6830 findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6834 findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6837 else if (root->section==Entry::OVERLOADDOC_SEC)
6839 //printf("Overloaded member %s found\n",root->name.data());
6840 findMember(rootNav,root->name,TRUE,isFunc);
6843 ((root->section==Entry::FUNCTION_SEC // function
6845 (root->section==Entry::VARIABLE_SEC && // variable
6846 !root->type.isEmpty() && // with a type
6847 g_compoundKeywordDict.find(root->type)==0 // that is not a keyword
6848 // (to skip forward declaration of class etc.)
6853 //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6854 // root->name.data(),root->args.data(),root->exception.data());
6855 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6856 //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6857 if (root->type=="friend class" || root->type=="friend struct" ||
6858 root->type=="friend union")
6866 else if (!root->type.isEmpty())
6886 else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6888 findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6890 else if (root->section==Entry::VARIABLEDOC_SEC)
6892 //printf("Documentation for variable %s found\n",root->name.data());
6893 //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data());
6894 findMember(rootNav,root->name,FALSE,FALSE);
6896 else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
6897 root->section==Entry::INCLUDED_SERVICE_SEC)
6899 findMember(rootNav,root->type + " " + root->name,FALSE,FALSE);
6904 //printf("skip section\n");
6908 static void findMemberDocumentation(EntryNav *rootNav)
6910 if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6911 rootNav->section()==Entry::OVERLOADDOC_SEC ||
6912 rootNav->section()==Entry::FUNCTION_SEC ||
6913 rootNav->section()==Entry::VARIABLE_SEC ||
6914 rootNav->section()==Entry::VARIABLEDOC_SEC ||
6915 rootNav->section()==Entry::DEFINE_SEC ||
6916 rootNav->section()==Entry::INCLUDED_SERVICE_SEC ||
6917 rootNav->section()==Entry::EXPORTED_INTERFACE_SEC
6920 rootNav->loadEntry(g_storage);
6922 filterMemberDocumentation(rootNav);
6924 rootNav->releaseEntry();
6926 if (rootNav->children())
6928 EntryNavListIterator eli(*rootNav->children());
6930 for (;(e=eli.current());++eli)
6932 if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6937 //----------------------------------------------------------------------
6939 static void findObjCMethodDefinitions(EntryNav *rootNav)
6941 if (rootNav->children())
6943 EntryNavListIterator eli(*rootNav->children());
6944 EntryNav *objCImplNav;
6945 for (;(objCImplNav=eli.current());++eli)
6947 if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
6949 EntryNavListIterator seli(*objCImplNav->children());
6950 EntryNav *objCMethodNav;
6951 for (;(objCMethodNav=seli.current());++seli)
6953 if (objCMethodNav->section()==Entry::FUNCTION_SEC)
6955 objCMethodNav->loadEntry(g_storage);
6956 Entry *objCMethod = objCMethodNav->entry();
6958 //Printf(" Found ObjC method definition %s\n",objCMethod->name.data());
6959 findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
6960 objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
6961 objCMethod->section=Entry::EMPTY_SEC;
6963 objCMethodNav->releaseEntry();
6971 //----------------------------------------------------------------------
6972 // find and add the enumeration to their classes, namespaces or files
6974 static void findEnums(EntryNav *rootNav)
6976 if (rootNav->section()==Entry::ENUM_SEC)
6978 rootNav->loadEntry(g_storage);
6979 Entry *root = rootNav->entry();
6985 MemberNameSDict *mnsd=0;
6987 bool isRelated=FALSE;
6988 bool isMemberOf=FALSE;
6989 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
6995 if ((i=root->name.findRev("::"))!=-1) // scope is specified
6997 scope=root->name.left(i); // extract scope
6998 name=root->name.right(root->name.length()-i-2); // extract name
6999 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7001 else // no scope, check the scope in which the docs where found
7003 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7004 && !rootNav->parent()->name().isEmpty()
7005 ) // found enum docs inside a compound
7007 scope=rootNav->parent()->name();
7008 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7013 if (!root->relates.isEmpty())
7014 { // related member, prefix user specified scope
7016 isMemberOf=(root->relatesType == MemberOf);
7017 if (getClass(root->relates)==0 && !scope.isEmpty())
7018 scope=mergeScopes(scope,root->relates);
7020 scope=root->relates.copy();
7021 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7024 if (cd && !name.isEmpty()) // found a enum inside a compound
7026 //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
7028 mnsd=Doxygen::memberNameSDict;
7031 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7033 mnsd=Doxygen::functionNameSDict;
7036 else // found a global enum
7038 fd=rootNav->fileDef();
7039 mnsd=Doxygen::functionNameSDict;
7043 if (!name.isEmpty())
7047 root->fileName,root->startLine,root->startColumn,
7049 root->protection,Normal,FALSE,
7050 isMemberOf ? Foreign : isRelated ? Related : Member,
7051 MemberType_Enumeration,
7053 md->setTagInfo(rootNav->tagInfo());
7054 md->setLanguage(root->lang);
7055 md->setId(root->id);
7056 if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7057 md->setBodySegment(root->bodyLine,root->endBodyLine);
7058 md->setBodyDef(rootNav->fileDef());
7059 md->setMemberSpecifiers(root->spec); // UNO IDL "published"
7060 md->setEnumBaseType(root->args);
7061 //printf("Enum %s definition at line %d of %s: protection=%d\n",
7062 // root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
7063 md->addSectionsToDefinition(root->anchors);
7064 md->setMemberGroupId(root->mGrpId);
7065 md->enableCallGraph(root->callGraph);
7066 md->enableCallerGraph(root->callerGraph);
7067 //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
7068 md->setRefItems(root->sli);
7069 //printf("found enum %s nd=%p\n",name.data(),nd);
7072 QCString baseType = root->args;
7073 if (!baseType.isEmpty())
7075 baseType.prepend(" : ");
7078 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7080 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
7082 md->setDefinition(name+baseType);
7086 md->setDefinition(nd->name()+"::"+name+baseType);
7088 //printf("definition=%s\n",md->definition());
7090 md->setNamespace(nd);
7091 nd->insertMember(md);
7094 // even if we have already added the enum to a namespace, we still
7095 // also want to add it to other appropriate places such as file
7099 if (!defSet) md->setDefinition(name+baseType);
7100 if (fd==0 && rootNav->parent())
7102 fd=rootNav->parent()->fileDef();
7107 fd->insertMember(md);
7112 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
7114 md->setDefinition(name+baseType);
7118 md->setDefinition(cd->name()+"::"+name+baseType);
7120 cd->insertMember(md);
7121 cd->insertUsedFile(fd);
7123 md->setDocumentation(root->doc,root->docFile,root->docLine);
7124 md->setDocsForDefinition(!root->proto);
7125 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7126 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7128 //printf("Adding member=%s\n",md->name().data());
7130 if ((mn=(*mnsd)[name]))
7132 // this is used if the same enum is in multiple namespaces/classes
7135 else // new enum name
7137 mn = new MemberName(name);
7139 mnsd->append(name,mn);
7140 //printf("add %s to new memberName. Now %d members\n",
7141 // name.data(),mn->count());
7143 addMemberToGroups(root,md);
7145 rootNav->releaseEntry();
7149 RECURSE_ENTRYTREE(findEnums,rootNav);
7153 //----------------------------------------------------------------------
7155 static void addEnumValuesToEnums(EntryNav *rootNav)
7157 if (rootNav->section()==Entry::ENUM_SEC)
7158 // non anonymous enumeration
7160 rootNav->loadEntry(g_storage);
7161 Entry *root = rootNav->entry();
7166 MemberNameSDict *mnsd=0;
7168 bool isRelated=FALSE;
7169 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7175 if ((i=root->name.findRev("::"))!=-1) // scope is specified
7177 scope=root->name.left(i); // extract scope
7178 name=root->name.right(root->name.length()-i-2); // extract name
7179 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7181 else // no scope, check the scope in which the docs where found
7183 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7184 && !rootNav->parent()->name().isEmpty()
7185 ) // found enum docs inside a compound
7187 scope=rootNav->parent()->name();
7188 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7193 if (!root->relates.isEmpty())
7194 { // related member, prefix user specified scope
7196 if (getClass(root->relates)==0 && !scope.isEmpty())
7197 scope=mergeScopes(scope,root->relates);
7199 scope=root->relates.copy();
7200 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7203 if (cd && !name.isEmpty()) // found a enum inside a compound
7205 //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
7207 mnsd=Doxygen::memberNameSDict;
7210 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7212 //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
7213 mnsd=Doxygen::functionNameSDict;
7216 else // found a global enum
7218 fd=rootNav->fileDef();
7219 //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
7220 mnsd=Doxygen::functionNameSDict;
7224 if (!name.isEmpty())
7226 //printf("** name=%s\n",name.data());
7227 MemberName *mn = mnsd->find(name); // for all members with this name
7230 MemberNameIterator mni(*mn);
7232 for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list
7234 if (md->isEnumerate() && rootNav->children())
7236 //printf(" enum with %d children\n",rootNav->children()->count());
7237 EntryNavListIterator eli(*rootNav->children()); // for each enum value
7239 for (;(e=eli.current());++eli)
7243 (sle=rootNav->lang())==SrcLangExt_CSharp ||
7244 sle==SrcLangExt_Java ||
7245 sle==SrcLangExt_XML ||
7246 (root->spec&Entry::Strong)
7249 // Unlike classic C/C++ enums, for C++11, C# & Java enum
7250 // values are only visible inside the enum scope, so we must create
7251 // them here and only add them to the enum
7252 e->loadEntry(g_storage);
7253 Entry *root = e->entry();
7254 //printf("md->qualifiedName()=%s rootNav->name()=%s tagInfo=%p name=%s\n",
7255 // md->qualifiedName().data(),rootNav->name().data(),rootNav->tagInfo(),root->name.data());
7256 if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7257 substitute(rootNav->name(),"::",".") || // enum value scope matches that of the enum
7258 rootNav->tagInfo() // be less strict for tag files as members can have incomplete scope
7261 MemberDef *fmd=new MemberDef(
7262 root->fileName,root->startLine,root->startColumn,
7263 root->type,root->name,root->args,0,
7264 Public, Normal,root->stat,Member,
7265 MemberType_EnumValue,0,0);
7266 if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
7267 else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
7268 else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
7269 fmd->setOuterScope(md->getOuterScope());
7270 fmd->setTagInfo(e->tagInfo());
7271 fmd->setLanguage(root->lang);
7272 fmd->setId(root->id);
7273 fmd->setDocumentation(root->doc,root->docFile,root->docLine);
7274 fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7275 fmd->addSectionsToDefinition(root->anchors);
7276 fmd->setInitializer(root->initializer);
7277 fmd->setMaxInitLines(root->initLines);
7278 fmd->setMemberGroupId(root->mGrpId);
7279 fmd->setExplicitExternal(root->explicitExternal);
7280 fmd->setRefItems(root->sli);
7282 md->insertEnumField(fmd);
7283 fmd->setEnumScope(md,TRUE);
7284 MemberName *mn=mnsd->find(root->name);
7291 mn = new MemberName(root->name);
7293 mnsd->append(root->name,mn);
7300 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
7302 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
7303 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
7304 // get list of members with the same name as the field
7306 MemberNameIterator fmni(*fmn);
7308 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
7310 if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7312 //printf("found enum value with same name %s in scope %s\n",
7313 // fmd->name().data(),fmd->getOuterScope()->name().data());
7314 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7316 NamespaceDef *fnd=fmd->getNamespaceDef();
7317 if (fnd==nd) // enum value is inside a namespace
7319 md->insertEnumField(fmd);
7320 fmd->setEnumScope(md);
7325 FileDef *ffd=fmd->getFileDef();
7326 if (ffd==fd) // enum value has file scope
7328 md->insertEnumField(fmd);
7329 fmd->setEnumScope(md);
7332 else if (isRelated && cd) // reparent enum value to
7333 // match the enum's scope
7335 md->insertEnumField(fmd); // add field def to list
7336 fmd->setEnumScope(md); // cross ref with enum name
7337 fmd->setEnumClassScope(cd); // cross ref with enum name
7338 fmd->setOuterScope(cd);
7340 cd->insertMember(fmd);
7344 ClassDef *fcd=fmd->getClassDef();
7345 if (fcd==cd) // enum value is inside a class
7347 //printf("Inserting enum field %s in enum scope %s\n",
7348 // fmd->name().data(),md->name().data());
7349 md->insertEnumField(fmd); // add field def to list
7350 fmd->setEnumScope(md); // cross ref with enum name
7363 rootNav->releaseEntry();
7367 RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7372 //----------------------------------------------------------------------
7373 // find the documentation blocks for the enumerations
7375 static void findEnumDocumentation(EntryNav *rootNav)
7377 if (rootNav->section()==Entry::ENUMDOC_SEC
7378 && !rootNav->name().isEmpty()
7379 && rootNav->name().at(0)!='@' // skip anonymous enums
7382 rootNav->loadEntry(g_storage);
7383 Entry *root = rootNav->entry();
7385 //printf("Found docs for enum with name `%s' in context %s\n",
7386 // root->name.data(),root->parent->name.data());
7390 if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7392 name=root->name.right(root->name.length()-i-2); // extract name
7393 scope=root->name.left(i); // extract scope
7394 //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7396 else // just the name
7400 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7401 && !rootNav->parent()->name().isEmpty()
7402 ) // found enum docs inside a compound
7404 if (!scope.isEmpty()) scope.prepend("::");
7405 scope.prepend(rootNav->parent()->name());
7407 ClassDef *cd=getClass(scope);
7409 if (!name.isEmpty())
7414 //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7415 QCString className=cd->name().copy();
7416 MemberName *mn=Doxygen::memberNameSDict->find(name);
7419 MemberNameIterator mni(*mn);
7421 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7423 ClassDef *cd=md->getClassDef();
7424 if (cd && cd->name()==className && md->isEnumerate())
7426 // documentation outside a compound overrides the documentation inside it
7428 if (!md->documentation() || rootNav->parent()->name().isEmpty())
7431 md->setDocumentation(root->doc,root->docFile,root->docLine);
7432 md->setDocsForDefinition(!root->proto);
7435 // brief descriptions inside a compound override the documentation
7438 if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7441 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7444 if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7446 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7449 if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7451 md->setMemberGroupId(root->mGrpId);
7454 md->addSectionsToDefinition(root->anchors);
7455 md->setRefItems(root->sli);
7457 GroupDef *gd=md->getGroupDef();
7458 if (gd==0 &&root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7460 addMemberToGroups(root,md);
7469 //printf("MemberName %s not found!\n",name.data());
7472 else // enum outside class
7474 //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7475 MemberName *mn=Doxygen::functionNameSDict->find(name);
7478 MemberNameIterator mni(*mn);
7480 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7482 if (md->isEnumerate())
7484 md->setDocumentation(root->doc,root->docFile,root->docLine);
7485 md->setDocsForDefinition(!root->proto);
7486 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7487 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7488 md->addSectionsToDefinition(root->anchors);
7489 md->setMemberGroupId(root->mGrpId);
7491 GroupDef *gd=md->getGroupDef();
7492 if (gd==0 && root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7494 addMemberToGroups(root,md);
7504 warn(root->fileName,root->startLine,
7505 "Documentation for undefined enum `%s' found.",
7511 rootNav->releaseEntry();
7513 RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7516 // search for each enum (member or function) in mnl if it has documented
7518 static void findDEV(const MemberNameSDict &mnsd)
7521 MemberNameSDict::Iterator mnli(mnsd);
7522 // for each member name
7523 for (mnli.toFirst();(mn=mnli.current());++mnli)
7526 MemberNameIterator mni(*mn);
7527 // for each member definition
7528 for (mni.toFirst();(md=mni.current());++mni)
7530 if (md->isEnumerate()) // member is an enum
7532 MemberList *fmdl = md->enumFieldList();
7533 int documentedEnumValues=0;
7534 if (fmdl) // enum has values
7536 MemberListIterator fmni(*fmdl);
7538 // for each enum value
7539 for (fmni.toFirst();(fmd=fmni.current());++fmni)
7541 if (fmd->isLinkableInProject()) documentedEnumValues++;
7544 // at least one enum value is documented
7545 if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7551 // search for each enum (member or function) if it has documented enum
7553 static void findDocumentedEnumValues()
7555 findDEV(*Doxygen::memberNameSDict);
7556 findDEV(*Doxygen::functionNameSDict);
7559 //----------------------------------------------------------------------
7561 static void addMembersToIndex()
7564 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7565 // for each member name
7566 for (mnli.toFirst();(mn=mnli.current());++mnli)
7569 MemberNameIterator mni(*mn);
7570 // for each member definition
7571 for (mni.toFirst();(md=mni.current());++mni)
7573 addClassMemberNameToIndex(md);
7576 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7577 // for each member name
7578 for (fnli.toFirst();(mn=fnli.current());++fnli)
7581 MemberNameIterator mni(*mn);
7582 // for each member definition
7583 for (mni.toFirst();(md=mni.current());++mni)
7585 if (md->getNamespaceDef())
7587 addNamespaceMemberNameToIndex(md);
7591 addFileMemberNameToIndex(md);
7597 //----------------------------------------------------------------------
7598 // computes the relation between all members. For each member `m'
7599 // the members that override the implementation of `m' are searched and
7600 // the member that `m' overrides is searched.
7602 static void computeMemberRelations()
7604 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7606 for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7608 MemberNameIterator mdi(*mn);
7609 MemberNameIterator bmdi(*mn);
7612 for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7614 for ( bmdi.toFirst() ; (bmd=bmdi.current()); ++bmdi ) // for each other member with the same name
7616 ClassDef *mcd = md->getClassDef();
7617 if (mcd && mcd->baseClasses())
7619 ClassDef *bmcd = bmd->getClassDef();
7620 //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7621 // mcd->name().data(),md->name().data(),md,
7622 // bmcd->name().data(),bmd->name().data(),bmd
7624 if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
7625 (bmd->virtualness()!=Normal ||
7626 bmcd->compoundType()==ClassDef::Interface ||
7627 bmcd->compoundType()==ClassDef::Protocol
7630 mcd->isLinkable() &&
7631 bmcd->isLinkable() &&
7632 mcd->isBaseClass(bmcd,TRUE))
7634 //printf(" derived scope\n");
7635 ArgumentList *bmdAl = bmd->argumentList();
7636 ArgumentList *mdAl = md->argumentList();
7637 //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7638 // argListToString(bmdAl.pointer()).data(),
7639 // argListToString(mdAl.pointer()).data()
7642 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl,
7643 md->getOuterScope(), md->getFileDef(), mdAl,
7649 if ((rmd=md->reimplements())==0 ||
7650 minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7653 //printf("setting (new) reimplements member\n");
7654 md->setReimplements(bmd);
7656 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7657 bmd->insertReimplementedBy(md);
7667 //----------------------------------------------------------------------------
7668 //static void computeClassImplUsageRelations()
7671 // ClassSDict::Iterator cli(*Doxygen::classSDict);
7672 // for (;(cd=cli.current());++cli)
7674 // cd->determineImplUsageRelation();
7678 //----------------------------------------------------------------------------
7680 static void createTemplateInstanceMembers()
7682 ClassSDict::Iterator cli(*Doxygen::classSDict);
7685 for (cli.toFirst();(cd=cli.current());++cli)
7687 // that is a template
7688 QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7691 QDictIterator<ClassDef> qdi(*templInstances);
7693 // for each instance of the template
7694 for (qdi.toFirst();(tcd=qdi.current());++qdi)
7696 tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7702 //----------------------------------------------------------------------------
7704 static void mergeCategories()
7707 ClassSDict::Iterator cli(*Doxygen::classSDict);
7708 // merge members of categories into the class they extend
7709 for (cli.toFirst();(cd=cli.current());++cli)
7711 int i=cd->name().find('(');
7712 if (i!=-1) // it is an Objective-C category
7714 QCString baseName=cd->name().left(i);
7715 ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7718 //printf("*** merging members of category %s into %s\n",
7719 // cd->name().data(),baseClass->name().data());
7720 baseClass->mergeCategory(cd);
7726 // builds the list of all members for each class
7728 static void buildCompleteMemberLists()
7731 ClassSDict::Iterator cli(*Doxygen::classSDict);
7732 // merge the member list of base classes into the inherited classes.
7733 for (cli.toFirst();(cd=cli.current());++cli)
7735 if (// !cd->isReference() && // not an external class
7736 cd->subClasses()==0 && // is a root of the hierarchy
7737 cd->baseClasses()) // and has at least one base class
7739 //printf("*** merging members for %s\n",cd->name().data());
7743 // now sort the member list of all classes.
7744 for (cli.toFirst();(cd=cli.current());++cli)
7746 if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7750 //----------------------------------------------------------------------------
7752 static void generateFileSources()
7754 if (Doxygen::inputNameList->count()>0)
7757 static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
7758 if (clangAssistedParsing)
7760 QDict<void> g_processedFiles(10007);
7762 // create a dictionary with files to process
7763 QDict<void> g_filesToProcess(10007);
7764 FileNameListIterator fnli(*Doxygen::inputNameList);
7766 for (fnli.toFirst();(fn=fnli.current());++fnli)
7768 FileNameIterator fni(*fn);
7770 for (;(fd=fni.current());++fni)
7772 g_filesToProcess.insert(fd->absFilePath(),(void*)0x8);
7775 // process source files (and their include dependencies)
7776 for (fnli.toFirst();(fn=fnli.current());++fnli)
7778 FileNameIterator fni(*fn);
7780 for (;(fd=fni.current());++fni)
7782 if (fd->isSource() && !fd->isReference())
7784 QStrList filesInSameTu;
7785 fd->getAllIncludeFilesRecursively(filesInSameTu);
7787 if (fd->generateSourceFile()) // sources need to be shown in the output
7789 msg("Generating code for file %s...\n",fd->docName().data());
7790 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7793 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7794 // we needed to parse the sources even if we do not show them
7796 msg("Parsing code for file %s...\n",fd->docName().data());
7797 fd->parseSource(FALSE,filesInSameTu);
7800 char *incFile = filesInSameTu.first();
7801 while (incFile && g_filesToProcess.find(incFile))
7803 if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile))
7807 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
7808 if (ifd && !ifd->isReference())
7810 if (ifd->generateSourceFile()) // sources need to be shown in the output
7812 msg(" Generating code for file %s...\n",ifd->docName().data());
7813 ifd->writeSource(*g_outputList,TRUE,moreFiles);
7816 else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
7817 // we needed to parse the sources even if we do not show them
7819 msg(" Parsing code for file %s...\n",ifd->docName().data());
7820 ifd->parseSource(TRUE,moreFiles);
7822 g_processedFiles.insert(incFile,(void*)0x8);
7825 incFile = filesInSameTu.next();
7827 fd->finishParsing();
7828 g_processedFiles.insert(fd->absFilePath(),(void*)0x8);
7832 // process remaining files
7833 for (fnli.toFirst();(fn=fnli.current());++fnli)
7835 FileNameIterator fni(*fn);
7837 for (;(fd=fni.current());++fni)
7839 if (!g_processedFiles.find(fd->absFilePath())) // not yet processed
7841 QStrList filesInSameTu;
7843 if (fd->generateSourceFile()) // sources need to be shown in the output
7845 msg("Generating code for file %s...\n",fd->docName().data());
7846 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7849 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7850 // we needed to parse the sources even if we do not show them
7852 msg("Parsing code for file %s...\n",fd->docName().data());
7853 fd->parseSource(FALSE,filesInSameTu);
7855 fd->finishParsing();
7863 FileNameListIterator fnli(*Doxygen::inputNameList);
7865 for (;(fn=fnli.current());++fnli)
7867 FileNameIterator fni(*fn);
7869 for (;(fd=fni.current());++fni)
7871 QStrList filesInSameTu;
7873 if (fd->generateSourceFile()) // sources need to be shown in the output
7875 msg("Generating code for file %s...\n",fd->docName().data());
7876 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7879 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7880 // we needed to parse the sources even if we do not show them
7882 msg("Parsing code for file %s...\n",fd->docName().data());
7883 fd->parseSource(FALSE,filesInSameTu);
7885 fd->finishParsing();
7892 //----------------------------------------------------------------------------
7894 static void generateFileDocs()
7896 if (documentedHtmlFiles==0) return;
7898 if (Doxygen::inputNameList->count()>0)
7900 FileNameListIterator fnli(*Doxygen::inputNameList);
7902 for (fnli.toFirst();(fn=fnli.current());++fnli)
7904 FileNameIterator fni(*fn);
7906 for (fni.toFirst();(fd=fni.current());++fni)
7908 bool doc = fd->isLinkableInProject();
7911 msg("Generating docs for file %s...\n",fd->docName().data());
7912 fd->writeDocumentation(*g_outputList);
7919 //----------------------------------------------------------------------------
7921 static void addSourceReferences()
7923 // add source references for class definitions
7924 ClassSDict::Iterator cli(*Doxygen::classSDict);
7926 for (cli.toFirst();(cd=cli.current());++cli)
7928 FileDef *fd=cd->getBodyDef();
7929 if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
7931 fd->addSourceRef(cd->getStartBodyLine(),cd,0);
7934 // add source references for namespace definitions
7935 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7937 for (nli.toFirst();(nd=nli.current());++nli)
7939 FileDef *fd=nd->getBodyDef();
7940 if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
7942 fd->addSourceRef(nd->getStartBodyLine(),nd,0);
7946 // add source references for member names
7947 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7949 for (mnli.toFirst();(mn=mnli.current());++mnli)
7951 MemberNameIterator mni(*mn);
7953 for (mni.toFirst();(md=mni.current());++mni)
7955 //printf("class member %s: def=%s body=%d link?=%d\n",
7956 // md->name().data(),
7957 // md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
7958 // md->getStartBodyLine(),md->isLinkableInProject());
7959 FileDef *fd=md->getBodyDef();
7961 md->getStartBodyLine()!=-1 &&
7962 md->isLinkableInProject() &&
7963 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7966 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7967 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
7968 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7972 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7973 for (fnli.toFirst();(mn=fnli.current());++fnli)
7975 MemberNameIterator mni(*mn);
7977 for (mni.toFirst();(md=mni.current());++mni)
7979 FileDef *fd=md->getBodyDef();
7980 //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
7981 // md->name().data(),
7982 // md->getStartBodyLine(),md->getEndBodyLine(),fd,
7983 // md->isLinkableInProject(),
7984 // Doxygen::parseSourcesNeeded);
7986 md->getStartBodyLine()!=-1 &&
7987 md->isLinkableInProject() &&
7988 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7991 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7992 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
7993 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7999 //----------------------------------------------------------------------------
8001 static void sortMemberLists()
8003 // sort class member lists
8004 ClassSDict::Iterator cli(*Doxygen::classSDict);
8006 for (cli.toFirst();(cd=cli.current());++cli)
8008 cd->sortMemberLists();
8011 // sort namespace member lists
8012 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8014 for (nli.toFirst();(nd=nli.current());++nli)
8016 nd->sortMemberLists();
8019 // sort file member lists
8020 FileNameListIterator fnli(*Doxygen::inputNameList);
8022 for (;(fn=fnli.current());++fnli)
8024 FileNameIterator fni(*fn);
8026 for (;(fd=fni.current());++fni)
8028 fd->sortMemberLists();
8032 // sort group member lists
8033 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8035 for (gli.toFirst();(gd=gli.current());++gli)
8037 gd->sortMemberLists();
8041 //----------------------------------------------------------------------------
8042 // generate the documentation of all classes
8044 static void generateClassList(ClassSDict &classSDict)
8046 ClassSDict::Iterator cli(classSDict);
8047 for ( ; cli.current() ; ++cli )
8049 ClassDef *cd=cli.current();
8051 //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
8052 if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8053 cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8054 ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8057 // skip external references, anonymous compounds and
8058 // template instances
8059 if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8061 msg("Generating docs for compound %s...\n",cd->name().data());
8063 cd->writeDocumentation(*g_outputList);
8064 cd->writeMemberList(*g_outputList);
8066 // even for undocumented classes, the inner classes can be documented.
8067 cd->writeDocumentationForInnerClasses(*g_outputList);
8072 static void generateClassDocs()
8074 generateClassList(*Doxygen::classSDict);
8075 generateClassList(*Doxygen::hiddenClasses);
8078 //----------------------------------------------------------------------------
8080 static void inheritDocumentation()
8082 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8085 for (;(mn=mnli.current());++mnli)
8087 MemberNameIterator mni(*mn);
8089 for (;(md=mni.current());++mni)
8091 //printf("%04d Member `%s'\n",count++,md->name().data());
8092 if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
8093 { // no documentation yet
8094 MemberDef *bmd = md->reimplements();
8095 while (bmd && bmd->documentation().isEmpty() &&
8096 bmd->briefDescription().isEmpty()
8098 { // search up the inheritance tree for a documentation member
8099 //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
8100 bmd = bmd->reimplements();
8102 if (bmd) // copy the documentation from the reimplemented member
8104 md->setInheritsDocsFrom(bmd);
8105 md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8106 md->setDocsForDefinition(bmd->isDocsForDefinition());
8107 md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8108 md->copyArgumentNames(bmd);
8109 md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
8116 //----------------------------------------------------------------------------
8118 static void combineUsingRelations()
8121 FileNameListIterator fnli(*Doxygen::inputNameList);
8123 for (fnli.toFirst();(fn=fnli.current());++fnli)
8125 FileNameIterator fni(*fn);
8127 for (fni.toFirst();(fd=fni.current());++fni)
8132 for (fnli.toFirst();(fn=fnli.current());++fnli)
8134 FileNameIterator fni(*fn);
8136 for (fni.toFirst();(fd=fni.current());++fni)
8138 fd->combineUsingRelations();
8142 // for each namespace
8143 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8145 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8149 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8151 nd->combineUsingRelations();
8155 //----------------------------------------------------------------------------
8157 static void addMembersToMemberGroup()
8160 ClassSDict::Iterator cli(*Doxygen::classSDict);
8162 for ( ; (cd=cli.current()) ; ++cli )
8164 cd->addMembersToMemberGroup();
8167 FileNameListIterator fnli(*Doxygen::inputNameList);
8169 for (fnli.toFirst();(fn=fnli.current());++fnli)
8171 FileNameIterator fni(*fn);
8173 for (fni.toFirst();(fd=fni.current());++fni)
8175 fd->addMembersToMemberGroup();
8178 // for each namespace
8179 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8181 for ( ; (nd=nli.current()) ; ++nli )
8183 nd->addMembersToMemberGroup();
8186 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8188 for (gli.toFirst();(gd=gli.current());++gli)
8190 gd->addMembersToMemberGroup();
8194 //----------------------------------------------------------------------------
8196 static void distributeMemberGroupDocumentation()
8199 ClassSDict::Iterator cli(*Doxygen::classSDict);
8201 for ( ; (cd=cli.current()) ; ++cli )
8203 cd->distributeMemberGroupDocumentation();
8206 FileNameListIterator fnli(*Doxygen::inputNameList);
8208 for (fnli.toFirst();(fn=fnli.current());++fnli)
8210 FileNameIterator fni(*fn);
8212 for (fni.toFirst();(fd=fni.current());++fni)
8214 fd->distributeMemberGroupDocumentation();
8217 // for each namespace
8218 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8220 for ( ; (nd=nli.current()) ; ++nli )
8222 nd->distributeMemberGroupDocumentation();
8225 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8227 for (gli.toFirst();(gd=gli.current());++gli)
8229 gd->distributeMemberGroupDocumentation();
8233 //----------------------------------------------------------------------------
8235 static void findSectionsInDocumentation()
8238 ClassSDict::Iterator cli(*Doxygen::classSDict);
8240 for ( ; (cd=cli.current()) ; ++cli )
8242 cd->findSectionsInDocumentation();
8245 FileNameListIterator fnli(*Doxygen::inputNameList);
8247 for (fnli.toFirst();(fn=fnli.current());++fnli)
8249 FileNameIterator fni(*fn);
8251 for (fni.toFirst();(fd=fni.current());++fni)
8253 fd->findSectionsInDocumentation();
8256 // for each namespace
8257 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8259 for ( ; (nd=nli.current()) ; ++nli )
8261 nd->findSectionsInDocumentation();
8264 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8266 for (gli.toFirst();(gd=gli.current());++gli)
8268 gd->findSectionsInDocumentation();
8271 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8273 for (pdi.toFirst();(pd=pdi.current());++pdi)
8275 pd->findSectionsInDocumentation();
8277 if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8280 static void flushCachedTemplateRelations()
8282 // remove all references to classes from the cache
8283 // as there can be new template instances in the inheritance path
8284 // to this class. Optimization: only remove those classes that
8285 // have inheritance instances as direct or indirect sub classes.
8286 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8288 for (ci.toFirst();(li=ci.current());++ci)
8292 Doxygen::lookupCache->remove(ci.currentKey());
8295 // remove all cached typedef resolutions whose target is a
8296 // template class as this may now be a template instance
8297 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8299 for (;(fn=fnli.current());++fnli) // for each global function name
8301 MemberNameIterator fni(*fn);
8303 for (;(fmd=fni.current());++fni) // for each function with that name
8305 if (fmd->isTypedefValCached())
8307 ClassDef *cd = fmd->getCachedTypedefVal();
8308 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8312 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8313 for (;(fn=mnli.current());++mnli) // for each class method name
8315 MemberNameIterator mni(*fn);
8317 for (;(fmd=mni.current());++mni) // for each function with that name
8319 if (fmd->isTypedefValCached())
8321 ClassDef *cd = fmd->getCachedTypedefVal();
8322 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8328 //----------------------------------------------------------------------------
8330 static void flushUnresolvedRelations()
8332 // Remove all unresolved references to classes from the cache.
8333 // This is needed before resolving the inheritance relations, since
8334 // it would otherwise not find the inheritance relation
8335 // for C in the example below, as B::I was already found to be unresolvable
8336 // (which is correct if you igore the inheritance relation between A and B).
8338 // class A { class I {} };
8339 // class B : public A {};
8340 // class C : public B::I {};
8342 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8344 for (ci.toFirst();(li=ci.current());++ci)
8346 if (li->classDef==0 && li->typeDef==0)
8348 Doxygen::lookupCache->remove(ci.currentKey());
8352 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8354 for (;(fn=fnli.current());++fnli) // for each global function name
8356 MemberNameIterator fni(*fn);
8358 for (;(fmd=fni.current());++fni) // for each function with that name
8360 fmd->invalidateCachedArgumentTypes();
8363 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8364 for (;(fn=mnli.current());++mnli) // for each class method name
8366 MemberNameIterator mni(*fn);
8368 for (;(fmd=mni.current());++mni) // for each function with that name
8370 fmd->invalidateCachedArgumentTypes();
8376 //----------------------------------------------------------------------------
8378 static void findDefineDocumentation(EntryNav *rootNav)
8380 if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
8381 rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
8384 rootNav->loadEntry(g_storage);
8385 Entry *root = rootNav->entry();
8387 //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
8388 // root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
8390 if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8392 MemberDef *md=new MemberDef("<tagfile>",1,1,
8393 "#define",root->name,root->args,0,
8394 Public,Normal,FALSE,Member,MemberType_Define,0,0);
8395 md->setTagInfo(rootNav->tagInfo());
8396 md->setLanguage(root->lang);
8397 //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
8398 md->setFileDef(rootNav->parent()->fileDef());
8399 //printf("Adding member=%s\n",md->name().data());
8401 if ((mn=Doxygen::functionNameSDict->find(root->name)))
8407 mn = new MemberName(root->name);
8409 Doxygen::functionNameSDict->append(root->name,mn);
8412 MemberName *mn=Doxygen::functionNameSDict->find(root->name);
8415 MemberNameIterator mni(*mn);
8418 for (;(md=mni.current());++mni)
8420 if (md->memberType()==MemberType_Define) count++;
8424 for (mni.toFirst();(md=mni.current());++mni)
8426 if (md->memberType()==MemberType_Define)
8428 md->setDocumentation(root->doc,root->docFile,root->docLine);
8429 md->setDocsForDefinition(!root->proto);
8430 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8431 if (md->inbodyDocumentation().isEmpty())
8433 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8435 md->setBodySegment(root->bodyLine,root->endBodyLine);
8436 md->setBodyDef(rootNav->fileDef());
8437 md->addSectionsToDefinition(root->anchors);
8438 md->setMaxInitLines(root->initLines);
8439 md->setRefItems(root->sli);
8440 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8441 addMemberToGroups(root,md);
8446 (!root->doc.isEmpty() ||
8447 !root->brief.isEmpty() ||
8451 // multiple defines don't know where to add docs
8452 // but maybe they are in different files together with their documentation
8454 for (mni.toFirst();(md=mni.current());++mni)
8456 if (md->memberType()==MemberType_Define)
8458 FileDef *fd=md->getFileDef();
8459 if (fd && fd->absFilePath()==root->fileName)
8460 // doc and define in the same file assume they belong together.
8463 if (md->documentation().isEmpty())
8466 md->setDocumentation(root->doc,root->docFile,root->docLine);
8467 md->setDocsForDefinition(!root->proto);
8470 if (md->briefDescription().isEmpty())
8473 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8475 if (md->inbodyDocumentation().isEmpty())
8477 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8479 md->setBodySegment(root->bodyLine,root->endBodyLine);
8480 md->setBodyDef(rootNav->fileDef());
8481 md->addSectionsToDefinition(root->anchors);
8482 md->setRefItems(root->sli);
8483 md->setLanguage(root->lang);
8484 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8485 addMemberToGroups(root,md);
8489 //warn("define %s found in the following files:\n",root->name.data());
8490 //warn("Cannot determine where to add the documentation found "
8491 // "at line %d of file %s. \n",
8492 // root->startLine,root->fileName.data());
8495 else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8497 static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
8500 warn(root->fileName,root->startLine,
8501 "documentation for unknown define %s found.\n",
8507 warn(root->fileName,root->startLine,
8508 "found documented #define but ignoring it because "
8509 "ENABLE_PREPROCESSING is NO.\n",
8515 rootNav->releaseEntry();
8517 RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8520 //----------------------------------------------------------------------------
8522 static void findDirDocumentation(EntryNav *rootNav)
8524 if (rootNav->section() == Entry::DIRDOC_SEC)
8526 rootNav->loadEntry(g_storage);
8527 Entry *root = rootNav->entry();
8529 QCString normalizedName = root->name;
8530 normalizedName = substitute(normalizedName,"\\","/");
8531 //printf("root->docFile=%s normalizedName=%s\n",
8532 // root->docFile.data(),normalizedName.data());
8533 if (root->docFile==normalizedName) // current dir?
8535 int lastSlashPos=normalizedName.findRev('/');
8536 if (lastSlashPos!=-1) // strip file name
8538 normalizedName=normalizedName.left(lastSlashPos);
8541 if (normalizedName.at(normalizedName.length()-1)!='/')
8543 normalizedName+='/';
8545 DirDef *dir,*matchingDir=0;
8546 SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8547 for (sdi.toFirst();(dir=sdi.current());++sdi)
8549 //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8550 if (dir->name().right(normalizedName.length())==normalizedName)
8554 warn(root->fileName,root->startLine,
8555 "\\dir command matches multiple directories.\n"
8556 " Applying the command for directory %s\n"
8557 " Ignoring the command for directory %s\n",
8558 matchingDir->name().data(),dir->name().data()
8569 //printf("Match for with dir %s\n",matchingDir->name().data());
8570 matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8571 matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8572 matchingDir->setRefItems(root->sli);
8573 addDirToGroups(root,matchingDir);
8577 warn(root->fileName,root->startLine,"No matching "
8578 "directory found for command \\dir %s\n",normalizedName.data());
8580 rootNav->releaseEntry();
8582 RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8586 //----------------------------------------------------------------------------
8587 // create a (sorted) list of separate documentation pages
8589 static void buildPageList(EntryNav *rootNav)
8591 if (rootNav->section() == Entry::PAGEDOC_SEC)
8593 rootNav->loadEntry(g_storage);
8594 Entry *root = rootNav->entry();
8596 if (!root->name.isEmpty())
8598 addRelatedPage(rootNav);
8601 rootNav->releaseEntry();
8603 else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8605 rootNav->loadEntry(g_storage);
8606 Entry *root = rootNav->entry();
8608 QCString title=root->args.stripWhiteSpace();
8609 if (title.isEmpty()) title=theTranslator->trMainPage();
8610 //QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8611 QCString name = "index";
8612 addRefItem(root->sli,
8620 rootNav->releaseEntry();
8622 RECURSE_ENTRYTREE(buildPageList,rootNav);
8625 static void findMainPage(EntryNav *rootNav)
8627 if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8629 rootNav->loadEntry(g_storage);
8630 Entry *root = rootNav->entry();
8632 if (Doxygen::mainPage==0)
8634 //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8635 QCString title=root->args.stripWhiteSpace();
8636 //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8637 QCString indexName="index";
8638 Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8639 indexName, root->brief+root->doc+root->inbodyDocs,title);
8640 //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8641 Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8642 Doxygen::mainPage->setFileName(indexName,TRUE);
8643 Doxygen::mainPage->setShowToc(root->stat);
8644 addPageToContext(Doxygen::mainPage,rootNav);
8646 SectionInfo *si = Doxygen::sectionDict->find(Doxygen::mainPage->name());
8649 if (si->lineNr != -1)
8651 warn(root->fileName,root->startLine,"multiple use of section label '%s', (first occurrence: %s, line %d)",Doxygen::mainPage->name().data(),si->fileName.data(),si->lineNr);
8655 warn(root->fileName,root->startLine,"multiple use of section label '%s', (first occurrence: %s)",Doxygen::mainPage->name().data(),si->fileName.data());
8660 // a page name is a label as well! but should no be double either
8662 indexName, root->startLine,
8663 Doxygen::mainPage->name(),
8664 Doxygen::mainPage->title(),
8667 Doxygen::sectionDict->append(indexName,si);
8668 Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8673 warn(root->fileName,root->startLine,
8674 "found more than one \\mainpage comment block! Skipping this "
8679 rootNav->releaseEntry();
8681 RECURSE_ENTRYTREE(findMainPage,rootNav);
8684 static void computePageRelations(EntryNav *rootNav)
8686 if ((rootNav->section()==Entry::PAGEDOC_SEC ||
8687 rootNav->section()==Entry::MAINPAGEDOC_SEC
8689 && !rootNav->name().isEmpty()
8692 rootNav->loadEntry(g_storage);
8693 Entry *root = rootNav->entry();
8695 PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8696 Doxygen::pageSDict->find(root->name) :
8700 QListIterator<BaseInfo> bii(*root->extends);
8702 for (bii.toFirst();(bi=bii.current());++bii)
8704 PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8707 pd->addInnerCompound(subPd);
8708 //printf("*** Added subpage relation: %s->%s\n",
8709 // pd->name().data(),subPd->name().data());
8714 rootNav->releaseEntry();
8716 RECURSE_ENTRYTREE(computePageRelations,rootNav);
8719 static void checkPageRelations()
8721 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8723 for (pdi.toFirst();(pd=pdi.current());++pdi)
8725 Definition *ppd = pd->getOuterScope();
8730 err("page defined at line %d of file %s with label %s is a subpage "
8731 "of itself! Please remove this cyclic dependency.\n",
8732 pd->docLine(),pd->docFile().data(),pd->name().data());
8735 ppd=ppd->getOuterScope();
8740 //----------------------------------------------------------------------------
8742 static void resolveUserReferences()
8744 SDict<SectionInfo>::Iterator sdi(*Doxygen::sectionDict);
8746 for (;(si=sdi.current());++sdi)
8748 //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8749 // si->label.data(),si->definition?si->definition->name().data():"<none>",
8750 // si->fileName.data());
8753 // hack: the items of a todo/test/bug/deprecated list are all fragments from
8754 // different files, so the resulting section's all have the wrong file
8755 // name (not from the todo/test/bug/deprecated list, but from the file in
8756 // which they are defined). We correct this here by looking at the
8757 // generated section labels!
8758 QDictIterator<RefList> rli(*Doxygen::xrefLists);
8760 for (rli.toFirst();(rl=rli.current());++rli)
8762 QCString label="_"+rl->listName(); // "_todo", "_test", ...
8763 if (si->label.left(label.length())==label)
8765 si->fileName=rl->listName();
8771 //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8774 // if this section is in a page and the page is in a group, then we
8775 // have to adjust the link file name to point to the group.
8776 if (!si->fileName.isEmpty() &&
8777 (pd=Doxygen::pageSDict->find(si->fileName)) &&
8780 si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8785 // TODO: there should be one function in Definition that returns
8786 // the file to link to, so we can avoid the following tests.
8788 if (si->definition->definitionType()==Definition::TypeMember)
8790 gd = ((MemberDef *)si->definition)->getGroupDef();
8795 si->fileName=gd->getOutputFileBase().copy();
8799 //si->fileName=si->definition->getOutputFileBase().copy();
8800 //printf("Setting si->fileName to %s\n",si->fileName.data());
8804 //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8810 //----------------------------------------------------------------------------
8811 // generate all separate documentation pages
8814 static void generatePageDocs()
8816 //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8817 if (documentedPages==0) return;
8818 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8820 for (pdi.toFirst();(pd=pdi.current());++pdi)
8822 if (!pd->getGroupDef() && !pd->isReference())
8824 msg("Generating docs for page %s...\n",pd->name().data());
8825 Doxygen::insideMainPage=TRUE;
8826 pd->writeDocumentation(*g_outputList);
8827 Doxygen::insideMainPage=FALSE;
8832 //----------------------------------------------------------------------------
8833 // create a (sorted) list & dictionary of example pages
8835 static void buildExampleList(EntryNav *rootNav)
8837 if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty())
8839 rootNav->loadEntry(g_storage);
8840 Entry *root = rootNav->entry();
8842 if (Doxygen::exampleSDict->find(root->name))
8844 warn(root->fileName,root->startLine,
8845 "Example %s was already documented. Ignoring "
8846 "documentation found here.",
8852 PageDef *pd=new PageDef(root->fileName,root->startLine,
8853 root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8854 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8855 pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE),FALSE);
8856 pd->addSectionsToDefinition(root->anchors);
8857 pd->setLanguage(root->lang);
8858 //pi->addSections(root->anchors);
8860 Doxygen::exampleSDict->inSort(root->name,pd);
8861 //we don't add example to groups
8862 //addExampleToGroups(root,pd);
8865 rootNav->releaseEntry();
8867 RECURSE_ENTRYTREE(buildExampleList,rootNav);
8870 //----------------------------------------------------------------------------
8871 // prints the Entry tree (for debugging)
8873 void printNavTree(EntryNav *rootNav,int indent)
8876 indentStr.fill(' ',indent);
8877 msg("%s%s (sec=0x%x)\n",
8878 indentStr.isEmpty()?"":indentStr.data(),
8879 rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8880 rootNav->section());
8881 if (rootNav->children())
8883 EntryNavListIterator eli(*rootNav->children());
8884 for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8889 //----------------------------------------------------------------------------
8890 // generate the example documentation
8892 static void generateExampleDocs()
8894 g_outputList->disable(OutputGenerator::Man);
8895 PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8897 for (pdi.toFirst();(pd=pdi.current());++pdi)
8899 msg("Generating docs for example %s...\n",pd->name().data());
8900 resetCCodeParserState();
8901 QCString n=pd->getOutputFileBase();
8902 startFile(*g_outputList,n,n,pd->name());
8903 startTitle(*g_outputList,n);
8904 g_outputList->docify(pd->name());
8905 endTitle(*g_outputList,n,0);
8906 g_outputList->startContents();
8907 g_outputList->generateDoc(pd->docFile(), // file
8908 pd->docLine(), // startLine
8911 pd->documentation()+"\n\n\\include "+pd->name(), // docs
8912 TRUE, // index words
8916 endFile(*g_outputList); // contains g_outputList->endContents()
8918 g_outputList->enable(OutputGenerator::Man);
8921 //----------------------------------------------------------------------------
8922 // generate module pages
8924 static void generateGroupDocs()
8926 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8928 for (gli.toFirst();(gd=gli.current());++gli)
8930 if (!gd->isReference())
8932 gd->writeDocumentation(*g_outputList);
8937 //----------------------------------------------------------------------------
8939 //static void generatePackageDocs()
8941 // writePackageIndex(*g_outputList);
8943 // if (Doxygen::packageDict.count()>0)
8945 // PackageSDict::Iterator pdi(Doxygen::packageDict);
8947 // for (pdi.toFirst();(pd=pdi.current());++pdi)
8949 // pd->writeDocumentation(*g_outputList);
8954 //----------------------------------------------------------------------------
8955 // generate module pages
8957 static void generateNamespaceDocs()
8959 //writeNamespaceIndex(*g_outputList);
8961 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8963 // for each namespace...
8964 for (;(nd=nli.current());++nli)
8967 if (nd->isLinkableInProject())
8969 msg("Generating docs for namespace %s\n",nd->name().data());
8970 nd->writeDocumentation(*g_outputList);
8973 // for each class in the namespace...
8974 ClassSDict::Iterator cli(*nd->getClassSDict());
8975 for ( ; cli.current() ; ++cli )
8977 ClassDef *cd=cli.current();
8978 if ( ( cd->isLinkableInProject() &&
8979 cd->templateMaster()==0
8980 ) // skip external references, anonymous compounds and
8981 // template instances and nested classes
8982 && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8985 msg("Generating docs for compound %s...\n",cd->name().data());
8987 cd->writeDocumentation(*g_outputList);
8988 cd->writeMemberList(*g_outputList);
8990 cd->writeDocumentationForInnerClasses(*g_outputList);
8996 static QCString fixSlashes(QCString &s)
9000 for (i=0;i<s.length();i++)
9017 //----------------------------------------------------------------------------
9019 static bool openOutputFile(const char *outFile,QFile &f)
9021 bool fileOpened=FALSE;
9022 bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
9023 if (writeToStdout) // write to stdout
9025 fileOpened = f.open(IO_WriteOnly,stdout);
9027 else // write to file
9029 QFileInfo fi(outFile);
9030 if (fi.exists()) // create a backup
9033 QFileInfo backup(fi.fileName()+".bak");
9034 if (backup.exists()) // remove existing backup
9035 dir.remove(backup.fileName());
9036 dir.rename(fi.fileName(),fi.fileName()+".bak");
9039 fileOpened = f.open(IO_WriteOnly|IO_Translate);
9044 /*! Generate a template version of the configuration file.
9045 * If the \a shortList parameter is TRUE a configuration file without
9046 * comments will be generated.
9048 static void generateConfigFile(const char *configFile,bool shortList,
9049 bool updateOnly=FALSE)
9052 bool fileOpened=openOutputFile(configFile,f);
9053 bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
9057 Config::instance()->writeTemplate(t,shortList,updateOnly);
9062 msg("\n\nConfiguration file `%s' created.\n\n",configFile);
9063 msg("Now edit the configuration file and enter\n\n");
9064 if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
9065 msg(" doxygen %s\n\n",configFile);
9067 msg(" doxygen\n\n");
9068 msg("to generate the documentation for your project\n\n");
9072 msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
9078 err("Cannot open file %s for writing\n",configFile);
9083 //----------------------------------------------------------------------------
9084 // read and parse a tag file
9086 //static bool readLineFromFile(QFile &f,QCString &s)
9090 // while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
9091 // return f.atEnd();
9094 //----------------------------------------------------------------------------
9096 static void readTagFile(Entry *root,const char *tl)
9098 QCString tagLine = tl;
9101 int eqPos = tagLine.find('=');
9102 if (eqPos!=-1) // tag command contains a destination
9104 fileName = tagLine.left(eqPos).stripWhiteSpace();
9105 destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9106 QFileInfo fi(fileName);
9107 Doxygen::tagDestinationDict.insert(fi.absFilePath().utf8(),new QCString(destName));
9108 //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
9115 QFileInfo fi(fileName);
9116 if (!fi.exists() || !fi.isFile())
9118 err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
9123 if (!destName.isEmpty())
9124 msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
9126 msg("Reading tag file `%s'...\n",fileName.data());
9128 parseTagFile(root,fi.absFilePath().utf8());
9131 //----------------------------------------------------------------------------
9132 static void copyStyleSheet()
9134 QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
9135 if (!htmlStyleSheet.isEmpty())
9137 QFileInfo fi(htmlStyleSheet);
9140 err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
9141 htmlStyleSheet.resize(0); // revert to the default
9145 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9146 copyFile(htmlStyleSheet,destFileName);
9149 QCString &htmlExtraStyleSheet = Config_getString("HTML_EXTRA_STYLESHEET");
9150 if (!htmlExtraStyleSheet.isEmpty())
9152 QFileInfo fi(htmlExtraStyleSheet);
9155 err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",htmlExtraStyleSheet.data());
9156 htmlExtraStyleSheet.resize(0); // revert to the default
9160 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9161 copyFile(htmlExtraStyleSheet,destFileName);
9167 static void copyLogo()
9169 QCString &projectLogo = Config_getString("PROJECT_LOGO");
9170 if (!projectLogo.isEmpty())
9172 QFileInfo fi(projectLogo);
9175 err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
9176 projectLogo.resize(0); // revert to the default
9180 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
9181 copyFile(projectLogo,destFileName);
9182 Doxygen::indexList->addImageFile(fi.fileName().data());
9187 static void copyExtraFiles(const QCString& filesOption,const QCString &outputOption)
9189 QStrList files = Config_getList(filesOption);
9191 for (i=0; i<files.count(); ++i)
9193 QCString fileName(files.at(i));
9195 if (!fileName.isEmpty())
9197 QFileInfo fi(fileName);
9200 err("Extra file '%s' specified in " + filesOption + " does not exist!\n", fileName.data());
9204 QCString destFileName = Config_getString(outputOption)+"/"+fi.fileName().data();
9205 Doxygen::indexList->addImageFile(fi.fileName().utf8());
9206 copyFile(fileName, destFileName);
9212 //----------------------------------------------------------------------------
9214 static ParserInterface *getParserForFile(const char *fn)
9216 QCString fileName=fn;
9218 int ei = fileName.findRev('.');
9221 extension=fileName.right(fileName.length()-ei);
9225 extension = ".no_extension";
9228 return Doxygen::parserManager->getParser(extension);
9231 static void parseFile(ParserInterface *parser,
9232 Entry *root,EntryNav *rootNav,FileDef *fd,const char *fn,
9233 bool sameTu,QStrList &filesInSameTu)
9236 static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
9238 static bool clangAssistedParsing = FALSE;
9240 QCString fileName=fn;
9242 int ei = fileName.findRev('.');
9245 extension=fileName.right(fileName.length()-ei);
9249 extension = ".no_extension";
9252 QFileInfo fi(fileName);
9253 BufStr preBuf(fi.size()+4096);
9255 if (Config_getBool("ENABLE_PREPROCESSING") &&
9256 parser->needsPreprocessing(extension))
9258 BufStr inBuf(fi.size()+4096);
9259 msg("Preprocessing %s...\n",fn);
9260 readInputFile(fileName,inBuf);
9261 preprocessFile(fileName,inBuf,preBuf);
9263 else // no preprocessing
9265 msg("Reading %s...\n",fn);
9266 readInputFile(fileName,preBuf);
9269 BufStr convBuf(preBuf.curPos()+1024);
9271 // convert multi-line C++ comments to C style comments
9272 convertCppComments(&preBuf,&convBuf,fileName);
9274 convBuf.addChar('\0');
9276 if (clangAssistedParsing && !sameTu)
9278 fd->getAllIncludeFilesRecursively(filesInSameTu);
9281 // use language parse to parse the file
9282 parser->parseInput(fileName,convBuf.data(),root,sameTu,filesInSameTu);
9284 // store the Entry tree in a file and create an index to
9285 // navigate/load entries
9286 //printf("root->createNavigationIndex for %s\n",fd->name().data());
9287 root->createNavigationIndex(rootNav,g_storage,fd);
9290 //! parse the list of input files
9291 static void parseFiles(Entry *root,EntryNav *rootNav)
9294 static bool clangAssistedParsing = Config_getBool("CLANG_ASSISTED_PARSING");
9295 if (clangAssistedParsing)
9297 QDict<void> g_processedFiles(10007);
9299 // create a dictionary with files to process
9300 QDict<void> g_filesToProcess(10007);
9301 StringListIterator it(g_inputFiles);
9303 for (;(s=it.current());++it)
9305 g_filesToProcess.insert(*s,(void*)0x8);
9308 // process source files (and their include dependencies)
9309 for (it.toFirst();(s=it.current());++it)
9312 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9314 if (fd->isSource() && !fd->isReference()) // this is a source file
9316 QStrList filesInSameTu;
9317 ParserInterface * parser = getParserForFile(s->data());
9318 parser->startTranslationUnit(s->data());
9319 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9320 //printf(" got %d extra files in tu\n",filesInSameTu.count());
9322 // Now process any include files in the same translation unit
9323 // first. When libclang is used this is much more efficient.
9324 char *incFile = filesInSameTu.first();
9325 while (incFile && g_filesToProcess.find(incFile))
9327 if (qstrcmp(incFile,s->data()) && !g_processedFiles.find(incFile))
9329 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
9330 if (ifd && !ifd->isReference())
9333 //printf(" Processing %s in same translation unit as %s\n",incFile,s->data());
9334 parseFile(parser,root,rootNav,ifd,incFile,TRUE,moreFiles);
9335 g_processedFiles.insert(incFile,(void*)0x8);
9338 incFile = filesInSameTu.next();
9340 parser->finishTranslationUnit();
9341 g_processedFiles.insert(*s,(void*)0x8);
9344 // process remaining files
9345 for (it.toFirst();(s=it.current());++it)
9347 if (!g_processedFiles.find(*s)) // not yet processed
9350 QStrList filesInSameTu;
9351 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9353 ParserInterface * parser = getParserForFile(s->data());
9354 parser->startTranslationUnit(s->data());
9355 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9356 parser->finishTranslationUnit();
9357 g_processedFiles.insert(*s,(void*)0x8);
9361 else // normal pocessing
9364 StringListIterator it(g_inputFiles);
9366 for (;(s=it.current());++it)
9369 QStrList filesInSameTu;
9370 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9372 ParserInterface * parser = getParserForFile(s->data());
9373 parser->startTranslationUnit(s->data());
9374 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9379 // resolves a path that may include symlinks, if a recursive symlink is
9380 // found an empty string is returned.
9381 static QCString resolveSymlink(QCString path)
9386 QDict<void> nonSymlinks;
9388 QCString result = path;
9389 QCString oldPrefix = "/";
9393 // UNC path, skip server and share name
9394 if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
9395 sepPos = result.find('/',2);
9397 sepPos = result.find('/',sepPos+1);
9399 sepPos = result.find('/',sepPos+1);
9401 QCString prefix = sepPos==-1 ? result : result.left(sepPos);
9402 if (nonSymlinks.find(prefix)==0)
9407 QString target = fi.readLink();
9408 bool isRelative = QFileInfo(target).isRelative();
9411 target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
9415 if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
9419 target+=result.mid(sepPos);
9421 result = QDir::cleanDirPath(target).data();
9423 if (known.find(result)) return QCString(); // recursive symlink!
9424 known.insert(result,(void*)0x8);
9429 else // link to absolute path
9437 nonSymlinks.insert(prefix,(void*)0x8);
9444 return QDir::cleanDirPath(result).data();
9447 static QDict<void> g_pathsVisited(1009);
9449 //----------------------------------------------------------------------------
9450 // Read all files matching at least one pattern in `patList' in the
9451 // directory represented by `fi'.
9452 // The directory is read iff the recusiveFlag is set.
9453 // The contents of all files is append to the input string
9455 int readDir(QFileInfo *fi,
9456 FileNameList *fnList,
9457 FileNameDict *fnDict,
9458 StringDict *exclDict,
9460 QStrList *exclPatList,
9461 StringList *resultList,
9462 StringDict *resultDict,
9463 bool errorIfNotExist,
9465 QDict<void> *killDict,
9469 QCString dirName = fi->absFilePath().utf8();
9470 if (paths && paths->find(dirName)==0)
9472 paths->insert(dirName,(void*)0x8);
9474 if (fi->isSymLink())
9476 dirName = resolveSymlink(dirName.data());
9477 if (dirName.isEmpty()) return 0; // recusive symlink
9478 if (g_pathsVisited.find(dirName)) return 0; // already visited path
9479 g_pathsVisited.insert(dirName,(void*)0x8);
9482 dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
9484 msg("Searching for files in directory %s\n", fi->absFilePath().data());
9485 //printf("killDict=%p count=%d\n",killDict,killDict->count());
9487 const QFileInfoList *list = dir.entryInfoList();
9490 QFileInfoListIterator it( *list );
9493 while ((cfi=it.current()))
9495 if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0)
9496 { // file should not be excluded
9497 //printf("killDict->find(%s)\n",cfi->absFilePath().data());
9498 if (!cfi->exists() || !cfi->isReadable())
9500 if (errorIfNotExist)
9502 warn_uncond("source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
9505 else if (cfi->isFile() &&
9506 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
9507 (patList==0 || patternMatch(*cfi,patList)) &&
9508 !patternMatch(*cfi,exclPatList) &&
9509 (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
9512 totalSize+=cfi->size()+cfi->absFilePath().length()+4;
9513 QCString name=cfi->fileName().utf8();
9514 //printf("New file %s\n",name.data());
9517 FileDef *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
9519 if (!name.isEmpty() && (fn=(*fnDict)[name]))
9525 fn = new FileName(cfi->absFilePath().utf8(),name);
9527 if (fnList) fnList->inSort(fn);
9528 fnDict->insert(name,fn);
9532 if (resultList || resultDict)
9534 rs=new QCString(cfi->absFilePath().utf8());
9536 if (resultList) resultList->append(rs);
9537 if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
9538 if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
9540 else if (recursive &&
9541 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
9543 !patternMatch(*cfi,exclPatList) &&
9544 cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
9546 cfi->setFile(cfi->absFilePath());
9547 totalSize+=readDir(cfi,fnList,fnDict,exclDict,
9548 patList,exclPatList,resultList,resultDict,errorIfNotExist,
9549 recursive,killDict,paths);
9559 //----------------------------------------------------------------------------
9560 // read a file or all files in a directory and append their contents to the
9561 // input string. The names of the files are appended to the `fiList' list.
9563 int readFileOrDirectory(const char *s,
9564 FileNameList *fnList,
9565 FileNameDict *fnDict,
9566 StringDict *exclDict,
9568 QStrList *exclPatList,
9569 StringList *resultList,
9570 StringDict *resultDict,
9572 bool errorIfNotExist,
9573 QDict<void> *killDict,
9577 //printf("killDict=%p count=%d\n",killDict,killDict->count());
9578 // strip trailing slashes
9581 char lc = fs.at(fs.length()-1);
9582 if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9585 //printf("readFileOrDirectory(%s)\n",s);
9588 if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9590 if (!fi.exists() || !fi.isReadable())
9592 if (errorIfNotExist)
9594 warn_uncond("source %s is not a readable file or directory... skipping.\n",s);
9597 else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
9601 QCString dirPath = fi.dirPath(TRUE).utf8();
9602 QCString filePath = fi.absFilePath().utf8();
9603 if (paths && paths->find(dirPath))
9605 paths->insert(dirPath,(void*)0x8);
9607 //printf("killDict->find(%s)\n",fi.absFilePath().data());
9608 if (killDict==0 || killDict->find(filePath)==0)
9610 totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input);
9611 //fiList->inSort(new FileInfo(fi));
9612 QCString name=fi.fileName().utf8();
9613 //printf("New file %s\n",name.data());
9616 FileDef *fd=new FileDef(dirPath+"/",name);
9618 if (!name.isEmpty() && (fn=(*fnDict)[name]))
9624 fn = new FileName(filePath,name);
9626 if (fnList) fnList->inSort(fn);
9627 fnDict->insert(name,fn);
9631 if (resultList || resultDict)
9633 rs=new QCString(filePath);
9634 if (resultList) resultList->append(rs);
9635 if (resultDict) resultDict->insert(filePath,rs);
9638 if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9641 else if (fi.isDir()) // readable dir
9643 totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9644 exclPatList,resultList,resultDict,errorIfNotExist,
9645 recursive,killDict,paths);
9653 //----------------------------------------------------------------------------
9655 void readFormulaRepository()
9657 QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
9658 if (f.open(IO_ReadOnly)) // open repository
9660 msg("Reading formula repository...\n");
9665 line=t.readLine().utf8();
9666 int se=line.find(':'); // find name and text separator.
9669 warn_uncond("formula.repository is corrupted!\n");
9674 QCString formName = line.left(se);
9675 QCString formText = line.right(line.length()-se-1);
9676 Formula *f=new Formula(formText);
9677 Doxygen::formulaList->setAutoDelete(TRUE);
9678 Doxygen::formulaList->append(f);
9679 Doxygen::formulaDict->insert(formText,f);
9680 Doxygen::formulaNameDict->insert(formName,f);
9686 //----------------------------------------------------------------------------
9688 static void expandAliases()
9690 QDictIterator<QCString> adi(Doxygen::aliasDict);
9692 for (adi.toFirst();(s=adi.current());++adi)
9694 *s = expandAlias(adi.currentKey(),*s);
9698 //----------------------------------------------------------------------------
9700 static void escapeAliases()
9702 QDictIterator<QCString> adi(Doxygen::aliasDict);
9704 for (adi.toFirst();(s=adi.current());++adi)
9706 QCString value=*s,newValue;
9708 // for each \n in the alias command value
9709 while ((in=value.find("\\n",p))!=-1)
9711 newValue+=value.mid(p,in-p);
9712 // expand \n's except if \n is part of a built-in command.
9713 if (value.mid(in,5)!="\\note" &&
9714 value.mid(in,5)!="\\name" &&
9715 value.mid(in,10)!="\\namespace" &&
9716 value.mid(in,14)!="\\nosubgrouping"
9719 newValue+="\\_linebr ";
9727 newValue+=value.mid(p,value.length()-p);
9729 //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9733 //----------------------------------------------------------------------------
9737 // add aliases to a dictionary
9738 Doxygen::aliasDict.setAutoDelete(TRUE);
9739 QStrList &aliasList = Config_getList("ALIASES");
9740 const char *s=aliasList.first();
9743 if (Doxygen::aliasDict[s]==0)
9746 int i=alias.find('=');
9749 QCString name=alias.left(i).stripWhiteSpace();
9750 QCString value=alias.right(alias.length()-i-1);
9751 //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
9752 if (!name.isEmpty())
9754 QCString *dn=Doxygen::aliasDict[name];
9755 if (dn==0) // insert new alias
9757 Doxygen::aliasDict.insert(name,new QCString(value));
9759 else // overwrite previous alias
9772 //----------------------------------------------------------------------------
9774 static void dumpSymbol(FTextStream &t,Definition *d)
9777 if (d->definitionType()==Definition::TypeMember)
9779 MemberDef *md = (MemberDef *)d;
9780 anchor=":"+md->anchor();
9783 if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope)
9785 scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
9787 t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9788 << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9790 << d->name() << "','"
9791 << d->getDefFileName() << "','"
9796 static void dumpSymbolMap()
9798 QFile f("symbols.sql");
9799 if (f.open(IO_WriteOnly))
9802 QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9803 DefinitionIntf *intf;
9804 for (;(intf=di.current());++di)
9806 if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9808 DefinitionListIterator dli(*(DefinitionList*)intf);
9811 for (dli.toFirst();(d=dli.current());++dli)
9816 else // single symbol
9818 Definition *d = (Definition *)intf;
9819 if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9825 // print developer options of doxygen
9826 static void devUsage()
9828 msg("Developer parameters:\n");
9829 msg(" -m dump symbol map\n");
9830 msg(" -b output to wizard\n");
9831 msg(" -T activates output generation via Django like template\n");
9832 msg(" -d <level> enable a debug level, such as (multiple invocations of -d are possible):\n");
9833 Debug::printFlags();
9837 //----------------------------------------------------------------------------
9838 // print the usage of doxygen
9840 static void usage(const char *name)
9842 msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2014\n\n",versionString);
9843 msg("You can use doxygen in a number of ways:\n\n");
9844 msg("1) Use doxygen to generate a template configuration file:\n");
9845 msg(" %s [-s] -g [configName]\n\n",name);
9846 msg(" If - is used for configName doxygen will write to standard output.\n\n");
9847 msg("2) Use doxygen to update an old configuration file:\n");
9848 msg(" %s [-s] -u [configName]\n\n",name);
9849 msg("3) Use doxygen to generate documentation using an existing ");
9850 msg("configuration file:\n");
9851 msg(" %s [configName]\n\n",name);
9852 msg(" If - is used for configName doxygen will read from standard input.\n\n");
9853 msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9854 msg(" generated documentation:\n");
9855 msg(" %s -l layoutFileName.xml\n\n",name);
9856 msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9857 msg(" RTF: %s -w rtf styleSheetFile\n",name);
9858 msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9859 msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9860 msg("6) Use doxygen to generate a rtf extensions file\n");
9861 msg(" RTF: %s -e rtf extensionsFile\n\n",name);
9862 msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
9863 msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9864 msg("-v print version string\n");
9867 //----------------------------------------------------------------------------
9868 // read the argument of option `c' from the comment argument list and
9869 // update the option index `optind'.
9871 static const char *getArg(int argc,char **argv,int &optind)
9874 if (qstrlen(&argv[optind][2])>0)
9876 else if (optind+1<argc && argv[optind+1][0]!='-')
9881 //----------------------------------------------------------------------------
9885 const char *lang = portable_getenv("LC_ALL");
9886 if (lang) portable_setenv("LANG",lang);
9887 setlocale(LC_ALL,"");
9888 setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
9889 setlocale(LC_NUMERIC,"C");
9891 Doxygen::runningTime.start();
9894 Doxygen::parserManager = new ParserManager;
9895 Doxygen::parserManager->registerParser("c", new CLanguageScanner, TRUE);
9896 Doxygen::parserManager->registerParser("python", new PythonLanguageScanner);
9897 Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
9898 Doxygen::parserManager->registerParser("fortranfree", new FortranLanguageScannerFree);
9899 Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed);
9900 Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner);
9901 Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
9902 Doxygen::parserManager->registerParser("tcl", new TclLanguageScanner);
9903 Doxygen::parserManager->registerParser("md", new MarkdownFileParser);
9905 // register any additional parsers here...
9907 initDefaultExtensionMapping();
9908 initClassMemberIndices();
9909 initNamespaceMemberIndices();
9910 initFileMemberIndices();
9912 Doxygen::symbolMap = new QDict<DefinitionIntf>(50177);
9914 Doxygen::clangUsrMap = new QDict<Definition>(50177);
9916 Doxygen::inputNameList = new FileNameList;
9917 Doxygen::inputNameList->setAutoDelete(TRUE);
9918 Doxygen::memberNameSDict = new MemberNameSDict(10000);
9919 Doxygen::memberNameSDict->setAutoDelete(TRUE);
9920 Doxygen::functionNameSDict = new MemberNameSDict(10000);
9921 Doxygen::functionNameSDict->setAutoDelete(TRUE);
9922 Doxygen::groupSDict = new GroupSDict(17);
9923 Doxygen::groupSDict->setAutoDelete(TRUE);
9924 Doxygen::globalScope = new NamespaceDef("<globalScope>",1,1,"<globalScope>");
9925 Doxygen::namespaceSDict = new NamespaceSDict(20);
9926 Doxygen::namespaceSDict->setAutoDelete(TRUE);
9927 Doxygen::classSDict = new ClassSDict(1009);
9928 Doxygen::classSDict->setAutoDelete(TRUE);
9929 Doxygen::hiddenClasses = new ClassSDict(257);
9930 Doxygen::hiddenClasses->setAutoDelete(TRUE);
9931 Doxygen::directories = new DirSDict(17);
9932 Doxygen::directories->setAutoDelete(TRUE);
9933 Doxygen::pageSDict = new PageSDict(1009); // all doc pages
9934 Doxygen::pageSDict->setAutoDelete(TRUE);
9935 Doxygen::exampleSDict = new PageSDict(1009); // all examples
9936 Doxygen::exampleSDict->setAutoDelete(TRUE);
9937 Doxygen::inputNameDict = new FileNameDict(10007);
9938 Doxygen::includeNameDict = new FileNameDict(10007);
9939 Doxygen::exampleNameDict = new FileNameDict(1009);
9940 Doxygen::exampleNameDict->setAutoDelete(TRUE);
9941 Doxygen::imageNameDict = new FileNameDict(257);
9942 Doxygen::imageNameDict->setAutoDelete(TRUE);
9943 Doxygen::dotFileNameDict = new FileNameDict(257);
9944 Doxygen::mscFileNameDict = new FileNameDict(257);
9945 Doxygen::diaFileNameDict = new FileNameDict(257);
9946 Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
9947 Doxygen::tagDestinationDict.setAutoDelete(TRUE);
9948 Doxygen::dirRelations.setAutoDelete(TRUE);
9949 Doxygen::citeDict = new CiteDict(257);
9950 Doxygen::genericsDict = new GenericsSDict;
9951 Doxygen::indexList = new IndexList;
9952 Doxygen::formulaList = new FormulaList;
9953 Doxygen::formulaDict = new FormulaDict(1009);
9954 Doxygen::formulaNameDict = new FormulaDict(1009);
9955 Doxygen::sectionDict = new SectionDict(257);
9956 Doxygen::sectionDict->setAutoDelete(TRUE);
9958 /**************************************************************************
9959 * Initialize some global constants
9960 **************************************************************************/
9962 g_compoundKeywordDict.insert("template class",(void *)8);
9963 g_compoundKeywordDict.insert("template struct",(void *)8);
9964 g_compoundKeywordDict.insert("class",(void *)8);
9965 g_compoundKeywordDict.insert("struct",(void *)8);
9966 g_compoundKeywordDict.insert("union",(void *)8);
9967 g_compoundKeywordDict.insert("interface",(void *)8);
9968 g_compoundKeywordDict.insert("exception",(void *)8);
9972 void cleanUpDoxygen()
9974 delete Doxygen::sectionDict;
9975 delete Doxygen::formulaNameDict;
9976 delete Doxygen::formulaDict;
9977 delete Doxygen::formulaList;
9978 delete Doxygen::indexList;
9979 delete Doxygen::genericsDict;
9980 delete Doxygen::inputNameDict;
9981 delete Doxygen::includeNameDict;
9982 delete Doxygen::exampleNameDict;
9983 delete Doxygen::imageNameDict;
9984 delete Doxygen::dotFileNameDict;
9985 delete Doxygen::mscFileNameDict;
9986 delete Doxygen::diaFileNameDict;
9987 delete Doxygen::mainPage;
9988 delete Doxygen::pageSDict;
9989 delete Doxygen::exampleSDict;
9990 delete Doxygen::globalScope;
9991 delete Doxygen::xrefLists;
9992 delete Doxygen::parserManager;
9993 cleanUpPreprocessor();
9994 delete theTranslator;
9995 delete g_outputList;
9996 Mappers::freeMappers();
9999 if (Doxygen::symbolMap)
10001 // iterate through Doxygen::symbolMap and delete all
10002 // DefinitionList objects, since they have no owner
10003 QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
10004 DefinitionIntf *di;
10005 for (dli.toFirst();(di=dli.current());)
10007 if (di->definitionType()==DefinitionIntf::TypeSymbolList)
10009 DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
10010 delete (DefinitionList *)tmp;
10019 delete Doxygen::inputNameList;
10020 delete Doxygen::memberNameSDict;
10021 delete Doxygen::functionNameSDict;
10022 delete Doxygen::groupSDict;
10023 delete Doxygen::classSDict;
10024 delete Doxygen::hiddenClasses;
10025 delete Doxygen::namespaceSDict;
10026 delete Doxygen::directories;
10028 //delete Doxygen::symbolMap; <- we cannot do this unless all static lists
10029 // (such as Doxygen::namespaceSDict)
10030 // with objects based on Definition are made
10034 static int computeIdealCacheParam(uint v)
10036 //printf("computeIdealCacheParam(v=%u)\n",v);
10039 while (v!=0) v>>=1,r++;
10042 // convert to a valid cache size value
10043 return QMAX(0,QMIN(r-16,9));
10046 void readConfiguration(int argc, char **argv)
10048 /**************************************************************************
10049 * Handle arguments *
10050 **************************************************************************/
10053 const char *configName=0;
10054 const char *layoutName=0;
10055 const char *debugLabel;
10056 const char *formatName;
10057 bool genConfig=FALSE;
10058 bool shortList=FALSE;
10059 bool updateConfig=FALSE;
10060 bool genLayout=FALSE;
10062 while (optind<argc && argv[optind][0]=='-' &&
10063 (isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
10064 argv[optind][1]=='-')
10067 switch(argv[optind][1])
10071 configName=getArg(argc,argv,optind);
10072 if (optind+1<argc && qstrcmp(argv[optind+1],"-")==0)
10073 { configName="-"; optind++; }
10075 { configName="Doxyfile"; }
10079 layoutName=getArg(argc,argv,optind);
10081 { layoutName="DoxygenLayout.xml"; }
10084 debugLabel=getArg(argc,argv,optind);
10087 err("option \"-d\" is missing debug specifier.\n");
10092 retVal = Debug::setFlag(debugLabel);
10095 err("option \"-d\" has unknown debug specifier: \"%s\".\n",debugLabel);
10107 formatName=getArg(argc,argv,optind);
10110 err("option \"-e\" is missing format specifier rtf.\n");
10114 if (qstricmp(formatName,"rtf")==0)
10116 if (optind+1>=argc)
10118 err("option \"-e rtf\" is missing an extensions file name\n");
10123 if (openOutputFile(argv[optind+1],f))
10125 RTFGenerator::writeExtensionsFile(f);
10130 err("option \"-e\" has invalid format specifier.\n");
10135 formatName=getArg(argc,argv,optind);
10138 err("option \"-w\" is missing format specifier rtf, html or latex\n");
10142 if (qstricmp(formatName,"rtf")==0)
10144 if (optind+1>=argc)
10146 err("option \"-w rtf\" is missing a style sheet file name\n");
10151 if (openOutputFile(argv[optind+1],f))
10153 RTFGenerator::writeStyleSheetFile(f);
10158 else if (qstricmp(formatName,"html")==0)
10160 if (optind+4<argc || QFileInfo("Doxyfile").exists())
10162 QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10163 if (!Config::instance()->parse(df))
10165 err("error opening or reading configuration file %s!\n",argv[optind+4]);
10169 Config::instance()->substituteEnvironmentVars();
10170 Config::instance()->convertStrToVal();
10171 // avoid bootstrapping issues when the config file already
10172 // refers to the files that we are supposed to parse.
10173 Config_getString("HTML_HEADER")="";
10174 Config_getString("HTML_FOOTER")="";
10175 Config::instance()->check();
10179 Config::instance()->init();
10181 if (optind+3>=argc)
10183 err("option \"-w html\" does not have enough arguments\n");
10188 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10189 if (!setTranslator(outputLanguage))
10191 warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10195 if (openOutputFile(argv[optind+1],f))
10197 HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
10200 if (openOutputFile(argv[optind+2],f))
10202 HtmlGenerator::writeFooterFile(f);
10205 if (openOutputFile(argv[optind+3],f))
10207 HtmlGenerator::writeStyleSheetFile(f);
10212 else if (qstricmp(formatName,"latex")==0)
10214 if (optind+4<argc) // use config file to get settings
10216 if (!Config::instance()->parse(argv[optind+4]))
10218 err("error opening or reading configuration file %s!\n",argv[optind+4]);
10221 Config::instance()->substituteEnvironmentVars();
10222 Config::instance()->convertStrToVal();
10223 Config_getString("LATEX_HEADER")="";
10224 Config::instance()->check();
10226 else // use default config
10228 Config::instance()->init();
10230 if (optind+3>=argc)
10232 err("option \"-w latex\" does not have enough arguments\n");
10237 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10238 if (!setTranslator(outputLanguage))
10240 warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10244 if (openOutputFile(argv[optind+1],f))
10246 LatexGenerator::writeHeaderFile(f);
10249 if (openOutputFile(argv[optind+2],f))
10251 LatexGenerator::writeFooterFile(f);
10254 if (openOutputFile(argv[optind+3],f))
10256 LatexGenerator::writeStyleSheetFile(f);
10263 err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",formatName);
10269 g_dumpSymbolMap = TRUE;
10272 msg("%s\n",versionString);
10277 if (qstrcmp(&argv[optind][2],"help")==0)
10282 else if (qstrcmp(&argv[optind][2],"version")==0)
10284 msg("%s\n",versionString);
10290 err("Unknown option \"-%s\"\n",&argv[optind][1]);
10296 setvbuf(stdout,NULL,_IONBF,0);
10297 Doxygen::outputToWizard=TRUE;
10300 msg("Warning: this option activates output generation via Django like template files. "
10301 "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
10302 "Only use if you are a doxygen developer\n");
10303 g_useOutputTemplate=TRUE;
10311 err("Unknown option \"-%c\"\n",argv[optind][1]);
10318 /**************************************************************************
10319 * Parse or generate the config file *
10320 **************************************************************************/
10322 Config::instance()->init();
10326 generateConfigFile(configName,shortList);
10332 writeDefaultLayoutFile(layoutName);
10337 QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
10340 if (configFileInfo1.exists())
10342 configName="Doxyfile";
10344 else if (configFileInfo2.exists())
10346 configName="doxyfile";
10350 err("Doxyfile not found and no input file specified!\n");
10357 QFileInfo fi(argv[optind]);
10358 if (fi.exists() || qstrcmp(argv[optind],"-")==0)
10360 configName=argv[optind];
10364 err("configuration file %s not found!\n",argv[optind]);
10371 if (!Config::instance()->parse(configName,updateConfig))
10373 err("could not open or read configuration file %s!\n",configName);
10380 generateConfigFile(configName,shortList,TRUE);
10385 /* Perlmod wants to know the path to the config file.*/
10386 QFileInfo configFileInfo(configName);
10387 setPerlModDoxyfile(configFileInfo.absFilePath().data());
10391 /** check and resolve config options */
10392 void checkConfiguration()
10395 Config::instance()->substituteEnvironmentVars();
10396 Config::instance()->convertStrToVal();
10397 Config::instance()->check();
10399 initWarningFormat();
10402 /** adjust globals that depend on configuration settings. */
10403 void adjustConfiguration()
10405 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
10406 if (!setTranslator(outputLanguage))
10408 warn_uncond("Output language %s not supported! Using English instead.\n",
10409 outputLanguage.data());
10411 QStrList &includePath = Config_getList("INCLUDE_PATH");
10412 char *s=includePath.first();
10416 addSearchDir(fi.absFilePath().utf8());
10417 s=includePath.next();
10420 /* Set the global html file extension. */
10421 Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
10424 Doxygen::xrefLists->setAutoDelete(TRUE);
10426 Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") ||
10427 Config_getBool("CALLER_GRAPH") ||
10428 Config_getBool("REFERENCES_RELATION") ||
10429 Config_getBool("REFERENCED_BY_RELATION");
10431 Doxygen::markdownSupport = Config_getBool("MARKDOWN_SUPPORT");
10433 /**************************************************************************
10434 * Add custom extension mappings
10435 **************************************************************************/
10437 QStrList &extMaps = Config_getList("EXTENSION_MAPPING");
10438 char *mapping = extMaps.first();
10441 QCString mapStr = mapping;
10443 if ((i=mapStr.find('='))!=-1)
10445 QCString ext=mapStr.left(i).stripWhiteSpace().lower();
10446 QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
10447 if (!updateLanguageMapping(ext,language))
10449 err("Failed to map file extension '%s' to unsupported language '%s'.\n"
10450 "Check the EXTENSION_MAPPING setting in the config file.\n",
10451 ext.data(),language.data());
10455 msg("Adding custom extension mapping: .%s will be treated as language %s\n",
10456 ext.data(),language.data());
10459 mapping = extMaps.next();
10463 // add predefined macro name to a dictionary
10464 QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
10465 s=expandAsDefinedList.first();
10468 if (Doxygen::expandAsDefinedDict[s]==0)
10470 Doxygen::expandAsDefinedDict.insert(s,(void *)666);
10472 s=expandAsDefinedList.next();
10475 // read aliases and store them in a dictionary
10478 // store number of spaces in a tab into Doxygen::spaces
10479 int &tabSize = Config_getInt("TAB_SIZE");
10480 Doxygen::spaces.resize(tabSize+1);
10481 int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
10482 Doxygen::spaces.at(tabSize)='\0';
10486 static void stopDoxygen(int)
10489 msg("Cleaning up...\n");
10490 if (!Doxygen::entryDBFileName.isEmpty())
10492 thisDir.remove(Doxygen::entryDBFileName);
10494 if (!Doxygen::objDBFileName.isEmpty())
10496 thisDir.remove(Doxygen::objDBFileName);
10503 static void exitDoxygen()
10505 if (!g_successfulRun) // premature exit
10508 msg("Exiting...\n");
10509 if (!Doxygen::entryDBFileName.isEmpty())
10511 thisDir.remove(Doxygen::entryDBFileName);
10513 if (!Doxygen::objDBFileName.isEmpty())
10515 thisDir.remove(Doxygen::objDBFileName);
10520 static QCString createOutputDirectory(const QCString &baseDirName,
10521 const char *formatDirOption,
10522 const char *defaultDirName)
10524 // Note the & on the next line, we modify the formatDirOption!
10525 QCString &formatDirName = Config_getString(formatDirOption);
10526 if (formatDirName.isEmpty())
10528 formatDirName = baseDirName + defaultDirName;
10530 else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
10532 formatDirName.prepend(baseDirName+'/');
10534 QDir formatDir(formatDirName);
10535 if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
10537 err("Could not create output directory %s\n", formatDirName.data());
10541 return formatDirName;
10544 static QCString getQchFileName()
10546 QCString const & qchFile = Config_getString("QCH_FILE");
10547 if (!qchFile.isEmpty())
10552 QCString const & projectName = Config_getString("PROJECT_NAME");
10553 QCString const & versionText = Config_getString("PROJECT_NUMBER");
10555 return QCString("../qch/")
10556 + (projectName.isEmpty() ? QCString("index") : projectName)
10557 + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
10558 + QCString(".qch");
10561 void searchInputFiles()
10563 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10564 bool alwaysRecursive = Config_getBool("RECURSIVE");
10565 StringDict excludeNameDict(1009);
10566 excludeNameDict.setAutoDelete(TRUE);
10568 // gather names of all files in the include path
10569 g_s.begin("Searching for include files...\n");
10570 QStrList &includePathList = Config_getList("INCLUDE_PATH");
10571 char *s=includePathList.first();
10574 QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
10577 pl = Config_getList("FILE_PATTERNS");
10579 readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
10582 s=includePathList.next();
10586 g_s.begin("Searching for example files...\n");
10587 QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
10588 s=examplePathList.first();
10591 readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
10592 &Config_getList("EXAMPLE_PATTERNS"),
10594 (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
10595 s=examplePathList.next();
10599 g_s.begin("Searching for images...\n");
10600 QStrList &imagePathList=Config_getList("IMAGE_PATH");
10601 s=imagePathList.first();
10604 readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
10607 s=imagePathList.next();
10611 g_s.begin("Searching for dot files...\n");
10612 QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
10613 s=dotFileList.first();
10616 readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
10619 s=dotFileList.next();
10623 g_s.begin("Searching for msc files...\n");
10624 QStrList &mscFileList=Config_getList("MSCFILE_DIRS");
10625 s=mscFileList.first();
10628 readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
10631 s=mscFileList.next();
10635 g_s.begin("Searching for dia files...\n");
10636 QStrList &diaFileList=Config_getList("DIAFILE_DIRS");
10637 s=diaFileList.first();
10640 readFileOrDirectory(s,0,Doxygen::diaFileNameDict,0,0,
10643 s=diaFileList.next();
10647 g_s.begin("Searching for files to exclude\n");
10648 QStrList &excludeList = Config_getList("EXCLUDE");
10649 s=excludeList.first();
10652 readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
10653 0,0,&excludeNameDict,
10656 s=excludeList.next();
10660 /**************************************************************************
10661 * Determine Input Files *
10662 **************************************************************************/
10664 g_s.begin("Searching for files to process...\n");
10665 QDict<void> *killDict = new QDict<void>(10007);
10667 QStrList &inputList=Config_getList("INPUT");
10668 g_inputFiles.setAutoDelete(TRUE);
10669 s=inputList.first();
10673 uint l = path.length();
10676 // strip trailing slashes
10677 if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
10679 inputSize+=readFileOrDirectory(
10681 Doxygen::inputNameList,
10682 Doxygen::inputNameDict,
10684 &Config_getList("FILE_PATTERNS"),
10690 &Doxygen::inputPaths);
10692 s=inputList.next();
10701 atexit(exitDoxygen);
10704 /**************************************************************************
10705 * Make sure the output directory exists
10706 **************************************************************************/
10707 QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
10708 if (outputDirectory.isEmpty())
10710 outputDirectory=QDir::currentDirPath().utf8();
10714 QDir dir(outputDirectory);
10717 dir.setPath(QDir::currentDirPath());
10718 if (!dir.mkdir(outputDirectory))
10720 err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
10721 "exist and cannot be created\n",outputDirectory.data());
10727 msg("Notice: Output directory `%s' does not exist. "
10728 "I have created it for you.\n", outputDirectory.data());
10730 dir.cd(outputDirectory);
10732 outputDirectory=dir.absPath().utf8();
10735 /**************************************************************************
10736 * Initialize global lists and dictionaries
10737 **************************************************************************/
10739 Doxygen::symbolStorage = new Store;
10741 // also scale lookup cache with SYMBOL_CACHE_SIZE
10742 int cacheSize = Config_getInt("LOOKUP_CACHE_SIZE");
10743 if (cacheSize<0) cacheSize=0;
10744 if (cacheSize>9) cacheSize=9;
10745 uint lookupSize = 65536 << cacheSize;
10746 Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
10747 Doxygen::lookupCache->setAutoDelete(TRUE);
10750 signal(SIGINT, stopDoxygen);
10753 uint pid = portable_pid();
10754 Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10755 Doxygen::objDBFileName.prepend(outputDirectory+"/");
10756 Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10757 Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10759 if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10761 err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10767 /**************************************************************************
10768 * Check/create output directorties *
10769 **************************************************************************/
10771 QCString htmlOutput;
10772 bool &generateHtml = Config_getBool("GENERATE_HTML");
10774 htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");
10776 QCString docbookOutput;
10777 bool &generateDocbook = Config_getBool("GENERATE_DOCBOOK");
10778 if (generateDocbook)
10779 docbookOutput = createOutputDirectory(outputDirectory,"DOCBOOK_OUTPUT","/docbook");
10781 QCString xmlOutput;
10782 bool &generateXml = Config_getBool("GENERATE_XML");
10784 xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");
10786 QCString latexOutput;
10787 bool &generateLatex = Config_getBool("GENERATE_LATEX");
10789 latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");
10791 QCString rtfOutput;
10792 bool &generateRtf = Config_getBool("GENERATE_RTF");
10794 rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");
10796 QCString manOutput;
10797 bool &generateMan = Config_getBool("GENERATE_MAN");
10799 manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");
10801 //QCString sqlOutput;
10802 //bool &generateSql = Config_getBool("GENERATE_SQLITE3");
10804 // sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3");
10806 if (Config_getBool("HAVE_DOT"))
10808 QCString curFontPath = Config_getString("DOT_FONTPATH");
10809 if (curFontPath.isEmpty())
10811 portable_getenv("DOTFONTPATH");
10812 QCString newFontPath = ".";
10813 if (!curFontPath.isEmpty())
10815 newFontPath+=portable_pathListSeparator();
10816 newFontPath+=curFontPath;
10818 portable_setenv("DOTFONTPATH",newFontPath);
10822 portable_setenv("DOTFONTPATH",curFontPath);
10828 /**************************************************************************
10829 * Handle layout file *
10830 **************************************************************************/
10832 LayoutDocManager::instance().init();
10833 QCString &layoutFileName = Config_getString("LAYOUT_FILE");
10834 bool defaultLayoutUsed = FALSE;
10835 if (layoutFileName.isEmpty())
10837 layoutFileName = "DoxygenLayout.xml";
10838 defaultLayoutUsed = TRUE;
10841 QFile layoutFile(layoutFileName);
10842 if (layoutFile.open(IO_ReadOnly))
10844 msg("Parsing layout file %s...\n",layoutFileName.data());
10845 QTextStream t(&layoutFile);
10846 t.setEncoding(QTextStream::Latin1);
10847 LayoutDocManager::instance().parse(t,layoutFileName);
10849 else if (!defaultLayoutUsed)
10851 warn_uncond("failed to open layout file '%s' for reading!\n",layoutFileName.data());
10854 /**************************************************************************
10855 * Read and preprocess input *
10856 **************************************************************************/
10858 // prevent search in the output directories
10859 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10860 if (generateHtml) exclPatterns.append(htmlOutput);
10861 if (generateDocbook) exclPatterns.append(docbookOutput);
10862 if (generateXml) exclPatterns.append(xmlOutput);
10863 if (generateLatex) exclPatterns.append(latexOutput);
10864 if (generateRtf) exclPatterns.append(rtfOutput);
10865 if (generateMan) exclPatterns.append(manOutput);
10867 searchInputFiles();
10869 // Notice: the order of the function calls below is very important!
10871 if (Config_getBool("GENERATE_HTML"))
10873 readFormulaRepository();
10876 /**************************************************************************
10877 * Handle Tag Files *
10878 **************************************************************************/
10880 g_storage = new FileStorage;
10881 g_storage->setName(Doxygen::entryDBFileName);
10882 if (!g_storage->open(IO_WriteOnly))
10884 err("Failed to create temporary storage file %s\n",
10885 Doxygen::entryDBFileName.data());
10888 Entry *root=new Entry;
10889 EntryNav *rootNav = new EntryNav(0,root);
10890 rootNav->setEntry(root);
10891 msg("Reading and parsing tag files\n");
10893 QStrList &tagFileList = Config_getList("TAGFILES");
10894 char *s=tagFileList.first();
10897 readTagFile(root,s);
10898 root->createNavigationIndex(rootNav,g_storage,0);
10899 s=tagFileList.next();
10902 /**************************************************************************
10903 * Parse source files *
10904 **************************************************************************/
10906 if (Config_getBool("BUILTIN_STL_SUPPORT"))
10908 addSTLClasses(rootNav);
10911 g_s.begin("Parsing files\n");
10912 parseFiles(root,rootNav);
10913 g_storage->close();
10916 // we are done with input scanning now, so free up the buffers used by flex
10917 // (can be around 4MB)
10920 pyscanFreeScanner();
10922 if (!g_storage->open(IO_ReadOnly))
10924 err("Failed to open temporary storage file %s for reading",
10925 Doxygen::entryDBFileName.data());
10929 /**************************************************************************
10930 * Gather information *
10931 **************************************************************************/
10933 g_s.begin("Building group list...\n");
10934 buildGroupList(rootNav);
10935 organizeSubGroups(rootNav);
10938 g_s.begin("Building directory list...\n");
10939 buildDirectories();
10940 findDirDocumentation(rootNav);
10943 g_s.begin("Building namespace list...\n");
10944 buildNamespaceList(rootNav);
10945 findUsingDirectives(rootNav);
10948 g_s.begin("Building file list...\n");
10949 buildFileList(rootNav);
10951 //generateFileTree();
10953 g_s.begin("Building class list...\n");
10954 buildClassList(rootNav);
10957 g_s.begin("Associating documentation with classes...\n");
10958 buildClassDocList(rootNav);
10960 // build list of using declarations here (global list)
10961 buildListOfUsingDecls(rootNav);
10964 g_s.begin("Computing nesting relations for classes...\n");
10965 resolveClassNestingRelations();
10967 // 1.8.2-20121111: no longer add nested classes to the group as well
10968 //distributeClassGroupRelations();
10970 // calling buildClassList may result in cached relations that
10971 // become invalid after resolveClassNestingRelations(), that's why
10972 // we need to clear the cache here
10973 Doxygen::lookupCache->clear();
10974 // we don't need the list of using declaration anymore
10975 g_usingDeclarations.clear();
10977 g_s.begin("Building example list...\n");
10978 buildExampleList(rootNav);
10981 g_s.begin("Searching for enumerations...\n");
10982 findEnums(rootNav);
10985 // Since buildVarList calls isVarWithConstructor
10986 // and this calls getResolvedClass we need to process
10987 // typedefs first so the relations between classes via typedefs
10988 // are properly resolved. See bug 536385 for an example.
10989 g_s.begin("Searching for documented typedefs...\n");
10990 buildTypedefList(rootNav);
10993 g_s.begin("Searching for members imported via using declarations...\n");
10994 findUsingDeclImports(rootNav);
10995 // this should be after buildTypedefList in order to properly import
10997 findUsingDeclarations(rootNav);
11000 g_s.begin("Searching for included using directives...\n");
11001 findIncludedUsingDirectives();
11004 g_s.begin("Searching for documented variables...\n");
11005 buildVarList(rootNav);
11008 g_s.begin("Building interface member list...\n");
11009 buildInterfaceAndServiceList(rootNav); // UNO IDL
11011 g_s.begin("Building member list...\n"); // using class info only !
11012 buildFunctionList(rootNav);
11015 g_s.begin("Searching for friends...\n");
11019 g_s.begin("Searching for documented defines...\n");
11020 findDefineDocumentation(rootNav);
11023 g_s.begin("Computing class inheritance relations...\n");
11024 findClassEntries(rootNav);
11025 findInheritedTemplateInstances();
11028 g_s.begin("Computing class usage relations...\n");
11029 findUsedTemplateInstances();
11032 if (Config_getBool("INLINE_SIMPLE_STRUCTS"))
11034 g_s.begin("Searching for tag less structs...\n");
11035 findTagLessClasses();
11039 g_s.begin("Flushing cached template relations that have become invalid...\n");
11040 flushCachedTemplateRelations();
11043 g_s.begin("Creating members for template instances...\n");
11044 createTemplateInstanceMembers();
11047 g_s.begin("Computing class relations...\n");
11048 computeTemplateClassRelations();
11049 flushUnresolvedRelations();
11050 if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
11052 VhdlDocGen::computeVhdlComponentRelations();
11054 computeClassRelations();
11055 g_classEntries.clear();
11058 g_s.begin("Add enum values to enums...\n");
11059 addEnumValuesToEnums(rootNav);
11060 findEnumDocumentation(rootNav);
11063 g_s.begin("Searching for member function documentation...\n");
11064 findObjCMethodDefinitions(rootNav);
11065 findMemberDocumentation(rootNav); // may introduce new members !
11067 transferRelatedFunctionDocumentation();
11068 transferFunctionDocumentation();
11071 g_s.begin("Building page list...\n");
11072 buildPageList(rootNav);
11075 g_s.begin("Search for main page...\n");
11076 findMainPage(rootNav);
11079 g_s.begin("Computing page relations...\n");
11080 computePageRelations(rootNav);
11081 checkPageRelations();
11084 g_s.begin("Determining the scope of groups...\n");
11085 findGroupScope(rootNav);
11088 g_s.begin("Sorting lists...\n");
11089 Doxygen::memberNameSDict->sort();
11090 Doxygen::functionNameSDict->sort();
11091 Doxygen::hiddenClasses->sort();
11092 Doxygen::classSDict->sort();
11095 msg("Freeing entry tree\n");
11097 g_storage->close();
11102 thisDir.remove(Doxygen::entryDBFileName);
11104 g_s.begin("Determining which enums are documented\n");
11105 findDocumentedEnumValues();
11108 g_s.begin("Computing member relations...\n");
11110 computeMemberRelations();
11113 g_s.begin("Building full member lists recursively...\n");
11114 buildCompleteMemberLists();
11117 g_s.begin("Adding members to member groups.\n");
11118 addMembersToMemberGroup();
11121 if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
11123 g_s.begin("Distributing member group documentation.\n");
11124 distributeMemberGroupDocumentation();
11128 g_s.begin("Computing member references...\n");
11129 computeMemberReferences();
11132 if (Config_getBool("INHERIT_DOCS"))
11134 g_s.begin("Inheriting documentation...\n");
11135 inheritDocumentation();
11139 // compute the shortest possible names of all files
11140 // without losing the uniqueness of the file names.
11141 g_s.begin("Generating disk names...\n");
11142 Doxygen::inputNameList->generateDiskNames();
11145 g_s.begin("Adding source references...\n");
11146 addSourceReferences();
11149 g_s.begin("Adding xrefitems...\n");
11150 addListReferences();
11151 generateXRefPages();
11154 g_s.begin("Sorting member lists...\n");
11158 if (Config_getBool("DIRECTORY_GRAPH"))
11160 g_s.begin("Computing dependencies between directories...\n");
11161 computeDirDependencies();
11165 //g_s.begin("Resolving citations...\n");
11166 //Doxygen::citeDict->resolve();
11168 g_s.begin("Generating citations page...\n");
11169 Doxygen::citeDict->generatePage();
11172 g_s.begin("Counting data structures...\n");
11173 countDataStructures();
11176 g_s.begin("Resolving user defined references...\n");
11177 resolveUserReferences();
11180 g_s.begin("Finding anchors and sections in the documentation...\n");
11181 findSectionsInDocumentation();
11184 g_s.begin("Transferring function references...\n");
11185 transferFunctionReferences();
11188 g_s.begin("Combining using relations...\n");
11189 combineUsingRelations();
11192 g_s.begin("Adding members to index pages...\n");
11193 addMembersToIndex();
11196 if (Config_getBool("OPTIMIZE_OUTPUT_VHDL") &&
11197 Config_getBool("HAVE_DOT") &&
11198 Config_getEnum("DOT_IMAGE_FORMAT")=="svg")
11200 VhdlDocGen::writeOverview();
11204 void generateOutput()
11206 /**************************************************************************
11207 * Initialize output generators *
11208 **************************************************************************/
11210 //// dump all symbols
11211 if (g_dumpSymbolMap)
11217 initSearchIndexer();
11219 bool generateHtml = Config_getBool("GENERATE_HTML");
11220 bool generateLatex = Config_getBool("GENERATE_LATEX");
11221 bool generateMan = Config_getBool("GENERATE_MAN");
11222 bool generateRtf = Config_getBool("GENERATE_RTF");
11225 g_outputList = new OutputList(TRUE);
11228 g_outputList->add(new HtmlGenerator);
11229 HtmlGenerator::init();
11231 // add HTML indexers that are enabled
11232 bool generateHtmlHelp = Config_getBool("GENERATE_HTMLHELP");
11233 bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");
11234 bool generateQhp = Config_getBool("GENERATE_QHP");
11235 bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
11236 bool generateDocSet = Config_getBool("GENERATE_DOCSET");
11237 if (generateEclipseHelp) Doxygen::indexList->addIndex(new EclipseHelp);
11238 if (generateHtmlHelp) Doxygen::indexList->addIndex(new HtmlHelp);
11239 if (generateQhp) Doxygen::indexList->addIndex(new Qhp);
11240 if (generateTreeView) Doxygen::indexList->addIndex(new FTVHelp(TRUE));
11241 if (generateDocSet) Doxygen::indexList->addIndex(new DocSets);
11242 Doxygen::indexList->initialize();
11243 HtmlGenerator::writeTabData();
11245 // copy static stuff
11248 copyExtraFiles("HTML_EXTRA_FILES","HTML_OUTPUT");
11249 FTVHelp::generateTreeViewImages();
11253 g_outputList->add(new LatexGenerator);
11254 LatexGenerator::init();
11256 // copy static stuff
11257 copyExtraFiles("LATEX_EXTRA_FILES","LATEX_OUTPUT");
11261 g_outputList->add(new ManGenerator);
11262 ManGenerator::init();
11266 g_outputList->add(new RTFGenerator);
11267 RTFGenerator::init();
11269 if (Config_getBool("USE_HTAGS"))
11271 Htags::useHtags = TRUE;
11272 QCString htmldir = Config_getString("HTML_OUTPUT");
11273 if (!Htags::execute(htmldir))
11274 err("USE_HTAGS is YES but htags(1) failed. \n");
11275 if (!Htags::loadFilemap(htmldir))
11276 err("htags(1) ended normally but failed to load the filemap. \n");
11279 /**************************************************************************
11280 * Generate documentation *
11281 **************************************************************************/
11284 QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
11285 if (!generateTagFile.isEmpty())
11287 tag=new QFile(generateTagFile);
11288 if (!tag->open(IO_WriteOnly))
11290 err("cannot open tag file %s for writing\n",
11291 generateTagFile.data()
11296 Doxygen::tagFile.setDevice(tag);
11297 Doxygen::tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
11298 Doxygen::tagFile << "<tagfile>" << endl;
11301 if (generateHtml) writeDoxFont(Config_getString("HTML_OUTPUT"));
11302 if (generateLatex) writeDoxFont(Config_getString("LATEX_OUTPUT"));
11303 if (generateRtf) writeDoxFont(Config_getString("RTF_OUTPUT"));
11305 g_s.begin("Generating style sheet...\n");
11306 //printf("writing style info\n");
11307 g_outputList->writeStyleInfo(0); // write first part
11310 static bool searchEngine = Config_getBool("SEARCHENGINE");
11311 static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
11313 // generate search indices (need to do this before writing other HTML
11314 // pages as these contain a drop down menu with options depending on
11315 // what categories we find in this function.
11316 if (generateHtml && searchEngine)
11318 g_s.begin("Generating search indices...\n");
11319 QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
11320 QDir searchDir(searchDirName);
11321 if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
11323 err("Could not create search results directory '%s' $PWD='%s'\n",
11324 searchDirName.data(),QDir::currentDirPath().data());
11327 HtmlGenerator::writeSearchData(searchDirName);
11328 if (!serverBasedSearch) // client side search index
11330 writeJavascriptSearchIndex();
11335 g_s.begin("Generating example documentation...\n");
11336 generateExampleDocs();
11339 if (!Htags::useHtags)
11341 g_s.begin("Generating file sources...\n");
11342 generateFileSources();
11346 g_s.begin("Generating file documentation...\n");
11347 generateFileDocs();
11350 g_s.begin("Generating page documentation...\n");
11351 generatePageDocs();
11354 g_s.begin("Generating group documentation...\n");
11355 generateGroupDocs();
11358 g_s.begin("Generating class documentation...\n");
11359 generateClassDocs();
11362 g_s.begin("Generating namespace index...\n");
11363 generateNamespaceDocs();
11366 if (Config_getBool("GENERATE_LEGEND"))
11368 g_s.begin("Generating graph info page...\n");
11369 writeGraphInfo(*g_outputList);
11373 g_s.begin("Generating directory documentation...\n");
11374 generateDirDocs(*g_outputList);
11377 if (Doxygen::formulaList->count()>0 && generateHtml
11378 && !Config_getBool("USE_MATHJAX"))
11380 g_s.begin("Generating bitmaps for formulas in HTML...\n");
11381 Doxygen::formulaList->generateBitmaps(Config_getString("HTML_OUTPUT"));
11385 if (Config_getBool("SORT_GROUP_NAMES"))
11387 Doxygen::groupSDict->sort();
11388 GroupSDict::Iterator gli(*Doxygen::groupSDict);
11390 for (gli.toFirst();(gd=gli.current());++gli)
11392 gd->sortSubGroups();
11396 writeMainPageTagFileData();
11398 if (g_outputList->count()>0)
11400 writeIndexHierarchy(*g_outputList);
11403 g_s.begin("finalizing index lists...\n");
11404 Doxygen::indexList->finalize();
11407 if (!generateTagFile.isEmpty())
11409 Doxygen::tagFile << "</tagfile>" << endl;
11413 if (Config_getBool("DOT_CLEANUP"))
11416 removeDoxFont(Config_getString("HTML_OUTPUT"));
11418 removeDoxFont(Config_getString("RTF_OUTPUT"));
11420 removeDoxFont(Config_getString("LATEX_OUTPUT"));
11423 if (Config_getBool("GENERATE_XML"))
11425 g_s.begin("Generating XML output...\n");
11426 Doxygen::generatingXmlOutput=TRUE;
11428 Doxygen::generatingXmlOutput=FALSE;
11433 g_s.begin("Generating SQLITE3 output...\n");
11438 if (Config_getBool("GENERATE_DOCBOOK"))
11440 g_s.begin("Generating Docbook output...\n");
11445 if (Config_getBool("GENERATE_AUTOGEN_DEF"))
11447 g_s.begin("Generating AutoGen DEF output...\n");
11451 if (Config_getBool("GENERATE_PERLMOD"))
11453 g_s.begin("Generating Perl module output...\n");
11457 if (generateHtml && searchEngine && serverBasedSearch)
11459 g_s.begin("Generating search index\n");
11460 if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
11462 HtmlGenerator::writeSearchPage();
11463 Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");
11465 else // write data for external search index
11467 HtmlGenerator::writeExternalSearchPage();
11468 QCString searchDataFile = Config_getString("SEARCHDATA_FILE");
11469 if (searchDataFile.isEmpty())
11471 searchDataFile="searchdata.xml";
11473 if (!portable_isAbsolutePath(searchDataFile))
11475 searchDataFile.prepend(Config_getString("OUTPUT_DIRECTORY")+"/");
11477 Doxygen::searchIndex->write(searchDataFile);
11482 if (g_useOutputTemplate) generateOutputViaTemplate();
11486 g_s.begin("Combining RTF output...\n");
11487 if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
11489 err("An error occurred during post-processing the RTF files!\n");
11494 if (Config_getBool("HAVE_DOT"))
11496 g_s.begin("Running dot...\n");
11497 DotManager::instance()->run();
11501 if (generateHtml &&
11502 Config_getBool("GENERATE_HTMLHELP") &&
11503 !Config_getString("HHC_LOCATION").isEmpty())
11505 g_s.begin("Running html help compiler...\n");
11506 QString oldDir = QDir::currentDirPath();
11507 QDir::setCurrent(Config_getString("HTML_OUTPUT"));
11508 portable_sysTimerStart();
11509 if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
11511 err("failed to run html help compiler on index.hhp\n");
11513 portable_sysTimerStop();
11514 QDir::setCurrent(oldDir);
11517 if ( generateHtml &&
11518 Config_getBool("GENERATE_QHP") &&
11519 !Config_getString("QHG_LOCATION").isEmpty())
11521 g_s.begin("Running qhelpgenerator...\n");
11522 QCString const qhpFileName = Qhp::getQhpFileName();
11523 QCString const qchFileName = getQchFileName();
11525 QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
11526 QString const oldDir = QDir::currentDirPath();
11527 QDir::setCurrent(Config_getString("HTML_OUTPUT"));
11528 portable_sysTimerStart();
11529 if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))
11531 err("failed to run qhelpgenerator on index.qhp\n");
11533 portable_sysTimerStop();
11534 QDir::setCurrent(oldDir);
11539 msg("lookup cache used %d/%d hits=%d misses=%d\n",
11540 Doxygen::lookupCache->count(),
11541 Doxygen::lookupCache->size(),
11542 Doxygen::lookupCache->hits(),
11543 Doxygen::lookupCache->misses());
11544 cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
11545 if (cacheParam>Config_getInt("LOOKUP_CACHE_SIZE"))
11547 msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
11550 if (Debug::isFlagSet(Debug::Time))
11552 msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
11553 ((double)Doxygen::runningTime.elapsed())/1000.0,
11554 portable_getSysElapsedTime()
11560 msg("finished...\n");
11564 /**************************************************************************
11565 * Start cleaning up *
11566 **************************************************************************/
11570 finializeSearchIndexer();
11571 Doxygen::symbolStorage->close();
11573 thisDir.remove(Doxygen::objDBFileName);
11574 Config::deleteInstance();
11575 QTextCodec::deleteAllCodecs();
11576 delete Doxygen::symbolMap;
11577 delete Doxygen::clangUsrMap;
11578 delete Doxygen::symbolStorage;
11579 g_successfulRun=TRUE;