1 /******************************************************************************
3 * Copyright (C) 1997-2015 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>
30 #include <qtextstream.h>
42 #include "tagreader.h"
45 #include "docparser.h"
47 #include "outputlist.h"
59 #include "sqlite3gen.h"
61 #include "docbookgen.h"
63 #include "perlmodgen.h"
67 #include "commentcnv.h"
68 #include "cmdmapper.h"
69 #include "searchindex.h"
70 #include "parserintf.h"
72 #include "pyscanner.h"
73 #include "fortranscanner.h"
74 #include "xmlscanner.h"
75 #include "sqlscanner.h"
76 #include "tclscanner.h"
82 #include "vhdljjparser.h"
83 #include "vhdldocgen.h"
84 #include "eclipsehelp.h"
86 #include "filestorage.h"
88 #include "arguments.h"
89 #include "memberlist.h"
92 #include "classlist.h"
93 #include "namespacedef.h"
95 #include "membername.h"
96 #include "membergroup.h"
101 #include "fileparser.h"
103 // provided by the generated file resources.cpp
104 extern void initResources();
106 #define RECURSE_ENTRYTREE(func,var) \
107 do { if (var->children()) { \
108 EntryNavListIterator eli(*var->children()); \
109 for (;eli.current();++eli) func(eli.current()); \
113 #if !defined(_WIN32) || defined(__CYGWIN__)
118 // globally accessible variables
119 ClassSDict *Doxygen::classSDict = 0;
120 ClassSDict *Doxygen::hiddenClasses = 0;
121 NamespaceSDict *Doxygen::namespaceSDict = 0;
122 MemberNameSDict *Doxygen::memberNameSDict = 0;
123 MemberNameSDict *Doxygen::functionNameSDict = 0;
124 FileNameList *Doxygen::inputNameList = 0; // all input files
125 FileNameDict *Doxygen::inputNameDict = 0;
126 GroupSDict *Doxygen::groupSDict = 0;
127 FormulaList *Doxygen::formulaList = 0; // all formulas
128 FormulaDict *Doxygen::formulaDict = 0; // all formulas
129 FormulaDict *Doxygen::formulaNameDict = 0; // the label name of all formulas
130 PageSDict *Doxygen::pageSDict = 0;
131 PageSDict *Doxygen::exampleSDict = 0;
132 SectionDict *Doxygen::sectionDict = 0; // all page sections
133 CiteDict *Doxygen::citeDict=0; // database of bibliographic references
134 StringDict Doxygen::aliasDict(257); // aliases
135 QDict<void> Doxygen::inputPaths(1009);
136 FileNameDict *Doxygen::includeNameDict = 0; // include names
137 FileNameDict *Doxygen::exampleNameDict = 0; // examples
138 FileNameDict *Doxygen::imageNameDict = 0; // images
139 FileNameDict *Doxygen::dotFileNameDict = 0; // dot files
140 FileNameDict *Doxygen::mscFileNameDict = 0; // msc files
141 FileNameDict *Doxygen::diaFileNameDict = 0; // dia files
142 StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases
143 StringDict Doxygen::tagDestinationDict(257); // all tag locations
144 QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
145 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
146 PageDef *Doxygen::mainPage = 0;
147 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
148 NamespaceDef *Doxygen::globalScope = 0;
149 QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
150 bool Doxygen::parseSourcesNeeded = FALSE;
151 QTime Doxygen::runningTime;
152 SearchIndexIntf *Doxygen::searchIndex=0;
153 QDict<DefinitionIntf> *Doxygen::symbolMap = 0;
154 QDict<Definition> *Doxygen::clangUsrMap = 0;
155 bool Doxygen::outputToWizard=FALSE;
156 QDict<int> * Doxygen::htmlDirMap = 0;
157 QCache<LookupInfo> *Doxygen::lookupCache;
158 DirSDict *Doxygen::directories;
159 SDict<DirRelation> Doxygen::dirRelations(257);
160 ParserManager *Doxygen::parserManager = 0;
161 QCString Doxygen::htmlFileExtension;
162 bool Doxygen::suppressDocWarnings = FALSE;
163 Store *Doxygen::symbolStorage;
164 QCString Doxygen::objDBFileName;
165 QCString Doxygen::entryDBFileName;
166 bool Doxygen::gatherDefines = TRUE;
167 IndexList *Doxygen::indexList;
168 int Doxygen::subpageNestingLevel = 0;
169 bool Doxygen::userComments = FALSE;
170 QCString Doxygen::spaces;
171 bool Doxygen::generatingXmlOutput = FALSE;
172 bool Doxygen::markdownSupport = TRUE;
173 GenericsSDict *Doxygen::genericsDict;
175 // locally accessible globals
176 static QDict<EntryNav> g_classEntries(1009);
177 static StringList g_inputFiles;
178 static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds
179 static OutputList *g_outputList = 0; // list of output generating objects
180 static QDict<FileDef> g_usingDeclarations(1009); // used classes
181 static FileStorage *g_storage = 0;
182 static bool g_successfulRun = FALSE;
183 static bool g_dumpSymbolMap = FALSE;
184 static bool g_useOutputTemplate = FALSE;
188 g_inputFiles.clear();
189 //g_excludeNameDict.clear();
190 //delete g_outputList; g_outputList=0;
192 Doxygen::classSDict->clear();
193 Doxygen::namespaceSDict->clear();
194 Doxygen::pageSDict->clear();
195 Doxygen::exampleSDict->clear();
196 Doxygen::inputNameList->clear();
197 Doxygen::formulaList->clear();
198 Doxygen::sectionDict->clear();
199 Doxygen::inputNameDict->clear();
200 Doxygen::includeNameDict->clear();
201 Doxygen::exampleNameDict->clear();
202 Doxygen::imageNameDict->clear();
203 Doxygen::dotFileNameDict->clear();
204 Doxygen::mscFileNameDict->clear();
205 Doxygen::diaFileNameDict->clear();
206 Doxygen::formulaDict->clear();
207 Doxygen::formulaNameDict->clear();
208 Doxygen::tagDestinationDict.clear();
209 delete Doxygen::citeDict;
210 delete Doxygen::mainPage; Doxygen::mainPage=0;
216 Statistics() { stats.setAutoDelete(TRUE); }
217 void begin(const char *name)
220 stat *entry= new stat(name,0);
226 stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
231 if (Debug::isFlagSet(Debug::Time))
233 Debug::clearFlag("time");
236 msg("----------------------\n");
237 QListIterator<stat> sli(stats);
239 for ( sli.toFirst(); (s=sli.current()); ++sli )
241 msg("Spent %.3f seconds in %s",s->elapsed,s->name);
243 if (restore) Debug::setFlag("time");
250 stat() : name(NULL),elapsed(0) {}
251 stat(const char *n, double el) : name(n),elapsed(el) {}
260 fprintf(stderr,"--- inputNameDict stats ----\n");
261 Doxygen::inputNameDict->statistics();
262 fprintf(stderr,"--- includeNameDict stats ----\n");
263 Doxygen::includeNameDict->statistics();
264 fprintf(stderr,"--- exampleNameDict stats ----\n");
265 Doxygen::exampleNameDict->statistics();
266 fprintf(stderr,"--- imageNameDict stats ----\n");
267 Doxygen::imageNameDict->statistics();
268 fprintf(stderr,"--- dotFileNameDict stats ----\n");
269 Doxygen::dotFileNameDict->statistics();
270 fprintf(stderr,"--- mscFileNameDict stats ----\n");
271 Doxygen::mscFileNameDict->statistics();
272 fprintf(stderr,"--- diaFileNameDict stats ----\n");
273 Doxygen::diaFileNameDict->statistics();
274 //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
275 //g_excludeNameDict.statistics();
276 fprintf(stderr,"--- aliasDict stats ----\n");
277 Doxygen::aliasDict.statistics();
278 fprintf(stderr,"--- typedefDict stats ----\n");
279 fprintf(stderr,"--- namespaceAliasDict stats ----\n");
280 Doxygen::namespaceAliasDict.statistics();
281 fprintf(stderr,"--- formulaDict stats ----\n");
282 Doxygen::formulaDict->statistics();
283 fprintf(stderr,"--- formulaNameDict stats ----\n");
284 Doxygen::formulaNameDict->statistics();
285 fprintf(stderr,"--- tagDestinationDict stats ----\n");
286 Doxygen::tagDestinationDict.statistics();
287 fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
288 g_compoundKeywordDict.statistics();
289 fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
290 Doxygen::expandAsDefinedDict.statistics();
291 fprintf(stderr,"--- memGrpInfoDict stats ----\n");
292 Doxygen::memGrpInfoDict.statistics();
297 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
298 ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
299 static void findMember(EntryNav *rootNav,
305 enum FindBaseClassRelation_Mode
312 static bool findClassRelation(
317 QDict<int> *templateNames,
318 /*bool insertUndocumented*/
319 FindBaseClassRelation_Mode mode,
323 /** A struct contained the data for an STL class */
326 const char *className;
327 const char *baseClass1;
328 const char *baseClass2;
329 const char *templType1;
330 const char *templName1;
331 const char *templType2;
332 const char *templName2;
333 bool virtualInheritance;
337 static STLInfo g_stlinfo[] =
339 // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators
340 { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
341 { "array", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, // C++11
342 { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // deprecated
343 { "smart_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
344 { "unique_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
345 { "weak_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
346 { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
347 { "error_code", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
348 { "error_category", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
349 { "system_error", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
350 { "error_condition", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
351 { "thread", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
352 { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE },
353 { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
354 { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
355 { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE },
356 { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
357 { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
358 { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
359 { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
360 { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
361 { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
362 { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
363 { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
364 { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
365 { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
366 { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
367 { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
368 { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
369 { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
370 { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
371 { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
372 { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
373 { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
374 { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
375 { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
376 { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
377 { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
378 { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
379 { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
380 { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE },
381 { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE },
382 { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE },
383 { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
384 { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE },
385 { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
386 { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
387 { "forward_list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, // C++11
388 { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
389 { "unordered_map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
390 { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
391 { "unordered_multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
392 { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
393 { "unordered_set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
394 { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
395 { "unordered_multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
396 { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
397 { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
398 { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
399 { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
400 { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
401 { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
402 { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
403 { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
404 { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
405 { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
406 { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
407 { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
408 { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
409 { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
410 { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
411 { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
412 { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
413 { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
414 { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
415 { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
416 { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE }
419 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
421 Entry *memEntry = new Entry;
422 memEntry->name = name;
423 memEntry->type = type;
424 memEntry->protection = Public;
425 memEntry->section = Entry::VARIABLE_SEC;
426 memEntry->brief = "STL member";
427 memEntry->hidden = FALSE;
428 memEntry->artificial = TRUE;
429 //memEntry->parent = root;
430 //root->addSubEntry(memEntry);
431 EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
432 memEntryNav->setEntry(memEntry);
433 rootNav->addChild(memEntryNav);
436 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
438 Entry *iteratorClassEntry = new Entry;
439 iteratorClassEntry->fileName = "[STL]";
440 iteratorClassEntry->startLine = 1;
441 iteratorClassEntry->name = name;
442 iteratorClassEntry->section = Entry::CLASS_SEC;
443 iteratorClassEntry->brief = "STL iterator class";
444 iteratorClassEntry->hidden = FALSE;
445 iteratorClassEntry->artificial= TRUE;
446 EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
447 iteratorClassEntryNav->setEntry(iteratorClassEntry);
448 classEntryNav->addChild(iteratorClassEntryNav);
452 static void addSTLClasses(EntryNav *rootNav)
454 Entry *namespaceEntry = new Entry;
455 namespaceEntry->fileName = "[STL]";
456 namespaceEntry->startLine = 1;
457 //namespaceEntry->parent = rootNav->entry();
458 namespaceEntry->name = "std";
459 namespaceEntry->section = Entry::NAMESPACE_SEC;
460 namespaceEntry->brief = "STL namespace";
461 namespaceEntry->hidden = FALSE;
462 namespaceEntry->artificial= TRUE;
463 //root->addSubEntry(namespaceEntry);
464 EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
465 namespaceEntryNav->setEntry(namespaceEntry);
466 rootNav->addChild(namespaceEntryNav);
468 STLInfo *info = g_stlinfo;
469 while (info->className)
471 //printf("Adding STL class %s\n",info->className);
472 QCString fullName = info->className;
473 fullName.prepend("std::");
475 // add fake Entry for the class
476 Entry *classEntry = new Entry;
477 classEntry->fileName = "[STL]";
478 classEntry->startLine = 1;
479 classEntry->name = fullName;
480 //classEntry->parent = namespaceEntry;
481 classEntry->section = Entry::CLASS_SEC;
482 classEntry->brief = "STL class";
483 classEntry->hidden = FALSE;
484 classEntry->artificial= TRUE;
485 //namespaceEntry->addSubEntry(classEntry);
486 EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
487 classEntryNav->setEntry(classEntry);
488 namespaceEntryNav->addChild(classEntryNav);
490 // add template arguments to class
491 if (info->templType1)
493 ArgumentList *al = new ArgumentList;
494 Argument *a=new Argument;
496 a->name=info->templType1;
498 if (info->templType2) // another template argument
502 a->name=info->templType2;
505 classEntry->tArgLists = new QList<ArgumentList>;
506 classEntry->tArgLists->setAutoDelete(TRUE);
507 classEntry->tArgLists->append(al);
509 // add member variables
510 if (info->templName1)
512 addSTLMember(classEntryNav,info->templType1,info->templName1);
514 if (info->templName2)
516 addSTLMember(classEntryNav,info->templType2,info->templName2);
518 if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
519 fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
521 Entry *memEntry = new Entry;
522 memEntry->name = "operator->";
523 memEntry->args = "()";
524 memEntry->type = "T*";
525 memEntry->protection = Public;
526 memEntry->section = Entry::FUNCTION_SEC;
527 memEntry->brief = "STL member";
528 memEntry->hidden = FALSE;
529 memEntry->artificial = FALSE;
530 EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
531 memEntryNav->setEntry(memEntry);
532 classEntryNav->addChild(memEntryNav);
534 if (info->baseClass1)
536 classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
538 if (info->baseClass2)
540 classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
544 // add iterator class
545 addSTLIterator(classEntryNav,fullName+"::iterator");
546 addSTLIterator(classEntryNav,fullName+"::const_iterator");
547 addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
548 addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
554 //----------------------------------------------------------------------------
556 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
557 FileDef *fileScope,TagInfo *tagInfo);
559 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
561 if (rootNav->parent()) // add the page to it's scope
563 QCString scope = rootNav->parent()->name();
564 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
566 scope=substitute(scope,".","::");
568 scope = stripAnonymousNamespaceScope(scope);
569 scope+="::"+pd->name();
570 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
578 static void addRelatedPage(EntryNav *rootNav)
580 Entry *root = rootNav->entry();
582 QListIterator<Grouping> gli(*root->groups);
584 for (;(g=gli.current());++gli)
586 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
588 //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
590 if (root->brief.isEmpty())
592 doc=root->doc+root->inbodyDocs;
596 doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
598 PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
599 root->docFile,root->docLine,
601 gd,rootNav->tagInfo(),
606 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
607 pd->addSectionsToDefinition(root->anchors);
608 pd->setShowToc(root->stat);
609 addPageToContext(pd,rootNav);
613 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
615 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
616 ((!includeExternal && rootNav->tagInfo()==0) ||
617 ( includeExternal && rootNav->tagInfo()!=0))
620 rootNav->loadEntry(g_storage);
621 Entry *root = rootNav->entry();
623 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
624 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
626 GroupDef *gd = Doxygen::groupSDict->find(root->name);
627 //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
628 // root->type.data(),root->name.data(),additional,includeExternal,gd);
632 if ( !gd->hasGroupTitle() )
634 gd->setGroupTitle( root->type );
636 else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
638 warn( root->fileName,root->startLine,
639 "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
640 qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
642 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
643 gd->setDocumentation( root->doc, root->docFile, root->docLine );
644 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
645 gd->addSectionsToDefinition(root->anchors);
646 gd->setRefItems(root->sli);
647 gd->setLanguage(root->lang);
651 if (rootNav->tagInfo())
653 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
654 gd->setReference(rootNav->tagInfo()->tagName);
658 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
660 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
661 // allow empty docs for group
662 gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
663 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
664 gd->addSectionsToDefinition(root->anchors);
665 Doxygen::groupSDict->append(root->name,gd);
666 gd->setRefItems(root->sli);
667 gd->setLanguage(root->lang);
671 rootNav->releaseEntry();
673 if (rootNav->children())
675 EntryNavListIterator eli(*rootNav->children());
677 for (;(e=eli.current());++eli)
679 buildGroupListFiltered(e,additional,includeExternal);
684 static void buildGroupList(EntryNav *rootNav)
686 // --- first process only local groups
687 // first process the @defgroups blocks
688 buildGroupListFiltered(rootNav,FALSE,FALSE);
689 // then process the @addtogroup, @weakgroup blocks
690 buildGroupListFiltered(rootNav,TRUE,FALSE);
692 // --- then also process external groups
693 // first process the @defgroups blocks
694 buildGroupListFiltered(rootNav,FALSE,TRUE);
695 // then process the @addtogroup, @weakgroup blocks
696 buildGroupListFiltered(rootNav,TRUE,TRUE);
699 static void findGroupScope(EntryNav *rootNav)
701 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
702 rootNav->parent() && !rootNav->parent()->name().isEmpty())
705 if ((gd=Doxygen::groupSDict->find(rootNav->name())))
707 QCString scope = rootNav->parent()->name();
708 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
710 scope=substitute(scope,".","::");
712 scope = stripAnonymousNamespaceScope(scope);
713 scope+="::"+gd->name();
714 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
717 gd->setGroupScope(d);
721 RECURSE_ENTRYTREE(findGroupScope,rootNav);
724 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
726 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
728 rootNav->loadEntry(g_storage);
729 Entry *root = rootNav->entry();
731 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
732 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
735 if ((gd=Doxygen::groupSDict->find(root->name)))
737 //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
738 addGroupToGroups(root,gd);
742 rootNav->releaseEntry();
744 if (rootNav->children())
746 EntryNavListIterator eli(*rootNav->children());
748 for (;(e=eli.current());++eli)
750 organizeSubGroupsFiltered(e,additional);
755 static void organizeSubGroups(EntryNav *rootNav)
757 //printf("Defining groups\n");
758 // first process the @defgroups blocks
759 organizeSubGroupsFiltered(rootNav,FALSE);
760 //printf("Additional groups\n");
761 // then process the @addtogroup, @weakgroup blocks
762 organizeSubGroupsFiltered(rootNav,TRUE);
765 //----------------------------------------------------------------------
767 static void buildFileList(EntryNav *rootNav)
769 if (((rootNav->section()==Entry::FILEDOC_SEC) ||
770 ((rootNav->section() & Entry::FILE_MASK) && Config_getBool(EXTRACT_ALL))) &&
771 !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
774 rootNav->loadEntry(g_storage);
775 Entry *root = rootNav->entry();
778 FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
779 //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
783 if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
784 (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
787 root->fileName,root->startLine,
788 "file %s already documented. "
789 "Skipping documentation.",
796 //printf("Adding documentation!\n");
797 // using FALSE in setDocumentation is small hack to make sure a file
798 // is documented even if a \file command is used without further
800 fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
801 fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
802 fd->addSectionsToDefinition(root->anchors);
803 fd->setRefItems(root->sli);
804 QListIterator<Grouping> gli(*root->groups);
806 for (;(g=gli.current());++gli)
809 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
812 fd->makePartOfGroup(gd);
813 //printf("File %s: in group %s\n",fd->name().data(),s->data());
820 const char *fn = root->fileName.data();
822 text.sprintf("the name `%s' supplied as "
823 "the second argument in the \\file statement ",
825 if (ambig) // name is ambiguous
827 text+="matches the following input files:\n";
828 text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
829 text+="Please use a more specific name by "
830 "including a (larger) part of the path!";
832 else // name is not an input file
834 text+="is not an input file";
836 warn(fn,root->startLine,text);
839 rootNav->releaseEntry();
841 RECURSE_ENTRYTREE(buildFileList,rootNav);
844 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
847 (!root->doc.stripWhiteSpace().isEmpty() ||
848 !root->brief.stripWhiteSpace().isEmpty() ||
849 Config_getBool(EXTRACT_ALL)
850 ) && root->protection!=Private
853 //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
855 bool local=Config_getBool(FORCE_LOCAL_INCLUDES);
856 QCString includeFile = root->includeFile;
857 if (!includeFile.isEmpty() && includeFile.at(0)=='"')
860 includeFile=includeFile.mid(1,includeFile.length()-2);
862 else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
865 includeFile=includeFile.mid(1,includeFile.length()-2);
870 // see if we need to include a verbatim copy of the header file
871 //printf("root->includeFile=%s\n",root->includeFile.data());
872 if (!includeFile.isEmpty() &&
873 (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
875 { // explicit request
877 text.sprintf("the name `%s' supplied as "
878 "the argument of the \\class, \\struct, \\union, or \\include command ",
881 if (ambig) // name is ambiguous
883 text+="matches the following input files:\n";
884 text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
885 text+="Please use a more specific name by "
886 "including a (larger) part of the path!";
888 else // name is not an input file
890 text+="is not an input file";
892 warn(root->fileName,root->startLine,text);
894 else if (includeFile.isEmpty() && ifd &&
895 // see if the file extension makes sense
896 guessSection(ifd->name())==Entry::HEADER_SEC)
897 { // implicit assumption
901 // if a file is found, we mark it as a source file.
904 QCString iName = !root->includeName.isEmpty() ?
905 root->includeName : includeFile;
906 if (!iName.isEmpty()) // user specified include file
908 if (iName.at(0)=='<') local=FALSE; // explicit override
909 else if (iName.at(0)=='"') local=TRUE;
910 if (iName.at(0)=='"' || iName.at(0)=='<')
912 iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
919 else if (!Config_getList(STRIP_FROM_INC_PATH).isEmpty())
921 iName=stripFromIncludePath(fd->absFilePath());
923 else // use name of the file containing the class definition
927 if (fd->generateSourceFile()) // generate code for header
929 cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
931 else // put #include in the class documentation without link
933 cd->setIncludeFile(0,iName,local,TRUE);
940 static bool addNamespace(Entry *root,ClassDef *cd)
942 // see if this class is defined inside a namespace
943 if (root->section & Entry::COMPOUND_MASK)
945 Entry *e = root->parent;
948 if (e->section==Entry::NAMESPACE_SEC)
951 QCString nsName = stripAnonymousNamespaceScope(e->name);
952 //printf("addNameSpace() trying: %s\n",nsName.data());
953 if (!nsName.isEmpty() && nsName.at(0)!='@' &&
954 (nd=getResolvedNamespace(nsName))
957 cd->setNamespace(nd);
958 cd->setOuterScope(nd);
971 static Definition *findScope(Entry *root,int level=0)
973 if (root==0) return 0;
974 //printf("start findScope name=%s\n",root->name.data());
975 Definition *result=0;
976 if (root->section&Entry::SCOPE_MASK)
978 result = findScope(root->parent,level+1); // traverse to the root of the tree
981 //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
982 // TODO: look at template arguments
983 result = result->findInnerCompound(root->name);
985 else // reached the global scope
987 // TODO: look at template arguments
988 result = Doxygen::globalScope->findInnerCompound(root->name);
989 //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
992 //printf("end findScope(%s,%d)=%s\n",root->name.data(),
993 // level,result==0 ? "<none>" : result->name().data());
998 /*! returns the Definition object belonging to the first \a level levels of
999 * full qualified name \a name. Creates an artificial scope if the scope is
1000 * not found and set the parent/child scope relation if the scope is found.
1002 static Definition *buildScopeFromQualifiedName(const QCString name,
1003 int level,SrcLangExt lang,TagInfo *tagInfo)
1005 //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
1008 Definition *prevScope=Doxygen::globalScope;
1012 int idx=getScopeFragment(name,p,&l);
1013 if (idx==-1) return prevScope;
1014 QCString nsName = name.mid(idx,l);
1015 if (nsName.isEmpty()) return prevScope;
1016 if (!fullScope.isEmpty()) fullScope+="::";
1018 NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
1019 Definition *innerScope = nd;
1021 if (nd==0) cd = getClass(fullScope);
1022 if (nd==0 && cd) // scope is a class
1026 else if (nd==0 && cd==0 && fullScope.find('<')==-1) // scope is not known and could be a namespace!
1028 // introduce bogus namespace
1029 //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
1030 nd=new NamespaceDef(
1031 "[generated]",1,1,fullScope,
1032 tagInfo?tagInfo->tagName:QCString(),
1033 tagInfo?tagInfo->fileName:QCString());
1034 nd->setLanguage(lang);
1036 // add namespace to the list
1037 Doxygen::namespaceSDict->inSort(fullScope,nd);
1040 else // scope is a namespace
1045 // make the parent/child scope relation
1046 prevScope->addInnerCompound(innerScope);
1047 innerScope->setOuterScope(prevScope);
1049 else // current scope is a class, so return only the namespace part...
1053 // proceed to the next scope fragment
1055 prevScope=innerScope;
1061 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
1062 FileDef *fileScope,TagInfo *tagInfo)
1064 //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
1065 Definition *resultScope=startScope;
1066 if (resultScope==0) resultScope=Doxygen::globalScope;
1067 QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
1069 i1=getScopeFragment(scope,0,&l1);
1072 //printf(">no fragments!\n");
1075 int p=i1+l1,l2=0,i2;
1076 while ((i2=getScopeFragment(scope,p,&l2))!=-1)
1078 QCString nestedNameSpecifier = scope.mid(i1,l1);
1079 Definition *orgScope = resultScope;
1080 //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
1081 resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
1082 //printf(" resultScope=%p\n",resultScope);
1085 NamespaceSDict *usedNamespaces;
1086 if (orgScope==Doxygen::globalScope && fileScope &&
1087 (usedNamespaces = fileScope->getUsedNamespaces()))
1088 // also search for used namespaces
1090 NamespaceSDict::Iterator ni(*usedNamespaces);
1092 for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
1094 // restart search within the used namespace
1095 resultScope = findScopeFromQualifiedName(nd,n,fileScope,tagInfo);
1099 // for a nested class A::I in used namespace N, we get
1100 // N::A::I while looking for A, so we should compare
1101 // resultScope->name() against scope.left(i2+l2)
1102 //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1103 if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1111 // also search for used classes. Complication: we haven't been able
1112 // to put them in the right scope yet, because we are still resolving
1113 // the scope relations!
1114 // Therefore loop through all used classes and see if there is a right
1115 // scope match between the used class and nestedNameSpecifier.
1116 QDictIterator<FileDef> ui(g_usingDeclarations);
1118 for (ui.toFirst();(usedFd=ui.current());++ui)
1120 //printf("Checking using class %s\n",ui.currentKey());
1121 if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1123 // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1124 // so use this instead.
1125 QCString fqn = QCString(ui.currentKey())+
1126 scope.right(scope.length()-p);
1127 resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),
1128 startScope->getLanguage(),0);
1129 //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1132 //printf("> Match! resultScope=%s\n",resultScope->name().data());
1138 //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1146 //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1150 ArgumentList *getTemplateArgumentsFromName(
1151 const QCString &name,
1152 const QList<ArgumentList> *tArgLists)
1154 if (tArgLists==0) return 0;
1156 QListIterator<ArgumentList> ali(*tArgLists);
1157 // for each scope fragment, check if it is a template and advance through
1160 while ((i=name.find("::",p))!=-1)
1162 NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1165 ClassDef *cd = getClass(name.left(i));
1168 if (cd->templateArguments())
1176 return ali.current();
1180 ClassDef::CompoundType convertToCompoundType(int section,uint64 specifier)
1182 ClassDef::CompoundType sec=ClassDef::Class;
1183 if (specifier&Entry::Struct)
1184 sec=ClassDef::Struct;
1185 else if (specifier&Entry::Union)
1186 sec=ClassDef::Union;
1187 else if (specifier&Entry::Category)
1188 sec=ClassDef::Category;
1189 else if (specifier&Entry::Interface)
1190 sec=ClassDef::Interface;
1191 else if (specifier&Entry::Protocol)
1192 sec=ClassDef::Protocol;
1193 else if (specifier&Entry::Exception)
1194 sec=ClassDef::Exception;
1195 else if (specifier&Entry::Service)
1196 sec=ClassDef::Service;
1197 else if (specifier&Entry::Singleton)
1198 sec=ClassDef::Singleton;
1202 //case Entry::UNION_SEC:
1203 case Entry::UNIONDOC_SEC:
1204 sec=ClassDef::Union;
1206 //case Entry::STRUCT_SEC:
1207 case Entry::STRUCTDOC_SEC:
1208 sec=ClassDef::Struct;
1210 //case Entry::INTERFACE_SEC:
1211 case Entry::INTERFACEDOC_SEC:
1212 sec=ClassDef::Interface;
1214 //case Entry::PROTOCOL_SEC:
1215 case Entry::PROTOCOLDOC_SEC:
1216 sec=ClassDef::Protocol;
1218 //case Entry::CATEGORY_SEC:
1219 case Entry::CATEGORYDOC_SEC:
1220 sec=ClassDef::Category;
1222 //case Entry::EXCEPTION_SEC:
1223 case Entry::EXCEPTIONDOC_SEC:
1224 sec=ClassDef::Exception;
1226 case Entry::SERVICEDOC_SEC:
1227 sec=ClassDef::Service;
1229 case Entry::SINGLETONDOC_SEC:
1230 sec=ClassDef::Singleton;
1237 static void addClassToContext(EntryNav *rootNav)
1239 //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1240 rootNav->loadEntry(g_storage);
1241 Entry *root = rootNav->entry();
1243 //NamespaceDef *nd = 0;
1244 FileDef *fd = rootNav->fileDef();
1247 if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1249 scName=rootNav->parent()->name();
1251 // name without parent's scope
1252 QCString fullName = root->name;
1254 // strip off any template parameters (but not those for specializations)
1255 fullName=stripTemplateSpecifiersFromScope(fullName);
1257 // name with scope (if not present already)
1258 QCString qualifiedName = fullName;
1259 if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1261 qualifiedName.prepend(scName+"::");
1264 // see if we already found the class before
1265 ClassDef *cd = getClass(qualifiedName);
1267 Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1268 cd ? qPrint(cd->name()) : qPrint(root->name), qPrint(qualifiedName),cd);
1272 fullName=cd->name();
1273 Debug::print(Debug::Classes,0," Existing class %s!\n",qPrint(cd->name()));
1274 //if (cd->templateArguments()==0)
1276 // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1277 // cd->setTemplateArguments(tArgList);
1280 cd->setDocumentation(root->doc,root->docFile,root->docLine);
1281 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1283 if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1285 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1288 //cd->setName(fullName); // change name to match docs
1290 if (cd->templateArguments()==0 || (cd->isForwardDeclared() && (root->spec&Entry::ForwardDecl)==0))
1292 // this happens if a template class declared with @class is found
1293 // before the actual definition or if a forward declaration has different template
1295 ArgumentList *tArgList =
1296 getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1297 cd->setTemplateArguments(tArgList);
1300 cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1304 ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1307 QCString namespaceName;
1308 extractNamespaceName(fullName,className,namespaceName);
1310 //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1311 // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1314 QCString refFileName;
1315 TagInfo *tagInfo = rootNav->tagInfo();
1319 tagName = tagInfo->tagName;
1320 refFileName = tagInfo->fileName;
1321 if (fullName.find("::")!=-1)
1322 // symbols imported via tag files may come without the parent scope,
1323 // so we artificially create it here
1325 buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1328 ArgumentList *tArgList = 0;
1329 if ((root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java) && (i=fullName.find('<'))!=-1)
1331 // a Java/C# generic class looks like a C++ specialization, so we need to split the
1332 // name and template arguments here
1333 tArgList = new ArgumentList;
1334 stringToArgumentList(fullName.mid(i),tArgList);
1335 fullName=fullName.left(i);
1339 tArgList = getTemplateArgumentsFromName(fullName,root->tArgLists);
1341 cd=new ClassDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn,
1342 fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1343 Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1344 qPrint(fullName),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
1345 cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1346 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1347 cd->setLanguage(root->lang);
1348 cd->setId(root->id);
1349 cd->setHidden(root->hidden);
1350 cd->setArtificial(root->artificial);
1351 cd->setClassSpecifier(root->spec);
1352 cd->setTypeConstraints(root->typeConstr);
1353 //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1355 //printf("class %s template args=%s\n",fullName.data(),
1356 // tArgList ? tempArgListToString(tArgList,root->lang).data() : "<none>");
1357 cd->setTemplateArguments(tArgList);
1358 cd->setProtection(root->protection);
1359 cd->setIsStatic(root->stat);
1361 // file definition containing the class cd
1362 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1365 // see if the class is found inside a namespace
1366 //bool found=addNamespace(root,cd);
1368 cd->insertUsedFile(fd);
1370 // add class to the list
1371 //printf("ClassDict.insert(%s)\n",fullName.data());
1372 Doxygen::classSDict->append(fullName,cd);
1374 if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1376 //printf("inserting generic '%s' cd=%p\n",fullName.data(),cd);
1377 Doxygen::genericsDict->insert(fullName,cd);
1381 cd->addSectionsToDefinition(root->anchors);
1382 if (!root->subGrouping) cd->setSubGrouping(FALSE);
1383 if (cd->hasDocumentation())
1385 addIncludeFile(cd,fd,root);
1387 if (fd && (root->section & Entry::COMPOUND_MASK))
1389 //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1390 // cd->name().data(),
1391 // fd->name().data(),
1392 // root->fileName.data()
1395 fd->insertClass(cd);
1397 addClassToGroups(root,cd);
1398 cd->setRefItems(root->sli);
1400 rootNav->releaseEntry();
1403 //----------------------------------------------------------------------
1404 // build a list of all classes mentioned in the documentation
1405 // and all classes that have a documentation block before their definition.
1406 static void buildClassList(EntryNav *rootNav)
1409 ((rootNav->section() & Entry::COMPOUND_MASK) ||
1410 rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1413 addClassToContext(rootNav);
1415 RECURSE_ENTRYTREE(buildClassList,rootNav);
1418 static void buildClassDocList(EntryNav *rootNav)
1421 (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1424 addClassToContext(rootNav);
1426 RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1429 static void resolveClassNestingRelations()
1431 ClassSDict::Iterator cli(*Doxygen::classSDict);
1432 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1441 for (cli.toFirst();(cd=cli.current());++cli)
1445 QCString name = stripAnonymousNamespaceScope(cd->name());
1446 //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1447 // also add class to the correct structural context
1448 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1449 name,cd->getFileDef(),0);
1452 //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1453 d->addInnerCompound(cd);
1454 cd->setOuterScope(d);
1460 // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1466 //give warnings for unresolved compounds
1468 for (cli.toFirst();(cd=cli.current());++cli)
1472 QCString name = stripAnonymousNamespaceScope(cd->name());
1473 //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1474 /// create the scope artificially
1475 // anyway, so we can at least relate scopes properly.
1476 Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1477 if (d!=cd && !cd->getDefFileName().isEmpty())
1478 // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1479 // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1480 // also avoid warning for stuff imported via a tagfile.
1482 d->addInnerCompound(cd);
1483 cd->setOuterScope(d);
1484 warn(cd->getDefFileName(),cd->getDefLine(),
1485 "Internal inconsistency: scope for class %s not "
1486 "found!",name.data()
1493 void distributeClassGroupRelations()
1495 //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
1496 //if (!inlineGroupedClasses) return;
1497 //printf("** distributeClassGroupRelations()\n");
1499 ClassSDict::Iterator cli(*Doxygen::classSDict);
1500 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1503 for (cli.toFirst();(cd=cli.current());++cli)
1505 //printf("Checking %s\n",cd->name().data());
1506 // distribute the group to nested classes as well
1507 if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1509 //printf(" Candidate for merging\n");
1510 ClassSDict::Iterator ncli(*cd->getClassSDict());
1512 GroupDef *gd = cd->partOfGroups()->at(0);
1513 for (ncli.toFirst();(ncd=ncli.current());++ncli)
1515 if (ncd->partOfGroups()==0)
1517 //printf(" Adding %s to group '%s'\n",ncd->name().data(),
1518 // gd->groupTitle());
1519 ncd->makePartOfGroup(gd);
1523 cd->visited=TRUE; // only visit every class once
1528 //----------------------------
1530 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1532 QCString fullName = removeAnonymousScopes(templ->name());
1533 if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1534 fullName+="."+fieldName;
1535 ClassDef *cd = new ClassDef(templ->getDefFileName(),
1536 templ->getDefLine(),
1537 templ->getDefColumn(),
1539 templ->compoundType());
1540 cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1541 cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1542 cd->setLanguage(templ->getLanguage());
1543 cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1544 cd->setBodyDef(templ->getBodyDef());
1546 cd->setOuterScope(rootCd->getOuterScope());
1547 if (rootCd->getOuterScope()!=Doxygen::globalScope)
1549 rootCd->getOuterScope()->addInnerCompound(cd);
1552 FileDef *fd = templ->getFileDef();
1556 fd->insertClass(cd);
1558 GroupList *groups = rootCd->partOfGroups();
1561 GroupListIterator gli(*groups);
1563 for (gli.toFirst();(gd=gli.current());++gli)
1565 cd->makePartOfGroup(gd);
1569 //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1570 Doxygen::classSDict->append(fullName,cd);
1572 MemberList *ml = templ->getMemberList(MemberListType_pubAttribs);
1575 MemberListIterator li(*ml);
1577 for (li.toFirst();(md=li.current());++li)
1579 //printf(" Member %s type=%s\n",md->name().data(),md->typeString());
1580 MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1581 md->typeString(),md->name(),md->argsString(),md->excpString(),
1582 md->protection(),md->virtualness(),md->isStatic(),Member,
1585 imd->setMemberClass(cd);
1586 imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1587 imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1588 imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1589 imd->setMemberSpecifiers(md->getMemberSpecifiers());
1590 imd->setMemberGroupId(md->getMemberGroupId());
1591 imd->setInitializer(md->initializer());
1592 imd->setMaxInitLines(md->initializerLines());
1593 imd->setBitfields(md->bitfieldString());
1594 imd->setLanguage(md->getLanguage());
1595 cd->insertMember(imd);
1601 /** Look through the members of class \a cd and its public members.
1602 * If there is a member m of a tag less struct/union,
1603 * then we create a duplicate of the struct/union with the name of the
1604 * member to identify it.
1605 * So if cd has name S, then the tag less struct/union will get name S.m
1606 * Since tag less structs can be nested we need to call this function
1607 * recursively. Later on we need to patch the member types so we keep
1608 * track of the hierarchy of classes we create.
1610 static void processTagLessClasses(ClassDef *rootCd,
1612 ClassDef *tagParentCd,
1613 const QCString &prefix,int count)
1615 //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1616 //printf("checking members for %s\n",cd->name().data());
1617 if (cd->getClassSDict())
1619 MemberList *ml = cd->getMemberList(MemberListType_pubAttribs);
1622 MemberListIterator li(*ml);
1624 for (li.toFirst();(md=li.current());++li)
1626 QCString type = md->typeString();
1627 if (type.find("::@")!=-1) // member of tag less struct/union
1629 ClassSDict::Iterator it(*cd->getClassSDict());
1631 for (it.toFirst();(icd=it.current());++it)
1633 //printf(" member %s: type='%s'\n",md->name().data(),type.data());
1634 //printf(" comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1635 if (type.find(icd->name())!=-1) // matching tag less struct/union
1637 QCString name = md->name();
1638 if (name.at(0)=='@') name = "__unnamed__";
1639 if (!prefix.isEmpty()) name.prepend(prefix+".");
1640 //printf(" found %s for class %s\n",name.data(),cd->name().data());
1641 ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1642 processTagLessClasses(rootCd,icd,ncd,name,count+1);
1643 //printf(" addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1644 tagParentCd->addTaggedInnerClass(ncd);
1645 ncd->setTagLessReference(icd);
1647 // replace tag-less type for generated/original member
1648 // by newly created class name.
1649 // note the difference between changing cd and tagParentCd.
1650 // for the initial call this is the same pointer, but for
1651 // recursive calls cd is the original tag-less struct (of which
1652 // there is only one instance) and tagParentCd is the newly
1653 // generated tagged struct of which there can be multiple instances!
1654 MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1657 MemberListIterator pli(*pml);
1659 for (pli.toFirst();(pmd=pli.current());++pli)
1661 if (pmd->name()==md->name())
1663 pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1664 //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1676 static void findTagLessClasses(ClassDef *cd)
1678 if (cd->getClassSDict())
1680 ClassSDict::Iterator it(*cd->getClassSDict());
1682 for (it.toFirst();(icd=it.current());++it)
1684 if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1686 findTagLessClasses(icd);
1691 processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1694 static void findTagLessClasses()
1696 ClassSDict::Iterator cli(*Doxygen::classSDict);
1698 for (cli.toFirst();(cd=cli.current());++cli) // for each class
1700 Definition *scope = cd->getOuterScope();
1701 if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1703 findTagLessClasses(cd);
1709 //----------------------------------------------------------------------
1710 // build a list of all namespaces mentioned in the documentation
1711 // and all namespaces that have a documentation block before their definition.
1712 static void buildNamespaceList(EntryNav *rootNav)
1715 (rootNav->section()==Entry::NAMESPACE_SEC ||
1716 rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1717 rootNav->section()==Entry::PACKAGEDOC_SEC
1719 !rootNav->name().isEmpty()
1722 rootNav->loadEntry(g_storage);
1723 Entry *root = rootNav->entry();
1725 //printf("** buildNamespaceList(%s)\n",root->name.data());
1727 QCString fName = root->name;
1728 if (root->section==Entry::PACKAGEDOC_SEC)
1730 fName=substitute(fName,".","::");
1733 QCString fullName = stripAnonymousNamespaceScope(fName);
1734 if (!fullName.isEmpty())
1736 //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1737 // root->fileName.data(), root->startLine);
1739 if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1741 nd->setDocumentation(root->doc,root->docFile,root->docLine);
1742 nd->setName(fullName); // change name to match docs
1743 nd->addSectionsToDefinition(root->anchors);
1744 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1745 if (nd->getLanguage()==SrcLangExt_Unknown)
1747 nd->setLanguage(root->lang);
1749 if (rootNav->tagInfo()==0) // if we found the namespace in a tag file
1750 // and also in a project file, then remove
1751 // the tag file reference
1753 nd->setReference("");
1754 nd->setFileName(fullName);
1757 // file definition containing the namespace nd
1758 FileDef *fd=rootNav->fileDef();
1759 // insert the namespace in the file definition
1760 if (fd) fd->insertNamespace(nd);
1761 addNamespaceToGroups(root,nd);
1762 nd->setRefItems(root->sli);
1764 else // fresh namespace
1767 QCString tagFileName;
1768 TagInfo *tagInfo = rootNav->tagInfo();
1771 tagName = tagInfo->tagName;
1772 tagFileName = tagInfo->fileName;
1774 //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1775 NamespaceDef *nd=new NamespaceDef(tagInfo?tagName:root->fileName,root->startLine,
1776 root->startColumn,fullName,tagName,tagFileName,
1777 root->type,root->spec&Entry::Published);
1778 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1779 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1780 nd->addSectionsToDefinition(root->anchors);
1781 nd->setHidden(root->hidden);
1782 nd->setArtificial(root->artificial);
1783 nd->setLanguage(root->lang);
1784 nd->setId(root->id);
1786 //printf("Adding namespace to group\n");
1787 addNamespaceToGroups(root,nd);
1788 nd->setRefItems(root->sli);
1790 // file definition containing the namespace nd
1791 FileDef *fd=rootNav->fileDef();
1792 // insert the namespace in the file definition
1793 if (fd) fd->insertNamespace(nd);
1795 // the empty string test is needed for extract all case
1796 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1797 nd->insertUsedFile(fd);
1798 nd->setBodySegment(root->bodyLine,root->endBodyLine);
1800 // add class to the list
1801 Doxygen::namespaceSDict->inSort(fullName,nd);
1803 // also add namespace to the correct structural context
1804 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName,0,tagInfo);
1805 //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1806 if (d==0) // we didn't find anything, create the scope artificially
1807 // anyway, so we can at least relate scopes properly.
1809 Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1810 d->addInnerCompound(nd);
1811 nd->setOuterScope(d);
1812 // TODO: Due to the order in which the tag file is written
1813 // a nested class can be found before its parent!
1817 d->addInnerCompound(nd);
1818 nd->setOuterScope(d);
1823 rootNav->releaseEntry();
1825 RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1828 //----------------------------------------------------------------------
1830 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1831 const QCString &name)
1833 NamespaceDef *usingNd =0;
1836 //printf("Found namespace dict %d\n",unl->count());
1837 NamespaceSDict::Iterator unli(*unl);
1839 for (unli.toFirst();(und=unli.current());++unli)
1841 QCString uScope=und->name()+"::";
1842 usingNd = getResolvedNamespace(uScope+name);
1843 //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1849 static void findUsingDirectives(EntryNav *rootNav)
1851 if (rootNav->section()==Entry::USINGDIR_SEC)
1853 rootNav->loadEntry(g_storage);
1854 Entry *root = rootNav->entry();
1856 //printf("Found using directive %s at line %d of %s\n",
1857 // root->name.data(),root->startLine,root->fileName.data());
1858 QCString name=substitute(root->name,".","::");
1859 if (name.right(2)=="::")
1861 name=name.left(name.length()-2);
1863 if (!name.isEmpty())
1865 NamespaceDef *usingNd = 0;
1866 NamespaceDef *nd = 0;
1867 FileDef *fd = rootNav->fileDef();
1870 // see if the using statement was found inside a namespace or inside
1871 // the global file scope.
1872 if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1873 (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1876 nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1877 if (!nsName.isEmpty())
1879 nd = getResolvedNamespace(nsName);
1883 // find the scope in which the `using' namespace is defined by prepending
1884 // the possible scopes in which the using statement was found, starting
1885 // with the most inner scope and going to the most outer scope (i.e.
1887 int scopeOffset = nsName.length();
1890 QCString scope=scopeOffset>0 ?
1891 nsName.left(scopeOffset)+"::" : QCString();
1892 usingNd = getResolvedNamespace(scope+name);
1893 //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1898 else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1902 } while (scopeOffset>=0 && usingNd==0);
1904 if (usingNd==0 && nd) // not found, try used namespaces in this scope
1905 // or in one of the parent namespace scopes
1907 NamespaceDef *pnd = nd;
1908 while (pnd && usingNd==0)
1910 // also try with one of the used namespaces found earlier
1911 usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1914 Definition *s = pnd->getOuterScope();
1915 if (s && s->definitionType()==Definition::TypeNamespace)
1917 pnd = (NamespaceDef*)s;
1925 if (usingNd==0 && fd) // still nothing, also try used namespace in the
1928 usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1931 //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1933 // add the namespace the correct scope
1936 //printf("using fd=%p nd=%p\n",fd,nd);
1939 //printf("Inside namespace %s\n",nd->name().data());
1940 nd->addUsingDirective(usingNd);
1944 //printf("Inside file %s\n",fd->name().data());
1945 fd->addUsingDirective(usingNd);
1948 else // unknown namespace, but add it anyway.
1950 //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1951 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1952 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1953 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1954 nd->addSectionsToDefinition(root->anchors);
1955 //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1956 nd->setHidden(root->hidden);
1957 nd->setArtificial(TRUE);
1958 nd->setLanguage(root->lang);
1959 nd->setId(root->id);
1961 QListIterator<Grouping> gli(*root->groups);
1963 for (;(g=gli.current());++gli)
1966 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1967 gd->addNamespace(nd);
1970 // insert the namespace in the file definition
1973 fd->insertNamespace(nd);
1974 fd->addUsingDirective(nd);
1977 // the empty string test is needed for extract all case
1978 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1979 nd->insertUsedFile(fd);
1980 // add class to the list
1981 Doxygen::namespaceSDict->inSort(name,nd);
1982 nd->setRefItems(root->sli);
1986 rootNav->releaseEntry();
1988 RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
1991 //----------------------------------------------------------------------
1993 static void buildListOfUsingDecls(EntryNav *rootNav)
1995 if (rootNav->section()==Entry::USINGDECL_SEC &&
1996 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1999 rootNav->loadEntry(g_storage);
2000 Entry *root = rootNav->entry();
2002 QCString name = substitute(root->name,".","::");
2004 if (g_usingDeclarations.find(name)==0)
2006 FileDef *fd = rootNav->fileDef();
2009 g_usingDeclarations.insert(name,fd);
2013 rootNav->releaseEntry();
2015 RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
2019 static void findUsingDeclarations(EntryNav *rootNav)
2021 if (rootNav->section()==Entry::USINGDECL_SEC &&
2022 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2025 rootNav->loadEntry(g_storage);
2026 Entry *root = rootNav->entry();
2028 //printf("Found using declaration %s at line %d of %s inside section %x\n",
2029 // root->name.data(),root->startLine,root->fileName.data(),
2030 // rootNav->parent()->section());
2031 if (!root->name.isEmpty())
2033 ClassDef *usingCd = 0;
2034 NamespaceDef *nd = 0;
2035 FileDef *fd = rootNav->fileDef();
2038 // see if the using statement was found inside a namespace or inside
2039 // the global file scope.
2040 if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
2042 scName=rootNav->parent()->name();
2043 if (!scName.isEmpty())
2045 nd = getResolvedNamespace(scName);
2049 // Assume the using statement was used to import a class.
2050 // Find the scope in which the `using' namespace is defined by prepending
2051 // the possible scopes in which the using statement was found, starting
2052 // with the most inner scope and going to the most outer scope (i.e.
2055 QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2056 usingCd = getClass(name); // try direct lookup first, this is needed to get
2057 // builtin STL classes to properly resolve, e.g.
2058 // vector -> std::vector
2061 usingCd = getResolvedClass(nd,fd,name); // try via resolving (see also bug757509)
2065 usingCd = Doxygen::hiddenClasses->find(name); // check if it is already hidden
2068 //printf("%s -> %p\n",root->name.data(),usingCd);
2069 if (usingCd==0) // definition not in the input => add an artificial class
2071 Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
2072 qPrint(name),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
2073 usingCd = new ClassDef(
2077 Doxygen::hiddenClasses->append(root->name,usingCd);
2078 usingCd->setArtificial(TRUE);
2079 usingCd->setLanguage(root->lang);
2083 Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",
2084 qPrint(usingCd->name()),
2085 nd?qPrint(nd->name()):
2086 fd?qPrint(fd->name()):
2092 //printf("Inside namespace %s\n",nd->name().data());
2093 nd->addUsingDeclaration(usingCd);
2097 //printf("Inside file %s\n",fd->name().data());
2098 fd->addUsingDeclaration(usingCd);
2102 rootNav->releaseEntry();
2104 RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
2107 //----------------------------------------------------------------------
2109 static void findUsingDeclImports(EntryNav *rootNav)
2111 if (rootNav->section()==Entry::USINGDECL_SEC &&
2112 (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
2115 //printf("Found using declaration %s inside section %x\n",
2116 // rootNav->name().data(), rootNav->parent()->section());
2117 QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
2118 fullName=stripAnonymousNamespaceScope(fullName);
2119 fullName=stripTemplateSpecifiersFromScope(fullName);
2120 ClassDef *cd = getClass(fullName);
2123 //printf("found class %s\n",cd->name().data());
2124 int i=rootNav->name().find("::");
2127 QCString scope=rootNav->name().left(i);
2128 QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
2129 ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2132 //printf("found class %s memName=%s\n",bcd->name().data(),memName.data());
2133 MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2136 MemberNameInfo *mni = mndict->find(memName);
2139 MemberNameInfoIterator mnii(*mni);
2141 for ( ; (mi=mnii.current()) ; ++mnii )
2143 MemberDef *md = mi->memberDef;
2144 if (md && md->protection()!=Private)
2147 rootNav->loadEntry(g_storage);
2148 Entry *root = rootNav->entry();
2150 //printf("found member %s\n",mni->memberName());
2151 MemberDef *newMd = 0;
2153 QCString fileName = root->fileName;
2154 if (fileName.isEmpty() && rootNav->tagInfo())
2156 fileName = rootNav->tagInfo()->tagName;
2158 ArgumentList *templAl = md->templateArguments();
2159 ArgumentList *al = md->templateArguments();
2160 newMd = new MemberDef(
2161 fileName,root->startLine,root->startColumn,
2162 md->typeString(),memName,md->argsString(),
2163 md->excpString(),root->protection,root->virt,
2164 md->isStatic(),Member,md->memberType(),
2168 newMd->setMemberClass(cd);
2169 cd->insertMember(newMd);
2170 if (!root->doc.isEmpty() || !root->brief.isEmpty())
2172 newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2173 newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2174 newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2178 newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2179 newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2180 newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2182 newMd->setDefinition(md->definition());
2183 newMd->enableCallGraph(root->callGraph);
2184 newMd->enableCallerGraph(root->callerGraph);
2185 newMd->setBitfields(md->bitfieldString());
2186 newMd->addSectionsToDefinition(root->anchors);
2187 newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2188 newMd->setBodyDef(md->getBodyDef());
2189 newMd->setInitializer(md->initializer());
2190 newMd->setMaxInitLines(md->initializerLines());
2191 newMd->setMemberGroupId(root->mGrpId);
2192 newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2193 newMd->setLanguage(root->lang);
2194 newMd->setId(root->id);
2196 rootNav->releaseEntry();
2206 RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2209 //----------------------------------------------------------------------
2211 static void findIncludedUsingDirectives()
2213 // first mark all files as not visited
2214 FileNameListIterator fnli(*Doxygen::inputNameList);
2216 for (fnli.toFirst();(fn=fnli.current());++fnli)
2218 FileNameIterator fni(*fn);
2220 for (;(fd=fni.current());++fni)
2225 // then recursively add using directives found in #include files
2226 // to files that have not been visited.
2227 for (fnli.toFirst();(fn=fnli.current());++fnli)
2229 FileNameIterator fni(*fn);
2231 for (fni.toFirst();(fd=fni.current());++fni)
2235 //printf("----- adding using directives for file %s\n",fd->name().data());
2236 fd->addIncludedUsingDirectives();
2242 //----------------------------------------------------------------------
2244 static MemberDef *addVariableToClass(
2248 const QCString &name,
2250 MemberDef *fromAnnMemb,
2252 Relationship related)
2254 Entry *root = rootNav->entry();
2256 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2257 QCString scopeSeparator="::";
2258 SrcLangExt lang = cd->getLanguage();
2259 if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2261 qualScope = substitute(qualScope,"::",".");
2264 Debug::print(Debug::Variables,0,
2265 " class variable:\n"
2266 " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2273 qPrint(root->initializer)
2277 if (!root->type.isEmpty())
2279 if (related || mtype==MemberType_Friend || Config_getBool(HIDE_SCOPE_NAMES))
2281 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2283 def="using "+name+" = "+root->type.mid(7);
2287 def=root->type+" "+name+root->args;
2292 if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2294 def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2298 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2304 if (Config_getBool(HIDE_SCOPE_NAMES))
2306 def=name+root->args;
2310 def=qualScope+scopeSeparator+name+root->args;
2313 def.stripPrefix("static ");
2315 // see if the member is already found in the same scope
2316 // (this may be the case for a static member that is initialized
2317 // outside the class)
2318 MemberName *mn=Doxygen::memberNameSDict->find(name);
2321 MemberNameIterator mni(*mn);
2323 for (mni.toFirst();(md=mni.current());++mni)
2325 //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2326 // md->getClassDef(),cd,root->type.data(),md->typeString());
2327 if (md->getClassDef()==cd &&
2328 removeRedundantWhiteSpace(root->type)==md->typeString())
2329 // member already in the scope
2332 if (root->lang==SrcLangExt_ObjC &&
2333 root->mtype==Property &&
2334 md->memberType()==MemberType_Variable)
2335 { // Objective-C 2.0 property
2336 // turn variable into a property
2337 md->setProtection(root->protection);
2338 cd->reclassifyMember(md,MemberType_Property);
2340 addMemberDocs(rootNav,md,def,0,FALSE);
2341 //printf(" Member already found!\n");
2347 QCString fileName = root->fileName;
2348 if (fileName.isEmpty() && rootNav->tagInfo())
2350 fileName = rootNav->tagInfo()->tagName;
2353 // new member variable, typedef or enum value
2354 MemberDef *md=new MemberDef(
2355 fileName,root->startLine,root->startColumn,
2356 root->type,name,root->args,root->exception,
2357 prot,Normal,root->stat,related,
2358 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2359 md->setTagInfo(rootNav->tagInfo());
2360 md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2361 //md->setDefFile(root->fileName);
2362 //md->setDefLine(root->startLine);
2363 md->setDocumentation(root->doc,root->docFile,root->docLine);
2364 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2365 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2366 md->setDefinition(def);
2367 md->setBitfields(root->bitfields);
2368 md->addSectionsToDefinition(root->anchors);
2369 md->setFromAnonymousScope(fromAnnScope);
2370 md->setFromAnonymousMember(fromAnnMemb);
2371 //md->setIndentDepth(indentDepth);
2372 md->setBodySegment(root->bodyLine,root->endBodyLine);
2373 md->setInitializer(root->initializer);
2374 md->setMaxInitLines(root->initLines);
2375 md->setMemberGroupId(root->mGrpId);
2376 md->setMemberSpecifiers(root->spec);
2377 md->setReadAccessor(root->read);
2378 md->setWriteAccessor(root->write);
2379 md->enableCallGraph(root->callGraph);
2380 md->enableCallerGraph(root->callerGraph);
2381 md->setHidden(root->hidden);
2382 md->setArtificial(root->artificial);
2383 md->setLanguage(root->lang);
2384 md->setId(root->id);
2385 addMemberToGroups(root,md);
2386 //if (root->mGrpId!=-1)
2388 // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2389 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
2391 md->setBodyDef(rootNav->fileDef());
2393 //printf(" Adding member=%s\n",md->name().data());
2394 // add the member to the global list
2399 else // new variable name
2401 mn = new MemberName(name);
2403 //printf("Adding memberName=%s\n",mn->memberName());
2404 //Doxygen::memberNameDict.insert(name,mn);
2405 //Doxygen::memberNameList.append(mn);
2406 Doxygen::memberNameSDict->append(name,mn);
2407 // add the member to the class
2409 //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd);
2410 cd->insertMember(md);
2411 md->setRefItems(root->sli);
2413 //TODO: insert FileDef instead of filename strings.
2414 cd->insertUsedFile(rootNav->fileDef());
2415 rootNav->changeSection(Entry::EMPTY_SEC);
2419 //----------------------------------------------------------------------
2421 static MemberDef *addVariableToFile(
2424 const QCString &scope,
2425 const QCString &name,
2427 /*int indentDepth,*/
2428 MemberDef *fromAnnMemb)
2430 Entry *root = rootNav->entry();
2431 Debug::print(Debug::Variables,0,
2432 " global variable:\n"
2433 " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2443 FileDef *fd = rootNav->fileDef();
2445 // see if we have a typedef that should hide a struct or union
2446 if (mtype==MemberType_Typedef && Config_getBool(TYPEDEF_HIDES_STRUCT))
2448 QCString type = root->type;
2449 type.stripPrefix("typedef ");
2450 if (type.left(7)=="struct " || type.left(6)=="union ")
2452 type.stripPrefix("struct ");
2453 type.stripPrefix("union ");
2454 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2456 s = re.match(type,0,&l);
2459 QCString typeValue = type.mid(s,l);
2460 ClassDef *cd = getClass(typeValue);
2463 // this typedef should hide compound name cd, so we
2464 // change the name that is displayed from cd.
2465 cd->setClassName(name);
2466 cd->setDocumentation(root->doc,root->docFile,root->docLine);
2467 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2474 // see if the function is inside a namespace
2475 NamespaceDef *nd = 0;
2476 if (!scope.isEmpty())
2478 if (scope.find('@')!=-1) return 0; // anonymous scope!
2479 //nscope=removeAnonymousScopes(scope);
2480 //if (!nscope.isEmpty())
2482 nd = getResolvedNamespace(scope);
2487 // determine the definition of the global variable
2488 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' &&
2489 !Config_getBool(HIDE_SCOPE_NAMES)
2491 // variable is inside a namespace, so put the scope before the name
2493 SrcLangExt lang = nd->getLanguage();
2494 QCString sep=getLanguageSpecificSeparator(lang);
2496 if (!root->type.isEmpty())
2498 if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2500 def="using "+nd->name()+sep+name+" = "+root->type;
2502 else // normal member
2504 def=root->type+" "+nd->name()+sep+name+root->args;
2509 def=nd->name()+sep+name+root->args;
2514 if (!root->type.isEmpty() && !root->name.isEmpty())
2516 if (name.at(0)=='@') // dummy variable representing anonymous union
2522 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2524 def="using "+root->name+" = "+root->type.mid(7);
2526 else // normal member
2528 def=root->type+" "+name+root->args;
2534 def=name+root->args;
2537 def.stripPrefix("static ");
2539 MemberName *mn=Doxygen::functionNameSDict->find(name);
2542 //QCString nscope=removeAnonymousScopes(scope);
2543 //NamespaceDef *nd=0;
2544 //if (!nscope.isEmpty())
2545 if (!scope.isEmpty())
2547 nd = getResolvedNamespace(scope);
2549 MemberNameIterator mni(*mn);
2551 for (mni.toFirst();(md=mni.current());++mni)
2554 ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2555 root->fileName==md->getFileDef()->absFilePath()
2556 ) // both variable names in the same file
2557 || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2559 && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2560 && !md->isEnumerate() // in C# an enum value and enum can have the same name
2562 // variable already in the scope
2564 bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2565 md->argsString()!=root->args &&
2566 root->args.find('[')!=-1;
2567 bool staticsInDifferentFiles =
2568 root->stat && md->isStatic() &&
2569 root->fileName!=md->getDefFileName();
2571 if (md->getFileDef() &&
2572 !isPHPArray && // not a php array
2573 !staticsInDifferentFiles
2575 // not a php array variable
2578 Debug::print(Debug::Variables,0,
2579 " variable already found: scope=%s\n",qPrint(md->getOuterScope()->name()));
2580 addMemberDocs(rootNav,md,def,0,FALSE);
2581 md->setRefItems(root->sli);
2588 QCString fileName = root->fileName;
2589 if (fileName.isEmpty() && rootNav->tagInfo())
2591 fileName = rootNav->tagInfo()->tagName;
2594 Debug::print(Debug::Variables,0,
2595 " new variable, nd=%s tagInfo=%p!\n",nd?qPrint(nd->name()):"<global>",rootNav->tagInfo());
2596 // new global variable, enum value or typedef
2597 MemberDef *md=new MemberDef(
2598 fileName,root->startLine,root->startColumn,
2599 root->type,name,root->args,0,
2600 root->protection, Normal,root->stat,Member,
2601 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0);
2602 md->setTagInfo(rootNav->tagInfo());
2603 md->setMemberSpecifiers(root->spec);
2604 md->setDocumentation(root->doc,root->docFile,root->docLine);
2605 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2606 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2607 md->addSectionsToDefinition(root->anchors);
2608 md->setFromAnonymousScope(fromAnnScope);
2609 md->setFromAnonymousMember(fromAnnMemb);
2610 md->setInitializer(root->initializer);
2611 md->setMaxInitLines(root->initLines);
2612 md->setMemberGroupId(root->mGrpId);
2613 md->setDefinition(def);
2614 md->setLanguage(root->lang);
2615 md->setId(root->id);
2616 md->enableCallGraph(root->callGraph);
2617 md->enableCallerGraph(root->callerGraph);
2618 md->setExplicitExternal(root->explicitExternal);
2619 //md->setOuterScope(fd);
2620 if (!root->explicitExternal)
2622 md->setBodySegment(root->bodyLine,root->endBodyLine);
2625 addMemberToGroups(root,md);
2627 md->setRefItems(root->sli);
2628 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2630 md->setNamespace(nd);
2631 nd->insertMember(md);
2634 // add member to the file (we do this even if we have already inserted
2635 // it into the namespace.
2639 fd->insertMember(md);
2642 // add member definition to the list of globals
2649 mn = new MemberName(name);
2651 Doxygen::functionNameSDict->append(name,mn);
2653 rootNav->changeSection(Entry::EMPTY_SEC);
2657 /*! See if the return type string \a type is that of a function pointer
2658 * \returns -1 if this is not a function pointer variable or
2659 * the index at which the closing brace of (...*name) was found.
2661 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2663 if (lang == SrcLangExt_Fortran || lang == SrcLangExt_VHDL)
2665 return -1; // Fortran and VHDL do not have function pointers
2667 static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2669 int bb=type.find('<');
2670 int be=type.findRev('>');
2671 if (!type.isEmpty() && // return type is non-empty
2672 (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2673 type.find("operator")==-1 && // not an operator
2674 (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2675 // not a function pointer return type
2676 !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2679 if (pLength) *pLength=l;
2680 //printf("findFunctionPtr=%d\n",i);
2685 //printf("findFunctionPtr=%d\n",-1);
2691 /*! Returns TRUE iff \a type is a class within scope \a context.
2692 * Used to detect variable declarations that look like function prototypes.
2694 static bool isVarWithConstructor(EntryNav *rootNav)
2696 static QRegExp initChars("[0-9\"'&*!^]+");
2697 static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2701 Definition *ctx = 0;
2705 //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2706 rootNav->loadEntry(g_storage);
2707 Entry *root = rootNav->entry();
2709 if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2714 else if ((fd = rootNav->fileDef()) &&
2715 (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2717 { // inside a .c file
2721 if (root->type.isEmpty())
2726 if (!rootNav->parent()->name().isEmpty())
2728 ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2731 // remove qualifiers
2732 findAndRemoveWord(type,"const");
2733 findAndRemoveWord(type,"static");
2734 findAndRemoveWord(type,"volatile");
2735 //if (type.left(6)=="const ") type=type.right(type.length()-6);
2736 typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2737 if (!typeIsClass && (ti=type.find('<'))!=-1)
2739 typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2741 if (typeIsClass) // now we still have to check if the arguments are
2742 // types or values. Since we do not have complete type info
2743 // we need to rely on heuristics :-(
2745 //printf("typeIsClass\n");
2746 ArgumentList *al = root->argList;
2747 if (al==0 || al->isEmpty())
2749 result=FALSE; // empty arg list -> function prototype.
2752 ArgumentListIterator ali(*al);
2754 for (ali.toFirst();(a=ali.current());++ali)
2756 if (!a->name.isEmpty() || !a->defval.isEmpty())
2758 if (a->name.find(initChars)==0)
2764 result=FALSE; // arg has (type,name) pair -> function prototype
2768 if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0)
2770 result=FALSE; // arg type is a known type
2773 if (checkIfTypedef(ctx,fd,a->type))
2775 //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2776 result=FALSE; // argument is a typedef
2779 if (a->type.at(a->type.length()-1)=='*' ||
2780 a->type.at(a->type.length()-1)=='&')
2781 // type ends with * or & => pointer or reference
2786 if (a->type.find(initChars)==0)
2788 result=TRUE; // argument type starts with typical initializer char
2791 QCString resType=resolveTypeDef(ctx,a->type);
2792 if (resType.isEmpty()) resType=a->type;
2794 if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2796 resType=resType.left(len);
2797 //printf("resType=%s\n",resType.data());
2798 if (resType=="int" || resType=="long" || resType=="float" ||
2799 resType=="double" || resType=="char" || resType=="signed" ||
2800 resType=="const" || resType=="unsigned" || resType=="void")
2802 result=FALSE; // type keyword -> function prototype
2811 //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2812 // root->type.data(),result);
2813 rootNav->releaseEntry();
2817 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2819 rootNav->loadEntry(g_storage);
2820 Entry *root = rootNav->entry();
2822 Debug::print(Debug::Variables,0,
2824 " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2830 qPrint(root->relates)
2832 //printf("root->parent->name=%s\n",root->parent->name.data());
2834 if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2835 (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2837 // recover from parse error caused by redundant braces
2838 // like in "int *(var[10]);", which is parsed as
2839 // type="" name="int *" args="(var[10])"
2841 root->type=root->name;
2842 static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2844 int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2847 root->name=root->args.mid(i,l);
2848 root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2850 //printf("new: type=`%s' name=`%s' args=`%s'\n",
2851 // root->type.data(),root->name.data(),root->args.data());
2856 if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2857 Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no");
2858 if (i!=-1) // function pointer
2860 int ai = root->type.find('[',i);
2861 if (ai>i) // function pointer array
2863 root->args.prepend(root->type.right(root->type.length()-ai));
2864 root->type=root->type.left(ai);
2866 else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2868 root->type=root->type.left(root->type.length()-1);
2869 root->args.prepend(") ");
2870 //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2875 QCString scope,name=removeRedundantWhiteSpace(root->name);
2877 // find the scope of this variable
2878 EntryNav *p = rootNav->parent();
2879 while ((p->section() & Entry::SCOPE_MASK))
2881 QCString scopeName = p->name();
2882 if (!scopeName.isEmpty())
2884 scope.prepend(scopeName);
2891 QCString type=root->type.stripWhiteSpace();
2893 bool isRelated=FALSE;
2894 bool isMemberOf=FALSE;
2896 QCString classScope=stripAnonymousNamespaceScope(scope);
2897 classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2898 QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2900 if (root->name.findRev("::")!=-1)
2902 if (root->type=="friend class" || root->type=="friend struct" ||
2903 root->type=="friend union")
2908 addVariableToClass(rootNav, // entry
2909 cd, // class to add member to
2910 MemberType_Friend, // type of member
2911 name, // name of the member
2912 FALSE, // from Anonymous scope
2913 0, // anonymous member
2914 Public, // protection
2915 Member // related to a class
2920 /* skip this member, because it is a
2921 * static variable definition (always?), which will be
2922 * found in a class scope as well, but then we know the
2923 * correct protection level, so only then it will be
2924 * inserted in the correct list!
2929 mtype=MemberType_EnumValue;
2930 else if (type.left(8)=="typedef ")
2931 mtype=MemberType_Typedef;
2932 else if (type.left(7)=="friend ")
2933 mtype=MemberType_Friend;
2934 else if (root->mtype==Property)
2935 mtype=MemberType_Property;
2936 else if (root->mtype==Event)
2937 mtype=MemberType_Event;
2939 mtype=MemberType_Variable;
2941 if (!root->relates.isEmpty()) // related variable
2944 isMemberOf=(root->relatesType == MemberOf);
2945 if (getClass(root->relates)==0 && !scope.isEmpty())
2946 scope=mergeScopes(scope,root->relates);
2948 scope=root->relates;
2952 if (cd==0 && classScope!=scope) cd=getClass(classScope);
2957 // if cd is an anonymous (=tag less) scope we insert the member
2958 // into a non-anonymous parent scope as well. This is needed to
2959 // be able to refer to it using \var or \fn
2961 //int indentDepth=0;
2962 int si=scope.find('@');
2963 //int anonyScopes = 0;
2966 static bool inlineSimpleStructs = Config_getBool(INLINE_SIMPLE_STRUCTS);
2967 if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2971 pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2972 if (!pScope.isEmpty())
2973 pScope.prepend(annScopePrefix);
2974 else if (annScopePrefix.length()>2)
2975 pScope=annScopePrefix.left(annScopePrefix.length()-2);
2976 if (name.at(0)!='@')
2978 if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2980 md=addVariableToClass(rootNav, // entry
2981 pcd, // class to add member to
2982 mtype, // member type
2983 name, // member name
2984 TRUE, // from anonymous scope
2985 0, // from anonymous member
2987 isMemberOf ? Foreign : isRelated ? Related : Member
2991 else // anonymous scope inside namespace or file => put variable in the global scope
2993 if (mtype==MemberType_Variable)
2995 md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0);
3002 //printf("name=`%s' scope=%s scope.right=%s\n",
3003 // name.data(),scope.data(),
3004 // scope.right(scope.length()-si).data());
3005 addVariableToClass(rootNav, // entry
3006 cd, // class to add member to
3007 mtype, // member type
3008 name, // name of the member
3009 FALSE, // from anonymous scope
3010 md, // from anonymous member
3012 isMemberOf ? Foreign : isRelated ? Related : Member);
3014 else if (!name.isEmpty()) // global variable
3016 //printf("Inserting member in global scope %s!\n",scope.data());
3017 addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
3021 rootNav->releaseEntry();
3024 //----------------------------------------------------------------------
3025 // Searches the Entry tree for typedef documentation sections.
3026 // If found they are stored in their class or in the global list.
3027 static void buildTypedefList(EntryNav *rootNav)
3029 //printf("buildVarList(%s)\n",rootNav->name().data());
3030 if (!rootNav->name().isEmpty() &&
3031 rootNav->section()==Entry::VARIABLE_SEC &&
3032 rootNav->type().find("typedef ")!=-1 // its a typedef
3035 addVariable(rootNav);
3037 if (rootNav->children())
3039 EntryNavListIterator eli(*rootNav->children());
3041 for (;(e=eli.current());++eli)
3043 if (e->section()!=Entry::ENUM_SEC)
3045 buildTypedefList(e);
3051 //----------------------------------------------------------------------
3052 // Searches the Entry tree for Variable documentation sections.
3053 // If found they are stored in their class or in the global list.
3055 static void buildVarList(EntryNav *rootNav)
3057 //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
3059 if (!rootNav->name().isEmpty() &&
3060 (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
3062 (rootNav->section()==Entry::VARIABLE_SEC // it's a variable
3064 (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable
3065 (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
3067 (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
3068 isVarWithConstructor(rootNav)
3071 ) // documented variable
3073 addVariable(rootNav,isFuncPtr);
3075 if (rootNav->children())
3077 EntryNavListIterator eli(*rootNav->children());
3079 for (;(e=eli.current());++eli)
3081 if (e->section()!=Entry::ENUM_SEC)
3089 //----------------------------------------------------------------------
3090 // Searches the Entry tree for Interface sections (UNO IDL only).
3091 // If found they are stored in their service or in the global list.
3094 static void addInterfaceOrServiceToServiceOrSingleton(
3095 EntryNav *const rootNav,
3097 QCString const& rname)
3099 Entry *const root = rootNav->entry();
3100 FileDef *const fd = rootNav->fileDef();
3101 enum MemberType const type = (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC)
3102 ? MemberType_Interface
3103 : MemberType_Service;
3104 QCString fileName = root->fileName;
3105 if (fileName.isEmpty() && rootNav->tagInfo())
3107 fileName = rootNav->tagInfo()->tagName;
3109 MemberDef *const md = new MemberDef(
3110 fileName, root->startLine, root->startColumn, root->type, rname,
3111 "", "", root->protection, root->virt, root->stat, Member,
3112 type, 0, root->argList);
3113 md->setTagInfo(rootNav->tagInfo());
3114 md->setMemberClass(cd);
3115 md->setDocumentation(root->doc,root->docFile,root->docLine);
3116 md->setDocsForDefinition(false);
3117 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3118 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3119 md->setBodySegment(root->bodyLine,root->endBodyLine);
3120 md->setMemberSpecifiers(root->spec);
3121 md->setMemberGroupId(root->mGrpId);
3122 md->setTypeConstraints(root->typeConstr);
3123 md->setLanguage(root->lang);
3126 md->addSectionsToDefinition(root->anchors);
3127 QCString const def = root->type + " " + rname;
3128 md->setDefinition(def);
3129 md->enableCallGraph(root->callGraph);
3130 md->enableCallerGraph(root->callerGraph);
3132 Debug::print(Debug::Functions,0,
3133 " Interface Member:\n"
3134 " `%s' `%s' proto=%d\n"
3142 // add member to the global list of all members
3144 if ((mn=Doxygen::memberNameSDict->find(rname)))
3150 mn = new MemberName(rname);
3152 Doxygen::memberNameSDict->append(rname,mn);
3155 // add member to the class cd
3156 cd->insertMember(md);
3157 // also add the member as a "base" (to get nicer diagrams)
3158 // "optional" interface/service get Protected which turns into dashed line
3159 BaseInfo base(rname,
3160 (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3161 findClassRelation(rootNav,cd,cd,&base,0,DocumentedOnly,true)
3162 || findClassRelation(rootNav,cd,cd,&base,0,Undocumented,true);
3163 // add file to list of used files
3164 cd->insertUsedFile(fd);
3166 addMemberToGroups(root,md);
3167 rootNav->changeSection(Entry::EMPTY_SEC);
3168 md->setRefItems(root->sli);
3171 static void buildInterfaceAndServiceList(EntryNav *const rootNav)
3173 if (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
3174 rootNav->section()==Entry::INCLUDED_SERVICE_SEC)
3176 rootNav->loadEntry(g_storage);
3177 Entry *const root = rootNav->entry();
3179 Debug::print(Debug::Functions,0,
3180 "EXPORTED_INTERFACE_SEC:\n"
3181 " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3183 qPrint(rootNav->parent()->name()),
3186 qPrint(root->relates),
3188 qPrint(root->fileName),
3191 root->tArgLists ? (int)root->tArgLists->count() : -1,
3195 qPrint(root->docFile)
3198 QCString const rname = removeRedundantWhiteSpace(root->name);
3200 if (!rname.isEmpty())
3202 QCString const scope = rootNav->parent()->name();
3203 ClassDef *const cd = getClass(scope);
3205 if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3206 (ClassDef::Service == cd->compoundType()) ||
3207 (ClassDef::Singleton == cd->compoundType())))
3209 addInterfaceOrServiceToServiceOrSingleton(rootNav,cd,rname);
3213 assert(false); // was checked by scanner.l
3216 else if (rname.isEmpty())
3218 warn(root->fileName,root->startLine,
3219 "Illegal member name found.");
3222 rootNav->releaseEntry();
3224 // can only have these in IDL anyway
3225 switch (rootNav->lang())
3227 case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3228 case SrcLangExt_IDL:
3229 RECURSE_ENTRYTREE(buildInterfaceAndServiceList,rootNav);
3232 return; // nothing to do here
3237 //----------------------------------------------------------------------
3238 // Searches the Entry tree for Function sections.
3239 // If found they are stored in their class or in the global list.
3241 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
3242 const QCString &rname,bool isFriend)
3244 Entry *root = rootNav->entry();
3245 FileDef *fd=rootNav->fileDef();
3248 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3249 int ts=root->type.find('<');
3250 int te=root->type.findRev('>');
3251 int i=re.match(root->type,0,&l);
3252 if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
3257 if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3258 !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3260 root->args+=root->type.right(root->type.length()-i-l);
3261 root->type=root->type.left(i+l);
3264 QCString name=removeRedundantWhiteSpace(rname);
3265 if (name.left(2)=="::") name=name.right(name.length()-2);
3268 if (isFriend) mtype=MemberType_Friend;
3269 else if (root->mtype==Signal) mtype=MemberType_Signal;
3270 else if (root->mtype==Slot) mtype=MemberType_Slot;
3271 else if (root->mtype==DCOP) mtype=MemberType_DCOP;
3272 else mtype=MemberType_Function;
3274 // strip redundant template specifier for constructors
3275 if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3276 name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3281 QCString fileName = root->fileName;
3282 if (fileName.isEmpty() && rootNav->tagInfo())
3284 fileName = rootNav->tagInfo()->tagName;
3287 //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
3288 // root->name.data(),root->args.data(),argListToString(root->argList).data()
3291 // adding class member
3292 MemberDef *md=new MemberDef(
3293 fileName,root->startLine,root->startColumn,
3294 root->type,name,root->args,root->exception,
3295 root->protection,root->virt,
3296 root->stat && root->relatesType != MemberOf,
3297 root->relates.isEmpty() ? Member :
3298 root->relatesType == MemberOf ? Foreign : Related,
3299 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,root->argList);
3300 md->setTagInfo(rootNav->tagInfo());
3301 md->setMemberClass(cd);
3302 md->setDocumentation(root->doc,root->docFile,root->docLine);
3303 md->setDocsForDefinition(!root->proto);
3304 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3305 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3306 md->setBodySegment(root->bodyLine,root->endBodyLine);
3307 md->setMemberSpecifiers(root->spec);
3308 md->setMemberGroupId(root->mGrpId);
3309 md->setTypeConstraints(root->typeConstr);
3310 md->setLanguage(root->lang);
3311 md->setId(root->id);
3314 //md->setScopeTemplateArguments(root->tArgList);
3315 md->addSectionsToDefinition(root->anchors);
3317 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3318 SrcLangExt lang = cd->getLanguage();
3319 QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3320 if (scopeSeparator!="::")
3322 qualScope = substitute(qualScope,"::",scopeSeparator);
3324 if (lang==SrcLangExt_PHP)
3326 // for PHP we use Class::method and Namespace\method
3327 scopeSeparator="::";
3329 if (!root->relates.isEmpty() || isFriend || Config_getBool(HIDE_SCOPE_NAMES))
3331 if (!root->type.isEmpty())
3335 def=root->type+" "+name;
3339 def=root->type+" "+name+root->args;
3350 def=name+root->args;
3356 if (!root->type.isEmpty())
3360 def=root->type+" "+qualScope+scopeSeparator+name;
3364 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3371 def=qualScope+scopeSeparator+name;
3375 def=qualScope+scopeSeparator+name+root->args;
3379 if (def.left(7)=="friend ") def=def.right(def.length()-7);
3380 md->setDefinition(def);
3381 md->enableCallGraph(root->callGraph);
3382 md->enableCallerGraph(root->callerGraph);
3384 Debug::print(Debug::Functions,0,
3386 " `%s' `%s'::`%s' `%s' proto=%d\n"
3396 // add member to the global list of all members
3397 //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3399 if ((mn=Doxygen::memberNameSDict->find(name)))
3405 mn = new MemberName(name);
3407 Doxygen::memberNameSDict->append(name,mn);
3410 // add member to the class cd
3411 cd->insertMember(md);
3412 // add file to list of used files
3413 cd->insertUsedFile(fd);
3415 addMemberToGroups(root,md);
3416 rootNav->changeSection(Entry::EMPTY_SEC);
3417 md->setRefItems(root->sli);
3421 static void buildFunctionList(EntryNav *rootNav)
3423 if (rootNav->section()==Entry::FUNCTION_SEC)
3425 rootNav->loadEntry(g_storage);
3426 Entry *root = rootNav->entry();
3428 Debug::print(Debug::Functions,0,
3430 " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3432 qPrint(rootNav->parent()->name()),
3435 qPrint(root->relates),
3437 qPrint(root->fileName),
3440 root->tArgLists ? (int)root->tArgLists->count() : -1,
3444 qPrint(root->docFile)
3447 bool isFriend=root->type.find("friend ")!=-1;
3448 QCString rname = removeRedundantWhiteSpace(root->name);
3449 //printf("rname=%s\n",rname.data());
3451 QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3452 if (!rname.isEmpty() && scope.find('@')==-1)
3455 // check if this function's parent is a class
3456 scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3458 FileDef *rfd=rootNav->fileDef();
3460 int memIndex=rname.findRev("::");
3463 if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3465 // strip scope from name
3466 rname=rname.right(rname.length()-rootNav->parent()->name().length()-2);
3469 NamespaceDef *nd = 0;
3470 bool isMember=FALSE;
3473 int ts=rname.find('<');
3474 int te=rname.find('>');
3475 if (memIndex>0 && (ts==-1 || te==-1))
3477 // note: the following code was replaced by inMember=TRUE to deal with a
3478 // function rname='X::foo' of class X inside a namespace also called X...
3480 //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3484 // // strip namespace scope from name
3485 // scope=rname.left(memIndex);
3486 // rname=rname.right(rname.length()-memIndex-2);
3492 isMember=memIndex<ts || memIndex>te;
3496 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3497 int ts=root->type.find('<');
3498 int te=root->type.findRev('>');
3500 if (!rootNav->parent()->name().isEmpty() &&
3501 (rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
3503 // do some fuzzy things to exclude function pointers
3504 (root->type.isEmpty() ||
3505 ((ti=root->type.find(re,0))==-1 || // type does not contain ..(..*
3506 (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3507 root->args.find(")[")!=-1) || // and args not )[.. -> function pointer
3508 root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3509 cd->getLanguage()!=SrcLangExt_Cpp // language other than C
3513 Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
3514 qPrint(rname),qPrint(cd->name()));
3515 addMethodToClass(rootNav,cd,rname,isFriend);
3517 else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK)
3518 || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3521 (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3522 root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3524 // no member => unrelated function
3526 /* check the uniqueness of the function name in the file.
3527 * A file could contain a function prototype and a function definition
3528 * or even multiple function prototypes.
3533 if ((mn=Doxygen::functionNameSDict->find(rname)))
3535 Debug::print(Debug::Functions,0," --> function %s already found!\n",qPrint(rname));
3536 MemberNameIterator mni(*mn);
3537 for (mni.toFirst();(!found && (md=mni.current()));++mni)
3539 NamespaceDef *mnd = md->getNamespaceDef();
3540 NamespaceDef *rnd = 0;
3541 //printf("root namespace=%s\n",rootNav->parent()->name().data());
3542 QCString fullScope = scope;
3543 QCString parentScope = rootNav->parent()->name();
3544 if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3546 if (!scope.isEmpty()) fullScope.prepend("::");
3547 fullScope.prepend(parentScope);
3549 //printf("fullScope=%s\n",fullScope.data());
3550 rnd = getResolvedNamespace(fullScope);
3551 FileDef *mfd = md->getFileDef();
3552 QCString nsName,rnsName;
3553 if (mnd) nsName = mnd->name().copy();
3554 if (rnd) rnsName = rnd->name().copy();
3555 //printf("matching arguments for %s%s %s%s\n",
3556 // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3557 ArgumentList *mdAl = md->argumentList();
3558 ArgumentList *mdTempl = md->templateArguments();
3560 // in case of template functions, we need to check if the
3561 // functions have the same number of template parameters
3562 bool sameNumTemplateArgs = TRUE;
3563 bool matchingReturnTypes = TRUE;
3564 if (mdTempl!=0 && root->tArgLists)
3566 if (mdTempl->count()!=root->tArgLists->getLast()->count())
3568 sameNumTemplateArgs = FALSE;
3570 if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3572 matchingReturnTypes = FALSE;
3576 bool staticsInDifferentFiles =
3577 root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3580 matchArguments2(md->getOuterScope(),mfd,mdAl,
3581 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3583 sameNumTemplateArgs &&
3584 matchingReturnTypes &&
3585 !staticsInDifferentFiles
3589 if (root->groups->getFirst()!=0)
3591 gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
3593 //printf("match!\n");
3594 //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3595 // see if we need to create a new member
3596 found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace
3597 ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and
3598 mfd->absFilePath()==root->fileName // prototype in the same file
3601 // otherwise, allow a duplicate global member with the same argument list
3602 if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3604 // member is already in the group, so we don't want to add it again.
3608 //printf("combining function with prototype found=%d in namespace %s\n",
3609 // found,nsName.data());
3613 // merge argument lists
3614 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
3615 // merge documentation
3616 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3618 ArgumentList *argList = new ArgumentList;
3619 stringToArgumentList(root->args,argList);
3622 //printf("setDeclArgumentList to %p\n",argList);
3623 md->setDeclArgumentList(argList);
3627 md->setArgumentList(argList);
3631 md->setDocumentation(root->doc,root->docFile,root->docLine);
3632 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3633 md->setDocsForDefinition(!root->proto);
3634 if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3636 md->setBodySegment(root->bodyLine,root->endBodyLine);
3637 md->setBodyDef(rfd);
3640 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3642 md->setArgsString(root->args);
3644 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3646 md->addSectionsToDefinition(root->anchors);
3648 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3649 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3651 // merge ingroup specifiers
3652 if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
3654 addMemberToGroups(root,md);
3656 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3658 //printf("existing member is grouped, new member not\n");
3659 root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3661 else if (md->getGroupDef()!=0 && root->groups->getFirst()!=0)
3663 //printf("both members are grouped\n");
3666 // if md is a declaration and root is the corresponding
3667 // definition, then turn md into a definition.
3668 if (md->isPrototype() && !root->proto)
3670 md->setPrototype(FALSE);
3676 if (!found) /* global function is unique with respect to the file */
3678 Debug::print(Debug::Functions,0," --> new function %s found!\n",qPrint(rname));
3679 //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3680 // root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3682 // new global function
3683 ArgumentList *tArgList = root->tArgLists ? root->tArgLists->getLast() : 0;
3684 QCString name=removeRedundantWhiteSpace(rname);
3686 root->fileName,root->startLine,root->startColumn,
3687 root->type,name,root->args,root->exception,
3688 root->protection,root->virt,root->stat,Member,
3689 MemberType_Function,tArgList,root->argList);
3691 md->setTagInfo(rootNav->tagInfo());
3692 md->setLanguage(root->lang);
3693 md->setId(root->id);
3694 //md->setDefFile(root->fileName);
3695 //md->setDefLine(root->startLine);
3696 md->setDocumentation(root->doc,root->docFile,root->docLine);
3697 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3698 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3699 md->setPrototype(root->proto);
3700 md->setDocsForDefinition(!root->proto);
3701 md->setTypeConstraints(root->typeConstr);
3702 //md->setBody(root->body);
3703 md->setBodySegment(root->bodyLine,root->endBodyLine);
3704 FileDef *fd=rootNav->fileDef();
3706 md->addSectionsToDefinition(root->anchors);
3707 md->setMemberSpecifiers(root->spec);
3708 md->setMemberGroupId(root->mGrpId);
3710 // see if the function is inside a namespace that was not part of
3711 // the name already (in that case nd should be non-zero already)
3712 if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3714 //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3715 QCString nscope=rootNav->parent()->name();
3716 if (!nscope.isEmpty())
3718 nd = getResolvedNamespace(nscope);
3722 if (!scope.isEmpty())
3724 QCString sep = getLanguageSpecificSeparator(root->lang);
3727 scope = substitute(scope,"::",sep);
3733 if (!root->type.isEmpty())
3737 def=root->type+" "+scope+name;
3741 def=root->type+" "+scope+name+root->args;
3748 def=scope+name.copy();
3752 def=scope+name+root->args;
3755 Debug::print(Debug::Functions,0,
3756 " Global Function:\n"
3757 " `%s' `%s'::`%s' `%s' proto=%d\n"
3760 qPrint(rootNav->parent()->name()),
3766 md->setDefinition(def);
3767 md->enableCallGraph(root->callGraph);
3768 md->enableCallerGraph(root->callerGraph);
3769 //if (root->mGrpId!=-1)
3771 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
3774 md->setRefItems(root->sli);
3775 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3777 // add member to namespace
3778 md->setNamespace(nd);
3779 nd->insertMember(md);
3783 // add member to the file (we do this even if we have already
3784 // inserted it into the namespace)
3786 fd->insertMember(md);
3789 // add member to the list of file members
3790 //printf("Adding member=%s\n",md->name().data());
3792 if ((mn=Doxygen::functionNameSDict->find(name)))
3798 mn = new MemberName(name);
3800 Doxygen::functionNameSDict->append(name,mn);
3802 addMemberToGroups(root,md);
3803 if (root->relatesType == Simple) // if this is a relatesalso command,
3804 // allow find Member to pick it up
3806 rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished
3813 FileDef *fd=rootNav->fileDef();
3816 // add member to the file (we do this even if we have already
3817 // inserted it into the namespace)
3818 fd->insertMember(md);
3822 //printf("unrelated function %d `%s' `%s' `%s'\n",
3823 // root->parent->section,root->type.data(),rname.data(),root->args.data());
3827 Debug::print(Debug::Functions,0," --> %s not processed!\n",qPrint(rname));
3830 else if (rname.isEmpty())
3832 warn(root->fileName,root->startLine,
3833 "Illegal member name found."
3837 rootNav->releaseEntry();
3839 RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3842 //----------------------------------------------------------------------
3844 static void findFriends()
3846 //printf("findFriends()\n");
3847 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3849 for (;(fn=fnli.current());++fnli) // for each global function name
3851 //printf("Function name=`%s'\n",fn->memberName());
3853 if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3854 { // there are members with the same name
3855 //printf("Function name is also a member name\n");
3856 MemberNameIterator fni(*fn);
3858 for (;(fmd=fni.current());++fni) // for each function with that name
3860 MemberNameIterator mni(*mn);
3862 for (;(mmd=mni.current());++mni) // for each member with that name
3864 //printf("Checking for matching arguments
3865 // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3866 // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3867 ArgumentList *mmdAl = mmd->argumentList();
3868 ArgumentList *fmdAl = fmd->argumentList();
3869 if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3870 matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl,
3871 fmd->getOuterScope(), fmd->getFileDef(), fmdAl,
3875 ) // if the member is related and the arguments match then the
3876 // function is actually a friend.
3878 mergeArguments(mmdAl,fmdAl);
3879 if (!fmd->documentation().isEmpty())
3881 mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3883 else if (!mmd->documentation().isEmpty())
3885 fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3887 if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3889 mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3891 else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3893 fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3895 if (!fmd->inbodyDocumentation().isEmpty())
3897 mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3899 else if (!mmd->inbodyDocumentation().isEmpty())
3901 fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3903 //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3904 if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3906 mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3907 mmd->setBodyDef(fmd->getBodyDef());
3908 //mmd->setBodyMember(fmd);
3910 else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3912 fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3913 fmd->setBodyDef(mmd->getBodyDef());
3914 //fmd->setBodyMember(mmd);
3916 mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3918 mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3919 mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3920 fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3921 fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3929 //----------------------------------------------------------------------
3931 static void transferFunctionDocumentation()
3933 //printf("---- transferFunctionDocumentation()\n");
3935 // find matching function declaration and definitions.
3936 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3938 for (;(mn=mnli.current());++mnli)
3940 //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3941 MemberDef *mdef=0,*mdec=0;
3942 MemberNameIterator mni1(*mn);
3943 /* find a matching function declaration and definition for this function */
3944 for (;(mdec=mni1.current());++mni1)
3946 if (mdec->isPrototype() ||
3947 (mdec->isVariable() && mdec->isExternal())
3950 MemberNameIterator mni2(*mn);
3951 for (;(mdef=mni2.current());++mni2)
3953 combineDeclarationAndDefinition(mdec,mdef);
3960 //----------------------------------------------------------------------
3962 static void transferFunctionReferences()
3964 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3966 for (;(mn=mnli.current());++mnli)
3968 MemberDef *md,*mdef=0,*mdec=0;
3969 MemberNameIterator mni(*mn);
3970 /* find a matching function declaration and definition for this function */
3971 for (;(md=mni.current());++mni)
3973 if (md->isPrototype())
3975 else if (md->isVariable() && md->isExternal())
3978 if (md->isFunction() && !md->isStatic() && !md->isPrototype())
3980 else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3985 ArgumentList *mdefAl = mdef->argumentList();
3986 ArgumentList *mdecAl = mdec->argumentList();
3988 matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
3989 mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
3994 MemberSDict *defDict = mdef->getReferencesMembers();
3995 MemberSDict *decDict = mdec->getReferencesMembers();
3998 MemberSDict::IteratorDict msdi(*defDict);
4000 for (msdi.toFirst();(rmd=msdi.current());++msdi)
4002 if (decDict==0 || decDict->find(rmd->name())==0)
4004 mdec->addSourceReferences(rmd);
4010 MemberSDict::IteratorDict msdi(*decDict);
4012 for (msdi.toFirst();(rmd=msdi.current());++msdi)
4014 if (defDict==0 || defDict->find(rmd->name())==0)
4016 mdef->addSourceReferences(rmd);
4021 defDict = mdef->getReferencedByMembers();
4022 decDict = mdec->getReferencedByMembers();
4025 MemberSDict::IteratorDict msdi(*defDict);
4027 for (msdi.toFirst();(rmd=msdi.current());++msdi)
4029 if (decDict==0 || decDict->find(rmd->name())==0)
4031 mdec->addSourceReferencedBy(rmd);
4037 MemberSDict::IteratorDict msdi(*decDict);
4039 for (msdi.toFirst();(rmd=msdi.current());++msdi)
4041 if (defDict==0 || defDict->find(rmd->name())==0)
4043 mdef->addSourceReferencedBy(rmd);
4052 //----------------------------------------------------------------------
4054 static void transferRelatedFunctionDocumentation()
4056 // find match between function declaration and definition for
4057 // related functions
4058 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4060 for (mnli.toFirst();(mn=mnli.current());++mnli)
4063 MemberNameIterator mni(*mn);
4064 /* find a matching function declaration and definition for this function */
4065 for (mni.toFirst();(md=mni.current());++mni) // for each global function
4067 //printf(" Function `%s'\n",md->name().data());
4069 if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
4071 //printf(" Member name found\n");
4073 MemberNameIterator rmni(*rmn);
4074 for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
4076 ArgumentList *mdAl = md->argumentList();
4077 ArgumentList *rmdAl = rmd->argumentList();
4078 //printf(" Member found: related=`%d'\n",rmd->isRelated());
4079 if ((rmd->isRelated() || rmd->isForeign()) && // related function
4080 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4081 rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
4086 //printf(" Found related member `%s'\n",md->name().data());
4087 if (rmd->relatedAlso())
4088 md->setRelatedAlso(rmd->relatedAlso());
4089 else if (rmd->isForeign())
4100 //----------------------------------------------------------------------
4102 /*! make a dictionary of all template arguments of class cd
4103 * that are part of the base class name.
4104 * Example: A template class A with template arguments <R,S,T>
4105 * that inherits from B<T,T,S> will have T and S in the dictionary.
4107 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
4109 QDict<int> *templateNames = new QDict<int>(17);
4110 templateNames->setAutoDelete(TRUE);
4111 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
4112 if (templateArguments)
4114 ArgumentListIterator ali(*templateArguments);
4117 for (ali.toFirst();(arg=ali.current());++ali,count++)
4120 while ((i=re.match(name,p,&l))!=-1)
4122 QCString n = name.mid(i,l);
4125 if (templateNames->find(n)==0)
4127 templateNames->insert(n,new int(count));
4134 return templateNames;
4137 /*! Searches a class from within \a context and \a cd and returns its
4138 * definition if found (otherwise 0 is returned).
4140 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
4147 FileDef *fd=cd->getFileDef();
4148 if (context && cd!=context)
4150 result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
4154 result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
4156 if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4158 result = getClass(name);
4161 (cd->getLanguage()==SrcLangExt_CSharp || cd->getLanguage()==SrcLangExt_Java) &&
4164 result = Doxygen::genericsDict->find(name);
4166 //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4168 // context ? context->name().data() : "<none>",
4169 // cd ? cd->name().data() : "<none>",
4170 // result ? result->name().data() : "<none>",
4171 // Doxygen::classSDict->find(name)
4177 static void findUsedClassesForClass(EntryNav *rootNav,
4178 Definition *context,
4180 ClassDef *instanceCd,
4182 ArgumentList *actualArgs=0,
4183 QDict<int> *templateNames=0
4186 masterCd->visited=TRUE;
4187 ArgumentList *formalArgs = masterCd->templateArguments();
4188 if (masterCd->memberNameInfoSDict())
4190 MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
4191 MemberNameInfo *mni;
4192 for (;(mni=mnili.current());++mnili)
4194 MemberNameInfoIterator mnii(*mni);
4196 for (mnii.toFirst();(mi=mnii.current());++mnii)
4198 MemberDef *md=mi->memberDef;
4199 if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4201 //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
4202 QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4203 QCString typedefValue = resolveTypeDef(masterCd,type);
4204 if (!typedefValue.isEmpty())
4206 type = typedefValue;
4209 QCString usedClassName;
4212 // the type can contain template variables, replace them if present
4215 type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4218 //printf(" template substitution gives=%s\n",type.data());
4219 while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
4221 // find the type (if any) that matches usedClassName
4222 ClassDef *typeCd = getResolvedClass(masterCd,
4223 masterCd->getFileDef(),
4228 //printf("====> usedClassName=%s -> typeCd=%s\n",
4229 // usedClassName.data(),typeCd?typeCd->name().data():"<none>");
4232 usedClassName = typeCd->name();
4235 int sp=usedClassName.find('<');
4237 int si=usedClassName.findRev("::",sp);
4240 // replace any namespace aliases
4241 replaceNamespaceAliases(usedClassName,si);
4243 // add any template arguments to the class
4244 QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4245 //printf(" usedName=%s\n",usedName.data());
4247 bool delTempNames=FALSE;
4248 if (templateNames==0)
4250 templateNames = getTemplateArgumentsInName(formalArgs,usedName);
4253 BaseInfo bi(usedName,Public,Normal);
4254 findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
4256 if (masterCd->templateArguments())
4258 ArgumentListIterator ali(*masterCd->templateArguments());
4261 for (ali.toFirst();(arg=ali.current());++ali,++count)
4263 if (arg->name==usedName) // type is a template argument
4266 Debug::print(Debug::Classes,0," New used class `%s'\n", qPrint(usedName));
4268 ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
4271 usedCd = new ClassDef(
4272 masterCd->getDefFileName(),masterCd->getDefLine(),
4273 masterCd->getDefColumn(),
4276 //printf("making %s a template argument!!!\n",usedCd->name().data());
4277 usedCd->makeTemplateArgument();
4278 usedCd->setUsedOnly(TRUE);
4279 usedCd->setLanguage(masterCd->getLanguage());
4280 Doxygen::hiddenClasses->append(usedName,usedCd);
4282 if (isArtificial) usedCd->setArtificial(TRUE);
4283 Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", qPrint(usedCd->name()));
4284 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4285 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4292 ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4293 //printf("Looking for used class %s: result=%s master=%s\n",
4294 // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
4299 Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", qPrint(usedCd->name()));
4300 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
4301 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4306 delete templateNames;
4310 if (!found && !type.isEmpty()) // used class is not documented in any scope
4312 ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4313 if (usedCd==0 && !Config_getBool(HIDE_UNDOC_RELATIONS))
4315 if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4317 type+=md->argsString();
4319 Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", qPrint(type));
4320 usedCd = new ClassDef(
4321 masterCd->getDefFileName(),masterCd->getDefLine(),
4322 masterCd->getDefColumn(),
4323 type,ClassDef::Class);
4324 usedCd->setUsedOnly(TRUE);
4325 usedCd->setLanguage(masterCd->getLanguage());
4326 Doxygen::hiddenClasses->append(type,usedCd);
4330 if (isArtificial) usedCd->setArtificial(TRUE);
4331 Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", qPrint(usedCd->name()));
4332 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4333 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4342 //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4346 static void findBaseClassesForClass(
4348 Definition *context,
4350 ClassDef *instanceCd,
4351 FindBaseClassRelation_Mode mode,
4353 ArgumentList *actualArgs=0,
4354 QDict<int> *templateNames=0
4357 Entry *root = rootNav->entry();
4358 //if (masterCd->visited) return;
4359 masterCd->visited=TRUE;
4360 // The base class could ofcouse also be a non-nested class
4361 ArgumentList *formalArgs = masterCd->templateArguments();
4362 QListIterator<BaseInfo> bii(*root->extends);
4364 for (bii.toFirst();(bi=bii.current());++bii)
4366 //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4367 // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4368 bool delTempNames=FALSE;
4369 if (templateNames==0)
4371 templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4374 BaseInfo tbi(bi->name,bi->prot,bi->virt);
4375 if (actualArgs) // substitute the formal template arguments of the base class
4377 tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4379 //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4381 if (mode==DocumentedOnly)
4383 // find a documented base class in the correct scope
4384 if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4386 // 1.8.2: decided to show inheritance relations even if not documented,
4387 // we do make them artificial, so they do not appear in the index
4388 //if (!Config_getBool(HIDE_UNDOC_RELATIONS))
4389 bool b = Config_getBool(HIDE_UNDOC_RELATIONS) ? TRUE : isArtificial;
4391 // no documented base class -> try to find an undocumented one
4392 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4396 else if (mode==TemplateInstances)
4398 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4402 delete templateNames;
4408 //----------------------------------------------------------------------
4410 static bool findTemplateInstanceRelation(Entry *root,
4411 Definition *context,
4412 ClassDef *templateClass,const QCString &templSpec,
4413 QDict<int> *templateNames,
4416 Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n",
4417 qPrint(templateClass->name()),qPrint(templSpec));
4418 //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4419 // templateClass->name().data(),templSpec.data());
4420 //if (templateNames)
4422 // QDictIterator<int> qdi(*templateNames);
4423 // int *tempArgIndex;
4424 // for (;(tempArgIndex=qdi.current());++qdi)
4426 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4431 bool existingClass = (templSpec ==
4432 tempArgListToString(templateClass->templateArguments(),root->lang)
4434 if (existingClass) return TRUE;
4436 bool freshInstance=FALSE;
4437 ClassDef *instanceClass = templateClass->insertTemplateInstance(
4438 root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4439 if (isArtificial) instanceClass->setArtificial(TRUE);
4440 instanceClass->setLanguage(root->lang);
4444 Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",qPrint(instanceClass->name()));
4445 Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4446 instanceClass->setTemplateBaseClassNames(templateNames);
4448 // search for new template instances caused by base classes of
4450 EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4451 if (templateRootNav)
4453 bool unloadNeeded=FALSE;
4454 Entry *templateRoot = templateRootNav->entry();
4455 if (templateRoot==0) // not yet loaded
4457 templateRootNav->loadEntry(g_storage);
4458 templateRoot = templateRootNav->entry();
4459 ASSERT(templateRoot!=0); // now it should really be loaded
4463 Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",
4464 qPrint(templateRoot->name),qPrint(templSpec));
4465 ArgumentList *templArgs = new ArgumentList;
4466 stringToArgumentList(templSpec,templArgs);
4467 findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4468 TemplateInstances,isArtificial,templArgs,templateNames);
4470 findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4471 isArtificial,templArgs,templateNames);
4474 if (unloadNeeded) // still cleanup to do
4476 templateRootNav->releaseEntry();
4481 Debug::print(Debug::Classes,0," no template root entry found!\n");
4482 // TODO: what happened if we get here?
4485 //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data());
4486 //ArgumentList *tl = templateClass->templateArguments();
4490 Debug::print(Debug::Classes,0," instance already exists!\n");
4495 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4498 int index=n.find('<');
4503 bool result = rightScopeMatch(scope,n);
4507 /*! Searches for the end of a template in prototype \a s starting from
4508 * character position \a startPos. If the end was found the position
4509 * of the closing \> is returned, otherwise -1 is returned.
4511 * Handles exotic cases such as
4520 static int findEndOfTemplate(const QCString &s,int startPos)
4522 // locate end of template
4526 int len = s.length();
4527 bool insideString=FALSE;
4528 bool insideChar=FALSE;
4530 while (e<len && brCount!=0)
4536 if (!insideString && !insideChar)
4538 if (e<len-1 && s.at(e+1)=='<')
4540 else if (roundCount==0)
4545 if (!insideString && !insideChar)
4547 if (e<len-1 && s.at(e+1)=='>')
4549 else if (roundCount==0)
4554 if (!insideString && !insideChar)
4558 if (!insideString && !insideChar)
4564 if (insideString && pc!='\\')
4573 if (insideChar && pc!='\\')
4583 return brCount==0 ? e : -1;
4586 static bool findClassRelation(
4588 Definition *context,
4591 QDict<int> *templateNames,
4592 FindBaseClassRelation_Mode mode,
4596 //printf("findClassRelation(class=%s base=%s templateNames=",
4597 // cd->name().data(),bi->name.data());
4598 //if (templateNames)
4600 // QDictIterator<int> qdi(*templateNames);
4601 // int *tempArgIndex;
4602 // for (;(tempArgIndex=qdi.current());++qdi)
4604 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4609 Entry *root = rootNav->entry();
4611 QCString biName=bi->name;
4612 bool explicitGlobalScope=FALSE;
4613 //printf("findClassRelation: biName=`%s'\n",biName.data());
4614 if (biName.left(2)=="::") // explicit global scope
4616 biName=biName.right(biName.length()-2);
4617 explicitGlobalScope=TRUE;
4620 EntryNav *parentNode=rootNav->parent();
4621 bool lastParent=FALSE;
4622 do // for each parent scope, starting with the largest scope
4623 // (in case of nested classes)
4625 QCString scopeName= parentNode ? parentNode->name().data() : "";
4626 int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4627 do // try all parent scope prefixes, starting with the largest scope
4629 //printf("scopePrefix=`%s' biName=`%s'\n",
4630 // scopeName.left(scopeOffset).data(),biName.data());
4632 QCString baseClassName=biName;
4635 baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4637 //QCString stripped;
4638 //baseClassName=stripTemplateSpecifiersFromScope
4639 // (removeRedundantWhiteSpace(baseClassName),TRUE,
4641 MemberDef *baseClassTypeDef=0;
4643 ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4651 //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4652 // baseClassName.data(),baseClass,cd,explicitGlobalScope);
4653 //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4654 // cd ? cd->name().data():"<none>",
4655 // baseClassName.data(),
4656 // baseClass?baseClass->name().data():"<none>",
4659 //if (baseClassName.left(root->name.length())!=root->name ||
4660 // baseClassName.at(root->name.length())!='<'
4661 // ) // Check for base class with the same name.
4662 // // If found then look in the outer scope for a match
4663 // // and prevent recursion.
4664 if (!isRecursiveBaseClass(rootNav->name(),baseClassName)
4665 || explicitGlobalScope
4666 // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4667 // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4668 || (rootNav->lang()==SrcLangExt_IDL &&
4669 (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
4670 rootNav->section()==Entry::INCLUDED_SERVICE_SEC)))
4673 Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4674 qPrint(baseClassName),
4675 qPrint(rootNav->name()),
4676 (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4677 (bi->virt==Normal)?"normal":"virtual",
4681 int i=baseClassName.find('<');
4682 int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4684 if (baseClass==0 && (root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java))
4686 // for Java/C# strip the template part before looking for matching
4687 baseClass = Doxygen::genericsDict->find(baseClassName.left(i));
4688 //printf("looking for '%s' result=%p\n",baseClassName.data(),baseClass);
4690 if (baseClass==0 && i!=-1)
4691 // base class has template specifiers
4693 // TODO: here we should try to find the correct template specialization
4694 // but for now, we only look for the unspecializated base class.
4695 int e=findEndOfTemplate(baseClassName,i+1);
4696 //printf("baseClass==0 i=%d e=%d\n",i,e);
4697 if (e!=-1) // end of template was found at e
4699 templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4700 baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4701 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4709 //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4710 // baseClass,baseClassName.data(),templSpec.data());
4713 else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4714 // know it is a template, so see if
4715 // we can also link to the explicit
4716 // instance (for instance if a class
4717 // derived from a template argument)
4719 //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4720 ClassDef *templClass=getClass(baseClass->name()+templSpec);
4723 // use the template instance instead of the template base.
4724 baseClass = templClass;
4725 templSpec.resize(0);
4729 //printf("cd=%p baseClass=%p\n",cd,baseClass);
4730 bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4731 //printf("1. found=%d\n",found);
4732 if (!found && si!=-1)
4734 QCString tmpTemplSpec;
4735 // replace any namespace aliases
4736 replaceNamespaceAliases(baseClassName,si);
4737 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4745 found=baseClass!=0 && baseClass!=cd;
4746 if (found) templSpec = tmpTemplSpec;
4748 //printf("2. found=%d\n",found);
4750 //printf("root->name=%s biName=%s baseClassName=%s\n",
4751 // root->name.data(),biName.data(),baseClassName.data());
4752 //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4754 // baseClassName+="-g";
4759 baseClass=findClassWithinClassContext(context,cd,baseClassName);
4760 //printf("findClassWithinClassContext(%s,%s)=%p\n",
4761 // cd->name().data(),baseClassName.data(),baseClass);
4762 found = baseClass!=0 && baseClass!=cd;
4767 // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4768 // the class name also in the alias mapping.
4769 QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4770 if (aliasName) // see if it is indeed a class.
4772 baseClass=getClass(*aliasName);
4773 found = baseClass!=0 && baseClass!=cd;
4776 bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4777 // make templSpec canonical
4778 // warning: the following line doesn't work for Mixin classes (see bug 560623)
4779 // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4781 //printf("3. found=%d\n",found);
4784 Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",qPrint(biName),qPrint(templSpec));
4785 // add base class to this class
4787 // if templSpec is not empty then we should "instantiate"
4788 // the template baseClass. A new ClassDef should be created
4789 // to represent the instance. To be able to add the (instantiated)
4790 // members and documentation of a template class
4791 // (inserted in that template class at a later stage),
4792 // the template should know about its instances.
4793 // the instantiation process, should be done in a recursive way,
4794 // since instantiating a template may introduce new inheritance
4796 if (!templSpec.isEmpty() && mode==TemplateInstances)
4798 // if baseClass is actually a typedef then we should not
4799 // instantiate it, since typedefs are in a different namespace
4800 // see bug531637 for an example where this would otherwise hang
4802 if (baseClassTypeDef==0)
4804 //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4805 findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4808 else if (mode==DocumentedOnly || mode==Undocumented)
4810 //printf(" => insert base class\n");
4812 if (baseClassTypeDef || cd->isCSharp())
4815 //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4817 static bool sipSupport = Config_getBool(SIP_SUPPORT);
4818 if (sipSupport) bi->prot=Public;
4819 if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4821 cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4822 // add this class as super class to the base class
4823 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4827 warn(root->fileName,root->startLine,
4828 "Detected potential recursive class relation "
4829 "between class %s and base class %s!",
4830 cd->name().data(),baseClass->name().data()
4836 else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4838 Debug::print(Debug::Classes,0,
4839 " New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4840 qPrint(biName),qPrint(baseClassName),qPrint(templSpec),isArtificial
4843 if (isATemplateArgument)
4845 baseClass=Doxygen::hiddenClasses->find(baseClassName);
4848 baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4851 Doxygen::hiddenClasses->append(baseClassName,baseClass);
4852 if (isArtificial) baseClass->setArtificial(TRUE);
4853 baseClass->setLanguage(root->lang);
4858 baseClass=Doxygen::classSDict->find(baseClassName);
4859 //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4860 // baseClassName.data(),baseClass,biName.data(),templSpec.data());
4863 baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4866 Doxygen::classSDict->append(baseClassName,baseClass);
4867 if (isArtificial) baseClass->setArtificial(TRUE);
4868 baseClass->setLanguage(root->lang);
4869 int si = baseClassName.findRev("::");
4870 if (si!=-1) // class is nested
4872 Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,rootNav->tagInfo());
4873 if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4875 baseClass->setArtificial(TRUE); // see bug678139
4880 if (biName.right(2)=="-p")
4882 biName="<"+biName.left(biName.length()-2)+">";
4884 // add base class to this class
4885 cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4886 // add this class as super class to the base class
4887 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4888 // the undocumented base was found in this file
4889 baseClass->insertUsedFile(rootNav->fileDef());
4890 baseClass->setOuterScope(Doxygen::globalScope);
4891 if (baseClassName.right(2)=="-p")
4893 baseClass->setCompoundType(ClassDef::Protocol);
4899 Debug::print(Debug::Classes,0," Base class `%s' not found\n",qPrint(biName));
4904 if (mode!=TemplateInstances)
4906 warn(root->fileName,root->startLine,
4907 "Detected potential recursive class relation "
4908 "between class %s and base class %s!\n",
4909 root->name.data(),baseClassName.data()
4912 // for mode==TemplateInstance this case is quite common and
4913 // indicates a relation between a template class and a template
4914 // instance with the same name.
4920 else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4924 //printf("new scopeOffset=`%d'",scopeOffset);
4925 } while (scopeOffset>=0);
4933 parentNode=parentNode->parent();
4935 } while (lastParent);
4940 //----------------------------------------------------------------------
4941 // Computes the base and super classes for each class in the tree
4943 static bool isClassSection(EntryNav *rootNav)
4945 if ( !rootNav->name().isEmpty() )
4947 if (rootNav->section() & Entry::COMPOUND_MASK)
4948 // is it a compound (class, struct, union, interface ...)
4952 else if (rootNav->section() & Entry::COMPOUNDDOC_MASK)
4953 // is it a documentation block with inheritance info.
4955 rootNav->loadEntry(g_storage);
4956 Entry *root = rootNav->entry();
4957 bool extends = root->extends->count()>0;
4958 rootNav->releaseEntry();
4959 if (extends) return TRUE;
4966 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
4968 static void findClassEntries(EntryNav *rootNav)
4970 if (isClassSection(rootNav))
4972 g_classEntries.insert(rootNav->name(),rootNav);
4974 RECURSE_ENTRYTREE(findClassEntries,rootNav);
4977 static QCString extractClassName(EntryNav *rootNav)
4979 // strip any anonymous scopes first
4980 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4981 bName=stripTemplateSpecifiersFromScope(bName);
4983 if ((rootNav->lang()==SrcLangExt_CSharp || rootNav->lang()==SrcLangExt_Java) &&
4984 (i=bName.find('<'))!=-1)
4986 // a Java/C# generic class looks like a C++ specialization, so we need to strip the
4987 // template part before looking for matches
4988 bName=bName.left(i);
4993 /*! Using the dictionary build by findClassEntries(), this
4994 * function will look for additional template specialization that
4995 * exists as inheritance relations only. These instances will be
4996 * added to the template they are derived from.
4998 static void findInheritedTemplateInstances()
5000 ClassSDict::Iterator cli(*Doxygen::classSDict);
5001 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5002 QDictIterator<EntryNav> edi(g_classEntries);
5004 for (;(rootNav=edi.current());++edi)
5007 QCString bName = extractClassName(rootNav);
5008 Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",qPrint(bName));
5009 if ((cd=getClass(bName)))
5011 rootNav->loadEntry(g_storage);
5012 //printf("Class %s %d\n",cd->name().data(),root->extends->count());
5013 findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
5014 rootNav->releaseEntry();
5019 static void findUsedTemplateInstances()
5021 ClassSDict::Iterator cli(*Doxygen::classSDict);
5022 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5023 QDictIterator<EntryNav> edi(g_classEntries);
5025 for (;(rootNav=edi.current());++edi)
5028 QCString bName = extractClassName(rootNav);
5029 Debug::print(Debug::Classes,0," Usage: Class %s : \n",qPrint(bName));
5030 if ((cd=getClass(bName)))
5032 rootNav->loadEntry(g_storage);
5033 findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
5034 cd->addTypeConstraints();
5035 rootNav->releaseEntry();
5040 static void computeClassRelations()
5042 ClassSDict::Iterator cli(*Doxygen::classSDict);
5043 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5044 QDictIterator<EntryNav> edi(g_classEntries);
5046 for (;(rootNav=edi.current());++edi)
5050 rootNav->loadEntry(g_storage);
5051 Entry *root = rootNav->entry();
5052 QCString bName = extractClassName(rootNav);
5053 Debug::print(Debug::Classes,0," Relations: Class %s : \n",qPrint(bName));
5054 if ((cd=getClass(bName)))
5056 findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
5058 int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
5059 if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
5060 bName.right(2)!="::")
5062 if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
5063 (guessSection(root->fileName)==Entry::HEADER_SEC ||
5064 Config_getBool(EXTRACT_LOCAL_CLASSES)) && // not defined in source file
5065 protectionLevelVisible(root->protection) && // hidden by protection
5066 !Config_getBool(HIDE_UNDOC_CLASSES) // undocumented class are visible
5069 root->fileName,root->startLine,
5070 "Compound %s is not documented.",
5075 rootNav->releaseEntry();
5079 static void computeTemplateClassRelations()
5081 QDictIterator<EntryNav> edi(g_classEntries);
5083 for (;(rootNav=edi.current());++edi)
5085 rootNav->loadEntry(g_storage);
5086 Entry *root = rootNav->entry();
5088 QCString bName=stripAnonymousNamespaceScope(root->name);
5089 bName=stripTemplateSpecifiersFromScope(bName);
5090 ClassDef *cd=getClass(bName);
5091 // strip any anonymous scopes first
5092 QDict<ClassDef> *templInstances = 0;
5093 if (cd && (templInstances=cd->getTemplateInstances()))
5095 Debug::print(Debug::Classes,0," Template class %s : \n",qPrint(cd->name()));
5096 QDictIterator<ClassDef> tdi(*templInstances);
5098 for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
5100 Debug::print(Debug::Classes,0," Template instance %s : \n",qPrint(tcd->name()));
5101 QCString templSpec = tdi.currentKey();
5102 ArgumentList *templArgs = new ArgumentList;
5103 stringToArgumentList(templSpec,templArgs);
5104 QList<BaseInfo> *baseList=root->extends;
5105 QListIterator<BaseInfo> it(*baseList);
5107 for (;(bi=it.current());++it) // for each base class of the template
5109 // check if the base class is a template argument
5110 BaseInfo tbi(bi->name,bi->prot,bi->virt);
5111 ArgumentList *tl = cd->templateArguments();
5114 QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
5115 QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
5116 // for each template name that we inherit from we need to
5117 // substitute the formal with the actual arguments
5118 QDict<int> *actualTemplateNames = new QDict<int>(17);
5119 actualTemplateNames->setAutoDelete(TRUE);
5120 QDictIterator<int> qdi(*templateNames);
5121 for (qdi.toFirst();qdi.current();++qdi)
5123 int templIndex = *qdi.current();
5124 Argument *actArg = 0;
5125 if (templIndex<(int)templArgs->count())
5127 actArg=templArgs->at(templIndex);
5130 baseClassNames!=0 &&
5131 baseClassNames->find(actArg->type)!=0 &&
5132 actualTemplateNames->find(actArg->type)==0
5135 actualTemplateNames->insert(actArg->type,new int(templIndex));
5138 delete templateNames;
5140 tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
5141 // find a documented base class in the correct scope
5142 if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
5144 // no documented base class -> try to find an undocumented one
5145 findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
5147 delete actualTemplateNames;
5151 } // class has no base classes
5154 rootNav->releaseEntry();
5158 //-----------------------------------------------------------------------
5159 // compute the references (anchors in HTML) for each function in the file
5161 static void computeMemberReferences()
5163 ClassSDict::Iterator cli(*Doxygen::classSDict);
5165 for (cli.toFirst();(cd=cli.current());++cli)
5167 cd->computeAnchors();
5169 FileNameListIterator fnli(*Doxygen::inputNameList);
5171 for (fnli.toFirst();(fn=fnli.current());++fnli)
5173 FileNameIterator fni(*fn);
5175 for (;(fd=fni.current());++fni)
5177 fd->computeAnchors();
5180 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5182 for (nli.toFirst();(nd=nli.current());++nli)
5184 nd->computeAnchors();
5186 GroupSDict::Iterator gli(*Doxygen::groupSDict);
5188 for (gli.toFirst();(gd=gli.current());++gli)
5190 gd->computeAnchors();
5194 //----------------------------------------------------------------------
5196 static void addListReferences()
5198 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
5200 for (mnli.toFirst();(mn=mnli.current());++mnli)
5202 MemberNameIterator mni(*mn);
5204 for (mni.toFirst();(md=mni.current());++mni)
5209 MemberNameSDict::Iterator fmnli(*Doxygen::functionNameSDict);
5210 for (fmnli.toFirst();(mn=fmnli.current());++fmnli)
5212 MemberNameIterator mni(*mn);
5214 for (mni.toFirst();(md=mni.current());++mni)
5220 ClassSDict::Iterator cli(*Doxygen::classSDict);
5222 for (cli.toFirst();(cd=cli.current());++cli)
5224 cd->addListReferences();
5227 FileNameListIterator fnli(*Doxygen::inputNameList);
5229 for (fnli.toFirst();(fn=fnli.current());++fnli)
5231 FileNameIterator fni(*fn);
5233 for (;(fd=fni.current());++fni)
5235 fd->addListReferences();
5239 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5241 for (nli.toFirst();(nd=nli.current());++nli)
5243 nd->addListReferences();
5246 GroupSDict::Iterator gli(*Doxygen::groupSDict);
5248 for (gli.toFirst();(gd=gli.current());++gli)
5250 gd->addListReferences();
5253 PageSDict::Iterator pdi(*Doxygen::pageSDict);
5255 for (pdi.toFirst();(pd=pdi.current());++pdi)
5257 QCString name = pd->getOutputFileBase();
5258 if (pd->getGroupDef())
5260 name = pd->getGroupDef()->getOutputFileBase();
5263 QList<ListItemInfo> *xrefItems = pd->xrefListItems();
5264 addRefItem(xrefItems,
5266 theTranslator->trPage(TRUE,TRUE),
5267 name,pd->title(),0,0);
5271 DirSDict::Iterator ddi(*Doxygen::directories);
5273 for (ddi.toFirst();(dd=ddi.current());++ddi)
5275 QCString name = dd->getOutputFileBase();
5276 //if (dd->getGroupDef())
5278 // name = dd->getGroupDef()->getOutputFileBase();
5280 QList<ListItemInfo> *xrefItems = dd->xrefListItems();
5281 addRefItem(xrefItems,
5283 theTranslator->trDir(TRUE,TRUE),
5284 name,dd->displayName(),0,0);
5288 //----------------------------------------------------------------------
5290 static void generateXRefPages()
5292 QDictIterator<RefList> di(*Doxygen::xrefLists);
5294 for (di.toFirst();(rl=di.current());++di)
5300 //----------------------------------------------------------------------
5301 // Copy the documentation in entry `root' to member definition `md' and
5302 // set the function declaration of the member to `funcDecl'. If the boolean
5303 // over_load is set the standard overload text is added.
5305 static void addMemberDocs(EntryNav *rootNav,
5306 MemberDef *md, const char *funcDecl,
5312 Entry *root = rootNav->entry();
5313 //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
5314 // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
5315 QCString fDecl=funcDecl;
5316 // strip extern specifier
5317 fDecl.stripPrefix("extern ");
5318 md->setDefinition(fDecl);
5319 md->enableCallGraph(root->callGraph);
5320 md->enableCallerGraph(root->callerGraph);
5321 ClassDef *cd=md->getClassDef();
5322 NamespaceDef *nd=md->getNamespaceDef();
5325 fullName = cd->name();
5327 fullName = nd->name();
5329 if (!fullName.isEmpty()) fullName+="::";
5330 fullName+=md->name();
5331 FileDef *rfd=rootNav->fileDef();
5333 // TODO determine scope based on root not md
5334 Definition *rscope = md->getOuterScope();
5336 ArgumentList *mdAl = md->argumentList();
5339 //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5340 mergeArguments(mdAl,al,!root->doc.isEmpty());
5345 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
5346 rscope,rfd,root->argList,
5351 //printf("merging arguments (2)\n");
5352 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
5355 if (over_load) // the \overload keyword was used
5357 QCString doc=getOverloadDocs();
5358 if (!root->doc.isEmpty())
5363 md->setDocumentation(doc,root->docFile,root->docLine);
5364 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5365 md->setDocsForDefinition(!root->proto);
5369 //printf("overwrite!\n");
5370 md->setDocumentation(root->doc,root->docFile,root->docLine);
5371 md->setDocsForDefinition(!root->proto);
5373 //printf("overwrite!\n");
5374 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5377 (md->inbodyDocumentation().isEmpty() ||
5378 !rootNav->parent()->name().isEmpty()
5379 ) && !root->inbodyDocs.isEmpty()
5382 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5386 //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5387 // md->initializer().data(),md->initializer().isEmpty(),
5388 // root->initializer.data(),root->initializer.isEmpty()
5390 if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5392 //printf("setInitializer\n");
5393 md->setInitializer(root->initializer);
5396 md->setMaxInitLines(root->initLines);
5400 if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5403 //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5404 md->setBodySegment(root->bodyLine,root->endBodyLine);
5405 md->setBodyDef(rfd);
5408 md->setRefItems(root->sli);
5411 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5412 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5414 md->mergeMemberSpecifiers(root->spec);
5415 md->addSectionsToDefinition(root->anchors);
5416 addMemberToGroups(root,md);
5417 if (cd) cd->insertUsedFile(rfd);
5418 //printf("root->mGrpId=%d\n",root->mGrpId);
5419 if (root->mGrpId!=-1)
5421 if (md->getMemberGroupId()!=-1)
5423 if (md->getMemberGroupId()!=root->mGrpId)
5426 root->fileName,root->startLine,
5427 "member %s belongs to two different groups. The second "
5428 "one found here will be ignored.",
5433 else // set group id
5435 //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5436 md->setMemberGroupId(root->mGrpId);
5441 //----------------------------------------------------------------------
5442 // find a class definition given the scope name and (optionally) a
5443 // template list specifier
5445 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5446 const char *scopeName)
5448 ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5453 //----------------------------------------------------------------------
5454 // Adds the documentation contained in `root' to a global function
5455 // with name `name' and argument list `args' (for overloading) and
5456 // function declaration `decl' to the corresponding member definition.
5458 static bool findGlobalMember(EntryNav *rootNav,
5459 const QCString &namespaceName,
5462 const char *tempArg,
5466 Entry *root = rootNav->entry();
5467 Debug::print(Debug::FindMembers,0,
5468 "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5469 qPrint(namespaceName),qPrint(type),qPrint(name),qPrint(tempArg),qPrint(decl));
5471 if (n.isEmpty()) return FALSE;
5472 if (n.find("::")!=-1) return FALSE; // skip undefined class members
5473 MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5476 mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5478 if (mn) // function name defined
5480 Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5482 MemberNameIterator mni(*mn);
5485 for (mni.toFirst();(md=mni.current()) && !found;++mni)
5487 NamespaceDef *nd=md->getNamespaceDef();
5489 //printf("Namespace namespaceName=%s nd=%s\n",
5490 // namespaceName.data(),nd ? nd->name().data() : "<none>");
5492 FileDef *fd=rootNav->fileDef();
5493 //printf("File %s\n",fd ? fd->name().data() : "<none>");
5494 NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5495 //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0;
5496 //printf("NamespaceList %p\n",nl);
5498 // search in the list of namespaces that are imported via a
5499 // using declaration
5500 bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5502 if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
5503 (nd && nd->name()==namespaceName) || // or in the same namespace
5504 viaUsingDirective // member in `using' namespace
5507 Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5508 qPrint(md->name()),qPrint(namespaceName));
5510 NamespaceDef *rnd = 0;
5511 if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5513 ArgumentList *mdAl = md->argumentList();
5515 (mdAl==0 && root->argList->count()==0) ||
5516 md->isVariable() || md->isTypedef() || /* in case of function pointers */
5517 matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl,
5518 rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5521 // for template members we need to check if the number of
5522 // template arguments is the same, otherwise we are dealing with
5523 // different functions.
5524 if (matching && root->tArgLists)
5526 ArgumentList *mdTempl = md->templateArguments();
5529 if (root->tArgLists->getLast()->count()!=mdTempl->count())
5536 //printf("%s<->%s\n",
5537 // argListToString(md->argumentList()).data(),
5538 // argListToString(root->argList).data());
5540 // for static members we also check if the comment block was found in
5541 // the same file. This is needed because static members with the same
5542 // name can be in different files. Thus it would be wrong to just
5543 // put the comment block at the first syntactically matching member.
5544 if (matching && md->isStatic() &&
5545 md->getDefFileName()!=root->fileName &&
5551 // for template member we also need to check the return type
5552 if (md->templateArguments()!=0 && root->tArgLists!=0)
5554 //printf("Comparing return types '%s'<->'%s'\n",
5555 // md->typeString(),type);
5556 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
5557 qstrcmp(md->typeString(),type)!=0)
5559 //printf(" ---> no matching\n");
5564 if (matching) // add docs to the member
5566 Debug::print(Debug::FindMembers,0,"5. Match found\n");
5567 addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5572 if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5574 QCString fullFuncDecl=decl;
5575 if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5577 QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5580 warnMsg+="\nPossible candidates:\n";
5581 for (mni.toFirst();(md=mni.current());++mni)
5584 warnMsg+=substitute(md->declaration(),"%","%%");
5585 warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5586 " of file"+md->getDefFileName()+"\n";
5589 warn(root->fileName,root->startLine,warnMsg);
5592 else // got docs for an undefined member!
5594 if (root->type!="friend class" &&
5595 root->type!="friend struct" &&
5596 root->type!="friend union" &&
5597 root->type!="friend" &&
5598 (!Config_getBool(TYPEDEF_HIDES_STRUCT) ||
5599 root->type.find("typedef ")==-1)
5602 warn(root->fileName,root->startLine,
5603 "documented symbol `%s' was not declared or defined.",decl
5610 static bool isSpecialization(
5611 const QList<ArgumentList> &srcTempArgLists,
5612 const QList<ArgumentList> &dstTempArgLists
5615 QListIterator<ArgumentList> srclali(srcTempArgLists);
5616 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5617 for (;srclali.current();++srclali,++dstlali)
5619 ArgumentList *sal = srclali.current();
5620 ArgumentList *dal = dstlali.current();
5621 if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5626 static bool scopeIsTemplate(Definition *d)
5629 if (d && d->definitionType()==Definition::TypeClass)
5631 result = ((ClassDef*)d)->templateArguments() || scopeIsTemplate(d->getOuterScope());
5636 static QCString substituteTemplatesInString(
5637 const QList<ArgumentList> &srcTempArgLists,
5638 const QList<ArgumentList> &dstTempArgLists,
5639 ArgumentList *funcTempArgList, // can be used to match template specializations
5644 QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5645 //printf("type=%s\n",sa->type.data());
5647 while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5650 dst+=src.mid(p,i-p);
5651 QCString name=src.mid(i,l);
5653 QListIterator<ArgumentList> srclali(srcTempArgLists);
5654 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5655 for (;srclali.current() && !found;++srclali,++dstlali)
5657 ArgumentListIterator tsali(*srclali.current());
5658 ArgumentListIterator tdali(*dstlali.current());
5659 ArgumentListIterator *fali=0;
5660 Argument *tsa =0,*tda=0, *fa=0;
5661 if (funcTempArgList)
5663 fali = new ArgumentListIterator(*funcTempArgList);
5664 fa = fali->current();
5667 for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5669 tda = tdali.current();
5670 //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5671 // tsa->type.data(),tsa->name.data(),
5672 // tda->type.data(),tda->name.data());
5673 if (name==tsa->name)
5675 if (tda && tda->name.isEmpty())
5678 if (tda->type.left(6)=="class ") vc=6;
5679 else if (tda->type.left(9)=="typename ") vc=9;
5680 if (vc>0) // convert type=="class T" to type=="class" name=="T"
5682 tda->name = tda->type.mid(vc);
5683 tda->type = tda->type.left(vc-1);
5686 if (tda && !tda->name.isEmpty())
5688 name=tda->name; // substitute
5700 { ++(*fali); fa=fali->current(); }
5704 //printf(" srcList='%s' dstList='%s faList='%s'\n",
5705 // argListToString(srclali.current()).data(),
5706 // argListToString(dstlali.current()).data(),
5707 // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5712 dst+=src.right(src.length()-p);
5713 //printf(" substituteTemplatesInString(%s)=%s\n",
5714 // src.data(),dst.data());
5718 static void substituteTemplatesInArgList(
5719 const QList<ArgumentList> &srcTempArgLists,
5720 const QList<ArgumentList> &dstTempArgLists,
5723 ArgumentList *funcTempArgs = 0
5726 ArgumentListIterator sali(*src);
5727 ArgumentListIterator dali(*dst);
5729 Argument *da=dali.current();
5731 for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5733 QCString dstType = substituteTemplatesInString(
5734 srcTempArgLists,dstTempArgLists,funcTempArgs,
5736 QCString dstArray = substituteTemplatesInString(
5737 srcTempArgLists,dstTempArgLists,funcTempArgs,
5741 da=new Argument(*sa);
5755 dst->constSpecifier = src->constSpecifier;
5756 dst->volatileSpecifier = src->volatileSpecifier;
5757 dst->pureSpecifier = src->pureSpecifier;
5758 dst->trailingReturnType = substituteTemplatesInString(
5759 srcTempArgLists,dstTempArgLists,
5760 funcTempArgs,src->trailingReturnType);
5761 //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5762 // argListToString(src).data(),argListToString(dst).data()
5768 /*! This function tries to find a member (in a documented class/file/namespace)
5769 * that corresponds to the function/variable declaration given in \a funcDecl.
5771 * The boolean \a overloaded is used to specify whether or not a standard
5772 * overload documentation line should be generated.
5774 * The boolean \a isFunc is a hint that indicates that this is a function
5775 * instead of a variable or typedef.
5777 static void findMember(EntryNav *rootNav,
5783 Entry *root = rootNav->entry();
5785 Debug::print(Debug::FindMembers,0,
5786 "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5787 "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5788 "spec=%lld lang=%x\n",
5789 root,qPrint(funcDecl),qPrint(root->relates),overloaded,isFunc,root->mGrpId,
5790 root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5791 root->spec,root->lang
5796 QCString namespaceName;
5800 QCString funcTempList;
5801 QCString exceptions;
5803 bool isRelated=FALSE;
5804 bool isMemberOf=FALSE;
5805 bool isFriend=FALSE;
5810 if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5815 if (funcDecl.stripPrefix("inline "))
5817 root->spec|=Entry::Inline;
5820 if (funcDecl.stripPrefix("explicit "))
5822 root->spec|=Entry::Explicit;
5825 if (funcDecl.stripPrefix("mutable "))
5827 root->spec|=Entry::Mutable;
5830 if (funcDecl.stripPrefix("virtual "))
5836 // delete any ; from the function declaration
5838 while ((sep=funcDecl.find(';'))!=-1)
5840 funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5843 // make sure the first character is a space to simplify searching.
5844 if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5846 // remove some superfluous spaces
5847 funcDecl= substitute(
5849 substitute(funcDecl,"~ ","~"),
5853 ).stripWhiteSpace();
5855 //printf("funcDecl=`%s'\n",funcDecl.data());
5856 if (isFriend && funcDecl.left(6)=="class ")
5858 //printf("friend class\n");
5859 funcDecl=funcDecl.right(funcDecl.length()-6);
5860 funcName = funcDecl.copy();
5862 else if (isFriend && funcDecl.left(7)=="struct ")
5864 funcDecl=funcDecl.right(funcDecl.length()-7);
5865 funcName = funcDecl.copy();
5869 // extract information from the declarations
5870 parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5871 funcArgs,funcTempList,exceptions
5874 //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5875 // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5877 // the class name can also be a namespace name, we decide this later.
5878 // if a related class name is specified and the class name could
5879 // not be derived from the function declaration, then use the
5881 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5882 // scopeName.data(),className.data(),namespaceName.data());
5883 if (!root->relates.isEmpty())
5884 { // related member, prefix user specified scope
5886 isMemberOf=(root->relatesType == MemberOf);
5887 if (getClass(root->relates)==0 && !scopeName.isEmpty())
5889 scopeName= mergeScopes(scopeName,root->relates);
5893 scopeName = root->relates;
5897 if (root->relates.isEmpty() && rootNav->parent() &&
5898 ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5899 (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5901 !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName
5902 // with the scope in which it was found
5904 QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5905 if (!scopeName.isEmpty() &&
5906 (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5908 scopeName = joinedName;
5912 scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5915 else // see if we can prefix a namespace or class that is used from the file
5917 FileDef *fd=rootNav->fileDef();
5920 NamespaceSDict *fnl = fd->getUsedNamespaces();
5923 QCString joinedName;
5925 NamespaceSDict::Iterator nsdi(*fnl);
5926 for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5928 joinedName = fnd->name()+"::"+scopeName;
5929 if (Doxygen::namespaceSDict->find(joinedName))
5931 scopeName=joinedName;
5938 scopeName=stripTemplateSpecifiersFromScope(
5939 removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
5941 // funcSpec contains the last template specifiers of the given scope.
5942 // If this method does not have any template arguments or they are
5943 // empty while funcSpec is not empty we assume this is a
5944 // specialization of a method. If not, we clear the funcSpec and treat
5945 // this as a normal method of a template class.
5946 if (!(root->tArgLists &&
5947 root->tArgLists->count()>0 &&
5948 root->tArgLists->getFirst()->count()==0
5955 // split scope into a namespace and a class part
5956 extractNamespaceName(scopeName,className,namespaceName,TRUE);
5957 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5958 // scopeName.data(),className.data(),namespaceName.data());
5960 //namespaceName=removeAnonymousScopes(namespaceName);
5961 if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5963 //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5964 // merge class and namespace scopes again
5965 scopeName.resize(0);
5966 if (!namespaceName.isEmpty())
5968 if (className.isEmpty())
5970 scopeName=namespaceName;
5972 else if (!root->relates.isEmpty() || // relates command with explicit scope
5973 !getClass(className)) // class name only exists in a namespace
5975 scopeName=namespaceName+"::"+className;
5979 scopeName=className;
5982 else if (!className.isEmpty())
5984 scopeName=className;
5986 //printf("new scope=`%s'\n",scopeName.data());
5988 QCString tempScopeName=scopeName;
5989 ClassDef *cd=getClass(scopeName);
5992 if (funcSpec.isEmpty())
5995 tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists,&argListIndex);
5999 tempScopeName=scopeName+funcSpec;
6002 //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
6003 // scopeName.data(),cd,root->tArgLists,tempScopeName.data());
6005 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6006 // rebuild the function declaration (needed to get the scope right).
6007 if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool(HIDE_SCOPE_NAMES))
6009 if (!funcType.isEmpty())
6011 if (isFunc) // a function -> we use argList for the arguments
6013 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
6017 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
6022 if (isFunc) // a function => we use argList for the arguments
6024 funcDecl=tempScopeName+"::"+funcName+funcTempList;
6026 else // variable => add `argument' list
6028 funcDecl=tempScopeName+"::"+funcName+funcArgs;
6032 else // build declaration without scope
6034 if (!funcType.isEmpty()) // but with a type
6036 if (isFunc) // function => omit argument list
6038 funcDecl=funcType+" "+funcName+funcTempList;
6040 else // variable => add `argument' list
6042 funcDecl=funcType+" "+funcName+funcArgs;
6049 funcDecl=funcName+funcTempList;
6053 funcDecl=funcName+funcArgs;
6058 if (funcType=="template class" && !funcTempList.isEmpty())
6059 return; // ignore explicit template instantiations
6061 Debug::print(Debug::FindMembers,0,
6062 "findMember() Parse results:\n"
6063 " namespaceName=`%s'\n"
6069 " funcTempList=`%s'\n"
6072 " exceptions=`%s'\n"
6077 qPrint(namespaceName),qPrint(className),
6078 qPrint(funcType),qPrint(funcSpec),qPrint(funcName),qPrint(funcArgs),qPrint(funcTempList),
6079 qPrint(funcDecl),qPrint(root->relates),qPrint(exceptions),isRelated,isMemberOf,isFriend,
6084 if (!funcName.isEmpty()) // function name is valid
6086 Debug::print(Debug::FindMembers,0,
6087 "1. funcName=`%s'\n",funcName.data());
6088 if (funcName.left(9)=="operator ") // strip class scope from cast operator
6090 funcName = substitute(funcName,className+"::","");
6092 if (!funcTempList.isEmpty()) // try with member specialization
6094 mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
6096 if (mn==0) // try without specialization
6098 mn=Doxygen::memberNameSDict->find(funcName);
6100 if (!isRelated && mn) // function name already found
6102 Debug::print(Debug::FindMembers,0,
6103 "2. member name exists (%d members with this name)\n",mn->count());
6104 if (!className.isEmpty()) // class name is valid
6106 if (funcSpec.isEmpty()) // not a member specialization
6110 MemberNameIterator mni(*mn);
6112 bool memFound=FALSE;
6113 for (mni.toFirst();!memFound && (md=mni.current());++mni)
6115 ClassDef *cd=md->getClassDef();
6116 Debug::print(Debug::FindMembers,0,
6117 "3. member definition found, "
6118 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
6119 qPrint(scopeName),cd ? qPrint(cd->name()) : "<none>",
6120 qPrint(md->argsString()),
6121 qPrint(root->fileName));
6122 //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
6123 FileDef *fd=rootNav->fileDef();
6125 if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
6127 //printf("scopeName %s->%s\n",scopeName.data(),
6128 // stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
6130 ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
6131 if (tcd==0 && cd && stripAnonymousNamespaceScope(cd->name())==scopeName)
6133 // don't be fooled by anonymous scopes
6136 //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
6137 // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
6139 if (cd && tcd==cd) // member's classes match
6141 Debug::print(Debug::FindMembers,0,
6142 "4. class definition %s found\n",cd->name().data());
6144 // get the template parameter lists found at the member declaration
6145 QList<ArgumentList> declTemplArgs;
6146 cd->getTemplateParameterLists(declTemplArgs);
6147 ArgumentList *templAl = md->templateArguments();
6150 declTemplArgs.append(templAl);
6153 // get the template parameter lists found at the member definition
6154 QList<ArgumentList> *defTemplArgs = root->tArgLists;
6155 //printf("defTemplArgs=%p\n",defTemplArgs);
6157 // do we replace the decl argument lists with the def argument lists?
6158 bool substDone=FALSE;
6159 ArgumentList *argList=0;
6161 /* substitute the occurrences of class template names in the
6162 * argument list before matching
6164 ArgumentList *mdAl = md->argumentList();
6165 if (declTemplArgs.count()>0 && defTemplArgs &&
6166 declTemplArgs.count()==defTemplArgs->count() &&
6170 /* the function definition has template arguments
6171 * and the class definition also has template arguments, so
6172 * we must substitute the template names of the class by that
6173 * of the function definition before matching.
6175 argList = new ArgumentList;
6176 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
6181 else /* no template arguments, compare argument lists directly */
6186 Debug::print(Debug::FindMembers,0,
6187 "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
6188 qPrint(argListToString(argList,TRUE)),qPrint(argListToString(root->argList,TRUE)),
6189 qPrint(className),qPrint(namespaceName)
6193 md->isVariable() || md->isTypedef() || // needed for function pointers
6194 (mdAl==0 && root->argList->count()==0) ||
6196 md->getClassDef(),md->getFileDef(),argList,
6197 cd,fd,root->argList,
6200 if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
6202 matching = FALSE; // don't match methods and attributes with the same name
6205 // for template member we also need to check the return type
6206 if (md->templateArguments()!=0 && root->tArgLists!=0)
6208 QCString memType = md->typeString();
6209 memType.stripPrefix("static "); // see bug700696
6210 funcType=substitute(stripTemplateSpecifiersFromScope(funcType,TRUE),
6211 className+"::",""); // see bug700693 & bug732594
6212 memType=substitute(stripTemplateSpecifiersFromScope(memType,TRUE),
6213 className+"::",""); // see bug758900
6214 Debug::print(Debug::FindMembers,0,
6215 "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
6216 qPrint(md->typeString()),qPrint(funcType),
6217 md->templateArguments()->count(),root->tArgLists->getLast()->count());
6218 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
6219 qstrcmp(memType,funcType))
6221 //printf(" ---> no matching\n");
6225 bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
6226 bool classIsTemplate = scopeIsTemplate(md->getClassDef());
6227 bool mdIsTemplate = md->templateArguments()!=0;
6228 bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
6229 bool rootIsTemplate = root->tArgLists!=0;
6230 //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
6231 if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
6232 (mdIsTemplate || rootIsTemplate) && // either md or root is a template
6233 ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
6236 // Method with template return type does not match method without return type
6237 // even if the parameters are the same. See also bug709052
6238 Debug::print(Debug::FindMembers,0,
6239 "5b. Comparing return types: template v.s. non-template\n");
6244 Debug::print(Debug::FindMembers,0,
6245 "6. match results of matchArguments2 = %d\n",matching);
6247 if (substDone) // found a new argument list
6249 if (matching) // replace member's argument list
6251 md->setDefinitionTemplateParameterLists(root->tArgLists);
6252 md->setArgumentList(argList); // new owner of the list => no delete
6256 if (!funcTempList.isEmpty() &&
6257 isSpecialization(declTemplArgs,*defTemplArgs))
6259 // check if we are dealing with a partial template
6260 // specialization. In this case we add it to the class
6261 // even though the member arguments do not match.
6263 // TODO: copy other aspects?
6264 root->protection=md->protection(); // copy protection level
6265 addMethodToClass(rootNav,cd,md->name(),isFriend);
6273 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
6278 else if (cd && cd!=tcd) // we did find a class with the same name as cd
6279 // but in a different namespace
6284 if (count==0 && rootNav->parent() &&
6285 rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6287 goto localObjCMethod;
6289 if (count==0 && !(isFriend && funcType=="class"))
6292 ClassDef *ecd = 0, *ucd = 0;
6293 MemberDef *emd = 0, *umd = 0;
6296 //printf("Assume template class\n");
6297 for (mni.toFirst();(md=mni.current());++mni)
6299 ClassDef *ccd=md->getClassDef();
6301 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
6302 if (ccd!=0 && rightScopeMatch(ccd->name(),className))
6304 ArgumentList *templAl = md->templateArguments();
6305 if (root->tArgLists && templAl!=0 &&
6306 root->tArgLists->getLast()->count()<=templAl->count())
6308 addMethodToClass(rootNav,ccd,md->name(),isFriend);
6311 if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
6312 { // exact argument list match -> remember
6315 Debug::print(Debug::FindMembers,0,
6316 "7. new candidate className=%s scope=%s args=%s exact match\n",
6317 qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6319 else // arguments do not match, but member name and scope do -> remember
6323 Debug::print(Debug::FindMembers,0,
6324 "7. new candidate className=%s scope=%s args=%s no match\n",
6325 qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6331 static bool strictProtoMatching = Config_getBool(STRICT_PROTO_MATCHING);
6332 if (!strictProtoMatching)
6334 if (candidates==1 && ucd && umd)
6336 // we didn't find an actual match on argument lists, but there is only 1 member with this
6337 // name in the same scope, so that has to be the one.
6338 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
6341 else if (candidates>1 && ecd && emd)
6343 // we didn't find a unique match using type resolution,
6344 // but one of the matches has the exact same signature so
6345 // we take that one.
6346 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
6351 QCString warnMsg = "no ";
6352 if (noMatchCount>1) warnMsg+="uniquely ";
6353 warnMsg+="matching class member found for \n";
6355 if (root->tArgLists)
6357 QListIterator<ArgumentList> alli(*root->tArgLists);
6359 for (;(al=alli.current());++alli)
6361 warnMsg+=" template ";
6362 warnMsg+=tempArgListToString(al,root->lang);
6366 QCString fullFuncDecl=funcDecl.copy();
6367 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6370 warnMsg+=fullFuncDecl;
6375 warnMsg+="Possible candidates:\n";
6376 for (mni.toFirst();(md=mni.current());++mni)
6378 ClassDef *cd=md->getClassDef();
6379 if (cd!=0 && rightScopeMatch(cd->name(),className))
6381 ArgumentList *templAl = md->templateArguments();
6384 warnMsg+=" 'template ";
6385 warnMsg+=tempArgListToString(templAl,root->lang);
6389 if (md->typeString())
6391 warnMsg+=md->typeString();
6394 QCString qScope = cd->qualifiedNameWithTemplateParameters();
6395 if (!qScope.isEmpty())
6396 warnMsg+=qScope+"::"+md->name();
6397 if (md->argsString())
6398 warnMsg+=md->argsString();
6401 warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6402 " of file "+md->getDefFileName();
6409 warn_simple(root->fileName,root->startLine,warnMsg);
6412 else if (cd) // member specialization
6414 MemberNameIterator mni(*mn);
6415 MemberDef *declMd=0;
6417 for (mni.toFirst();(md=mni.current());++mni)
6419 if (md->getClassDef()==cd)
6421 // TODO: we should probably also check for matching arguments
6426 MemberType mtype=MemberType_Function;
6427 ArgumentList *tArgList = new ArgumentList;
6428 // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6430 root->fileName,root->startLine,root->startColumn,
6431 funcType,funcName,funcArgs,exceptions,
6432 declMd ? declMd->protection() : root->protection,
6433 root->virt,root->stat,Member,
6434 mtype,tArgList,root->argList);
6435 //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6436 md->setTagInfo(rootNav->tagInfo());
6437 md->setLanguage(root->lang);
6438 md->setId(root->id);
6439 md->setMemberClass(cd);
6440 md->setTemplateSpecialization(TRUE);
6441 md->setTypeConstraints(root->typeConstr);
6442 md->setDefinition(funcDecl);
6443 md->enableCallGraph(root->callGraph);
6444 md->enableCallerGraph(root->callerGraph);
6445 md->setDocumentation(root->doc,root->docFile,root->docLine);
6446 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6447 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6448 md->setDocsForDefinition(!root->proto);
6449 md->setPrototype(root->proto);
6450 md->addSectionsToDefinition(root->anchors);
6451 md->setBodySegment(root->bodyLine,root->endBodyLine);
6452 FileDef *fd=rootNav->fileDef();
6454 md->setMemberSpecifiers(root->spec);
6455 md->setMemberGroupId(root->mGrpId);
6457 cd->insertMember(md);
6458 md->setRefItems(root->sli);
6463 //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6464 // scopeName.data(),funcName.data(),funcArgs.data());
6467 else if (overloaded) // check if the function belongs to only one class
6469 // for unique overloaded member we allow the class to be
6470 // omitted, this is to be Qt compatible. Using this should
6471 // however be avoided, because it is error prone
6472 MemberNameIterator mni(*mn);
6473 MemberDef *md=mni.toFirst();
6475 ClassDef *cd=md->getClassDef();
6477 QCString className=cd->name().copy();
6480 for (;(md=mni.current());++mni)
6482 ClassDef *cd=md->getClassDef();
6483 if (className!=cd->name()) unique=FALSE;
6488 if (root->mtype==Signal) mtype=MemberType_Signal;
6489 else if (root->mtype==Slot) mtype=MemberType_Slot;
6490 else if (root->mtype==DCOP) mtype=MemberType_DCOP;
6491 else mtype=MemberType_Function;
6493 // new overloaded member function
6494 ArgumentList *tArgList =
6495 getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6496 //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6497 MemberDef *md=new MemberDef(
6498 root->fileName,root->startLine,root->startColumn,
6499 funcType,funcName,funcArgs,exceptions,
6500 root->protection,root->virt,root->stat,Related,
6501 mtype,tArgList,root->argList);
6502 md->setTagInfo(rootNav->tagInfo());
6503 md->setLanguage(root->lang);
6504 md->setId(root->id);
6505 md->setTypeConstraints(root->typeConstr);
6506 md->setMemberClass(cd);
6507 md->setDefinition(funcDecl);
6508 md->enableCallGraph(root->callGraph);
6509 md->enableCallerGraph(root->callerGraph);
6510 QCString doc=getOverloadDocs();
6513 md->setDocumentation(doc,root->docFile,root->docLine);
6514 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6515 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6516 md->setDocsForDefinition(!root->proto);
6517 md->setPrototype(root->proto);
6518 md->addSectionsToDefinition(root->anchors);
6519 md->setBodySegment(root->bodyLine,root->endBodyLine);
6520 FileDef *fd=rootNav->fileDef();
6522 md->setMemberSpecifiers(root->spec);
6523 md->setMemberGroupId(root->mGrpId);
6525 cd->insertMember(md);
6526 cd->insertUsedFile(fd);
6527 md->setRefItems(root->sli);
6530 else // unrelated function with the same name as a member
6532 if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6534 QCString fullFuncDecl=funcDecl.copy();
6535 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6536 warn(root->fileName,root->startLine,
6537 "Cannot determine class for function\n%s",
6543 else if (isRelated && !root->relates.isEmpty())
6545 Debug::print(Debug::FindMembers,0,"2. related function\n"
6546 " scopeName=%s className=%s\n",qPrint(scopeName),qPrint(className));
6547 if (className.isEmpty()) className=root->relates;
6549 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6550 if ((cd=getClass(scopeName)))
6552 bool newMember=TRUE; // assume we have a new member
6553 bool newMemberName=FALSE;
6554 MemberDef *mdDefine=0;
6555 bool isDefine=FALSE;
6557 MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6560 MemberNameIterator mni(*mn);
6561 mdDefine = mni.current();
6562 while (mdDefine && !isDefine)
6564 isDefine = isDefine || mdDefine->isDefine();
6565 if (!isDefine) { ++mni; mdDefine=mni.current(); }
6570 FileDef *fd=rootNav->fileDef();
6572 if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6574 mn=new MemberName(funcName);
6575 newMemberName=TRUE; // we create a new member name
6579 MemberNameIterator mni(*mn);
6581 while ((rmd=mni.current()) && newMember) // see if we got another member with matching arguments
6583 ArgumentList *rmdAl = rmd->argumentList();
6586 className!=rmd->getOuterScope()->name() ||
6587 !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6588 cd,fd,root->argList,
6590 if (newMember) ++mni;
6592 if (!newMember && rmd) // member already exists as rmd -> add docs
6594 //printf("addMemberDocs for related member %s\n",root->name.data());
6595 //rmd->setMemberDefTemplateArguments(root->mtArgList);
6596 addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6600 if (newMember) // need to create a new member
6604 mtype=MemberType_Define;
6605 else if (root->mtype==Signal)
6606 mtype=MemberType_Signal;
6607 else if (root->mtype==Slot)
6608 mtype=MemberType_Slot;
6609 else if (root->mtype==DCOP)
6610 mtype=MemberType_DCOP;
6612 mtype=MemberType_Function;
6614 if (isDefine && mdDefine)
6616 mdDefine->setHidden(TRUE);
6618 funcArgs=mdDefine->argsString();
6619 funcDecl=funcType + " " + funcName;
6622 //printf("New related name `%s' `%d'\n",funcName.data(),
6623 // root->argList ? (int)root->argList->count() : -1);
6625 // first note that we pass:
6626 // (root->tArgLists ? root->tArgLists->last() : 0)
6627 // for the template arguments fo the new "member."
6628 // this accurately reflects the template arguments of
6629 // the related function, which don't have to do with
6630 // those of the related class.
6631 MemberDef *md=new MemberDef(
6632 root->fileName,root->startLine,root->startColumn,
6633 funcType,funcName,funcArgs,exceptions,
6634 root->protection,root->virt,
6635 root->stat && !isMemberOf,
6636 isMemberOf ? Foreign : Related,
6638 (root->tArgLists ? root->tArgLists->getLast() : 0),
6639 funcArgs.isEmpty() ? 0 : root->argList);
6641 if (isDefine && mdDefine)
6643 md->setInitializer(mdDefine->initializer());
6647 // we still have the problem that
6648 // MemberDef::writeDocumentation() in memberdef.cpp
6649 // writes the template argument list for the class,
6650 // as if this member is a member of the class.
6651 // fortunately, MemberDef::writeDocumentation() has
6652 // a special mechanism that allows us to totally
6653 // override the set of template argument lists that
6654 // are printed. We use that and set it to the
6655 // template argument lists of the related function.
6657 md->setDefinitionTemplateParameterLists(root->tArgLists);
6659 md->setTagInfo(rootNav->tagInfo());
6663 //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6664 // funcName.data(),funcDecl.data(),root->bodyLine);
6666 // try to find the matching line number of the body from the
6667 // global function list
6669 if (root->bodyLine==-1)
6671 MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6674 MemberNameIterator rmni(*rmn);
6676 while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
6678 ArgumentList *rmdAl = rmd->argumentList();
6679 // check for matching argument lists
6681 matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6682 cd,fd,root->argList,
6690 if (rmd) // member found -> copy line number info
6692 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6693 md->setBodyDef(rmd->getBodyDef());
6694 //md->setBodyMember(rmd);
6698 if (!found) // line number could not be found or is available in this
6701 md->setBodySegment(root->bodyLine,root->endBodyLine);
6705 //if (root->mGrpId!=-1)
6707 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
6709 md->setMemberClass(cd);
6710 md->setMemberSpecifiers(root->spec);
6711 md->setDefinition(funcDecl);
6712 md->enableCallGraph(root->callGraph);
6713 md->enableCallerGraph(root->callerGraph);
6714 md->setDocumentation(root->doc,root->docFile,root->docLine);
6715 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6716 md->setDocsForDefinition(!root->proto);
6717 md->setPrototype(root->proto);
6718 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6719 md->addSectionsToDefinition(root->anchors);
6720 md->setMemberGroupId(root->mGrpId);
6721 md->setLanguage(root->lang);
6722 md->setId(root->id);
6723 //md->setMemberDefTemplateArguments(root->mtArgList);
6725 cd->insertMember(md);
6726 cd->insertUsedFile(fd);
6727 md->setRefItems(root->sli);
6728 if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6731 addMemberToGroups(root,md);
6733 //printf("Adding member=%s\n",md->name().data());
6736 //Doxygen::memberNameList.append(mn);
6737 //Doxygen::memberNameDict.insert(funcName,mn);
6738 Doxygen::memberNameSDict->append(funcName,mn);
6741 if (root->relatesType == Duplicate)
6743 if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6745 QCString fullFuncDecl=funcDecl.copy();
6746 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6747 warn(root->fileName,root->startLine,
6748 "Cannot determine file/namespace for relatedalso function\n%s",
6756 warn_undoc(root->fileName,root->startLine,
6757 "class `%s' for related function `%s' is not "
6759 className.data(),funcName.data()
6763 else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6767 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6768 if (Config_getBool(EXTRACT_LOCAL_METHODS) && (cd=getClass(scopeName)))
6770 Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6771 " scopeName=%s className=%s\n",qPrint(root->name),qPrint(scopeName),qPrint(className));
6772 //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6773 MemberDef *md=new MemberDef(
6774 root->fileName,root->startLine,root->startColumn,
6775 funcType,funcName,funcArgs,exceptions,
6776 root->protection,root->virt,root->stat,Member,
6777 MemberType_Function,0,root->argList);
6778 md->setTagInfo(rootNav->tagInfo());
6779 md->setLanguage(root->lang);
6780 md->setId(root->id);
6781 md->makeImplementationDetail();
6782 md->setMemberClass(cd);
6783 md->setDefinition(funcDecl);
6784 md->enableCallGraph(root->callGraph);
6785 md->enableCallerGraph(root->callerGraph);
6786 md->setDocumentation(root->doc,root->docFile,root->docLine);
6787 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6788 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6789 md->setDocsForDefinition(!root->proto);
6790 md->setPrototype(root->proto);
6791 md->addSectionsToDefinition(root->anchors);
6792 md->setBodySegment(root->bodyLine,root->endBodyLine);
6793 FileDef *fd=rootNav->fileDef();
6795 md->setMemberSpecifiers(root->spec);
6796 md->setMemberGroupId(root->mGrpId);
6797 cd->insertMember(md);
6798 cd->insertUsedFile(fd);
6799 md->setRefItems(root->sli);
6800 if ((mn=Doxygen::memberNameSDict->find(root->name)))
6806 mn = new MemberName(root->name);
6808 Doxygen::memberNameSDict->append(root->name,mn);
6813 // local objective C method found for class without interface
6816 else // unrelated not overloaded member found
6818 bool globMem = findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl);
6819 if (className.isEmpty() && !globMem)
6821 warn(root->fileName,root->startLine,
6822 "class for member `%s' cannot "
6823 "be found.", funcName.data()
6826 else if (!className.isEmpty() && !globMem)
6828 warn(root->fileName,root->startLine,
6829 "member `%s' of class `%s' cannot be found",
6830 funcName.data(),className.data());
6836 // this should not be called
6837 warn(root->fileName,root->startLine,
6838 "member with no name found.");
6843 //----------------------------------------------------------------------
6844 // find the members corresponding to the different documentation blocks
6845 // that are extracted from the sources.
6847 static void filterMemberDocumentation(EntryNav *rootNav)
6849 Entry *root = rootNav->entry();
6851 Debug::print(Debug::FindMembers,0,
6852 "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6853 qPrint(root->type),qPrint(root->inside),qPrint(root->name),qPrint(root->args),root->section,root->spec,root->mGrpId
6855 //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6858 if (root->relatesType == Duplicate && !root->relates.isEmpty())
6860 QCString tmp = root->relates;
6861 root->relates.resize(0);
6862 filterMemberDocumentation(rootNav);
6863 root->relates = tmp;
6866 if ( // detect func variable/typedef to func ptr
6867 (i=findFunctionPtr(root->type,root->lang,&l))!=-1
6870 //printf("Fixing function pointer!\n");
6871 // fix type and argument
6872 root->args.prepend(root->type.right(root->type.length()-i-l));
6873 root->type=root->type.left(i+l);
6874 //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6877 else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1))
6878 // detect function types marked as functions
6883 //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6884 if (root->section==Entry::MEMBERDOC_SEC)
6886 //printf("Documentation for inline member `%s' found args=`%s'\n",
6887 // root->name.data(),root->args.data());
6888 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6889 if (root->type.isEmpty())
6891 findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6895 findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6898 else if (root->section==Entry::OVERLOADDOC_SEC)
6900 //printf("Overloaded member %s found\n",root->name.data());
6901 findMember(rootNav,root->name,TRUE,isFunc);
6904 ((root->section==Entry::FUNCTION_SEC // function
6906 (root->section==Entry::VARIABLE_SEC && // variable
6907 !root->type.isEmpty() && // with a type
6908 g_compoundKeywordDict.find(root->type)==0 // that is not a keyword
6909 // (to skip forward declaration of class etc.)
6914 //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6915 // root->name.data(),root->args.data(),root->exception.data());
6916 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6917 //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6918 if (root->type=="friend class" || root->type=="friend struct" ||
6919 root->type=="friend union")
6927 else if (!root->type.isEmpty())
6947 else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6949 findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6951 else if (root->section==Entry::VARIABLEDOC_SEC)
6953 //printf("Documentation for variable %s found\n",root->name.data());
6954 //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data());
6955 findMember(rootNav,root->name,FALSE,FALSE);
6957 else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
6958 root->section==Entry::INCLUDED_SERVICE_SEC)
6960 findMember(rootNav,root->type + " " + root->name,FALSE,FALSE);
6965 //printf("skip section\n");
6969 static void findMemberDocumentation(EntryNav *rootNav)
6971 if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6972 rootNav->section()==Entry::OVERLOADDOC_SEC ||
6973 rootNav->section()==Entry::FUNCTION_SEC ||
6974 rootNav->section()==Entry::VARIABLE_SEC ||
6975 rootNav->section()==Entry::VARIABLEDOC_SEC ||
6976 rootNav->section()==Entry::DEFINE_SEC ||
6977 rootNav->section()==Entry::INCLUDED_SERVICE_SEC ||
6978 rootNav->section()==Entry::EXPORTED_INTERFACE_SEC
6981 rootNav->loadEntry(g_storage);
6983 filterMemberDocumentation(rootNav);
6985 rootNav->releaseEntry();
6987 if (rootNav->children())
6989 EntryNavListIterator eli(*rootNav->children());
6991 for (;(e=eli.current());++eli)
6993 if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6998 //----------------------------------------------------------------------
7000 static void findObjCMethodDefinitions(EntryNav *rootNav)
7002 if (rootNav->children())
7004 EntryNavListIterator eli(*rootNav->children());
7005 EntryNav *objCImplNav;
7006 for (;(objCImplNav=eli.current());++eli)
7008 if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
7010 EntryNavListIterator seli(*objCImplNav->children());
7011 EntryNav *objCMethodNav;
7012 for (;(objCMethodNav=seli.current());++seli)
7014 if (objCMethodNav->section()==Entry::FUNCTION_SEC)
7016 objCMethodNav->loadEntry(g_storage);
7017 Entry *objCMethod = objCMethodNav->entry();
7019 //Printf(" Found ObjC method definition %s\n",objCMethod->name.data());
7020 findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
7021 objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
7022 objCMethod->section=Entry::EMPTY_SEC;
7024 objCMethodNav->releaseEntry();
7032 //----------------------------------------------------------------------
7033 // find and add the enumeration to their classes, namespaces or files
7035 static void findEnums(EntryNav *rootNav)
7037 if (rootNav->section()==Entry::ENUM_SEC)
7039 rootNav->loadEntry(g_storage);
7040 Entry *root = rootNav->entry();
7046 MemberNameSDict *mnsd=0;
7048 bool isRelated=FALSE;
7049 bool isMemberOf=FALSE;
7050 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7056 if ((i=root->name.findRev("::"))!=-1) // scope is specified
7058 scope=root->name.left(i); // extract scope
7059 name=root->name.right(root->name.length()-i-2); // extract name
7060 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7062 else // no scope, check the scope in which the docs where found
7064 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7065 && !rootNav->parent()->name().isEmpty()
7066 ) // found enum docs inside a compound
7068 scope=rootNav->parent()->name();
7069 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7074 if (!root->relates.isEmpty())
7075 { // related member, prefix user specified scope
7077 isMemberOf=(root->relatesType == MemberOf);
7078 if (getClass(root->relates)==0 && !scope.isEmpty())
7079 scope=mergeScopes(scope,root->relates);
7081 scope=root->relates.copy();
7082 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7085 if (cd && !name.isEmpty()) // found a enum inside a compound
7087 //printf("Enum `%s'::`%s'\n",cd->name().data(),name.data());
7089 mnsd=Doxygen::memberNameSDict;
7092 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7094 mnsd=Doxygen::functionNameSDict;
7097 else // found a global enum
7099 fd=rootNav->fileDef();
7100 mnsd=Doxygen::functionNameSDict;
7104 if (!name.isEmpty())
7108 root->fileName,root->startLine,root->startColumn,
7110 root->protection,Normal,FALSE,
7111 isMemberOf ? Foreign : isRelated ? Related : Member,
7112 MemberType_Enumeration,
7114 md->setTagInfo(rootNav->tagInfo());
7115 md->setLanguage(root->lang);
7116 md->setId(root->id);
7117 if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7118 md->setBodySegment(root->bodyLine,root->endBodyLine);
7119 md->setBodyDef(rootNav->fileDef());
7120 md->setMemberSpecifiers(root->spec);
7121 md->setEnumBaseType(root->args);
7122 //printf("Enum %s definition at line %d of %s: protection=%d scope=%s\n",
7123 // root->name.data(),root->bodyLine,root->fileName.data(),root->protection,cd?cd->name().data():"<none>");
7124 md->addSectionsToDefinition(root->anchors);
7125 md->setMemberGroupId(root->mGrpId);
7126 md->enableCallGraph(root->callGraph);
7127 md->enableCallerGraph(root->callerGraph);
7128 //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
7129 md->setRefItems(root->sli);
7130 //printf("found enum %s nd=%p\n",md->name().data(),nd);
7133 QCString baseType = root->args;
7134 if (!baseType.isEmpty())
7136 baseType.prepend(" : ");
7139 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7141 if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7143 md->setDefinition(name+baseType);
7147 md->setDefinition(nd->name()+"::"+name+baseType);
7149 //printf("definition=%s\n",md->definition());
7151 md->setNamespace(nd);
7152 nd->insertMember(md);
7155 // even if we have already added the enum to a namespace, we still
7156 // also want to add it to other appropriate places such as file
7160 if (!defSet) md->setDefinition(name+baseType);
7161 if (fd==0 && rootNav->parent())
7163 fd=rootNav->parent()->fileDef();
7168 fd->insertMember(md);
7173 if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7175 md->setDefinition(name+baseType);
7179 md->setDefinition(cd->name()+"::"+name+baseType);
7181 cd->insertMember(md);
7182 cd->insertUsedFile(fd);
7184 md->setDocumentation(root->doc,root->docFile,root->docLine);
7185 md->setDocsForDefinition(!root->proto);
7186 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7187 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7189 //printf("Adding member=%s\n",md->name().data());
7191 if ((mn=(*mnsd)[name]))
7193 // this is used if the same enum is in multiple namespaces/classes
7196 else // new enum name
7198 mn = new MemberName(name);
7200 mnsd->append(name,mn);
7201 //printf("add %s to new memberName. Now %d members\n",
7202 // name.data(),mn->count());
7204 addMemberToGroups(root,md);
7206 rootNav->releaseEntry();
7210 RECURSE_ENTRYTREE(findEnums,rootNav);
7214 //----------------------------------------------------------------------
7216 static void addEnumValuesToEnums(EntryNav *rootNav)
7218 if (rootNav->section()==Entry::ENUM_SEC)
7219 // non anonymous enumeration
7221 rootNav->loadEntry(g_storage);
7222 Entry *root = rootNav->entry();
7227 MemberNameSDict *mnsd=0;
7229 bool isRelated=FALSE;
7230 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7236 if ((i=root->name.findRev("::"))!=-1) // scope is specified
7238 scope=root->name.left(i); // extract scope
7239 name=root->name.right(root->name.length()-i-2); // extract name
7240 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7242 else // no scope, check the scope in which the docs where found
7244 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7245 && !rootNav->parent()->name().isEmpty()
7246 ) // found enum docs inside a compound
7248 scope=rootNav->parent()->name();
7249 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7254 if (!root->relates.isEmpty())
7255 { // related member, prefix user specified scope
7257 if (getClass(root->relates)==0 && !scope.isEmpty())
7258 scope=mergeScopes(scope,root->relates);
7260 scope=root->relates.copy();
7261 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7264 if (cd && !name.isEmpty()) // found a enum inside a compound
7266 //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
7268 mnsd=Doxygen::memberNameSDict;
7271 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7273 //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
7274 mnsd=Doxygen::functionNameSDict;
7277 else // found a global enum
7279 fd=rootNav->fileDef();
7280 //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
7281 mnsd=Doxygen::functionNameSDict;
7285 if (!name.isEmpty())
7287 //printf("** name=%s\n",name.data());
7288 MemberName *mn = mnsd->find(name); // for all members with this name
7291 MemberNameIterator mni(*mn);
7293 for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list
7295 if (md->isEnumerate() && rootNav->children())
7297 //printf(" enum with %d children\n",rootNav->children()->count());
7298 EntryNavListIterator eli(*rootNav->children()); // for each enum value
7300 for (;(e=eli.current());++eli)
7304 (sle=rootNav->lang())==SrcLangExt_CSharp ||
7305 sle==SrcLangExt_Java ||
7306 sle==SrcLangExt_XML ||
7307 (root->spec&Entry::Strong)
7310 // Unlike classic C/C++ enums, for C++11, C# & Java enum
7311 // values are only visible inside the enum scope, so we must create
7312 // them here and only add them to the enum
7313 e->loadEntry(g_storage);
7314 Entry *root = e->entry();
7315 //printf("md->qualifiedName()=%s rootNav->name()=%s tagInfo=%p name=%s\n",
7316 // md->qualifiedName().data(),rootNav->name().data(),rootNav->tagInfo(),root->name.data());
7317 QCString qualifiedName = substitute(rootNav->name(),"::",".");
7318 if (!scope.isEmpty() && rootNav->tagInfo())
7320 qualifiedName=substitute(scope,"::",".")+"."+qualifiedName;
7322 if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7323 qualifiedName // enum value scope matches that of the enum
7326 QCString fileName = root->fileName;
7327 if (fileName.isEmpty() && rootNav->tagInfo())
7329 fileName = rootNav->tagInfo()->tagName;
7331 MemberDef *fmd=new MemberDef(
7332 fileName,root->startLine,root->startColumn,
7333 root->type,root->name,root->args,0,
7334 root->protection, Normal,root->stat,Member,
7335 MemberType_EnumValue,0,0);
7336 if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
7337 else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
7338 else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
7339 fmd->setOuterScope(md->getOuterScope());
7340 fmd->setTagInfo(e->tagInfo());
7341 fmd->setLanguage(root->lang);
7342 fmd->setId(root->id);
7343 fmd->setDocumentation(root->doc,root->docFile,root->docLine);
7344 fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7345 fmd->addSectionsToDefinition(root->anchors);
7346 fmd->setInitializer(root->initializer);
7347 fmd->setMaxInitLines(root->initLines);
7348 fmd->setMemberGroupId(root->mGrpId);
7349 fmd->setExplicitExternal(root->explicitExternal);
7350 fmd->setRefItems(root->sli);
7352 md->insertEnumField(fmd);
7353 fmd->setEnumScope(md,TRUE);
7354 MemberName *mn=mnsd->find(root->name);
7361 mn = new MemberName(root->name);
7363 mnsd->append(root->name,mn);
7370 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
7372 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
7373 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
7374 // get list of members with the same name as the field
7376 MemberNameIterator fmni(*fmn);
7378 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
7380 if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7382 //printf("found enum value with same name %s in scope %s\n",
7383 // fmd->name().data(),fmd->getOuterScope()->name().data());
7384 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7386 NamespaceDef *fnd=fmd->getNamespaceDef();
7387 if (fnd==nd) // enum value is inside a namespace
7389 md->insertEnumField(fmd);
7390 fmd->setEnumScope(md);
7395 FileDef *ffd=fmd->getFileDef();
7396 if (ffd==fd) // enum value has file scope
7398 md->insertEnumField(fmd);
7399 fmd->setEnumScope(md);
7402 else if (isRelated && cd) // reparent enum value to
7403 // match the enum's scope
7405 md->insertEnumField(fmd); // add field def to list
7406 fmd->setEnumScope(md); // cross ref with enum name
7407 fmd->setEnumClassScope(cd); // cross ref with enum name
7408 fmd->setOuterScope(cd);
7410 cd->insertMember(fmd);
7414 ClassDef *fcd=fmd->getClassDef();
7415 if (fcd==cd) // enum value is inside a class
7417 //printf("Inserting enum field %s in enum scope %s\n",
7418 // fmd->name().data(),md->name().data());
7419 md->insertEnumField(fmd); // add field def to list
7420 fmd->setEnumScope(md); // cross ref with enum name
7433 rootNav->releaseEntry();
7437 RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7442 //----------------------------------------------------------------------
7443 // find the documentation blocks for the enumerations
7445 static void findEnumDocumentation(EntryNav *rootNav)
7447 if (rootNav->section()==Entry::ENUMDOC_SEC
7448 && !rootNav->name().isEmpty()
7449 && rootNav->name().at(0)!='@' // skip anonymous enums
7452 rootNav->loadEntry(g_storage);
7453 Entry *root = rootNav->entry();
7455 //printf("Found docs for enum with name `%s' in context %s\n",
7456 // root->name.data(),root->parent->name.data());
7460 if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7462 name=root->name.right(root->name.length()-i-2); // extract name
7463 scope=root->name.left(i); // extract scope
7464 //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7466 else // just the name
7470 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7471 && !rootNav->parent()->name().isEmpty()
7472 ) // found enum docs inside a compound
7474 if (!scope.isEmpty()) scope.prepend("::");
7475 scope.prepend(rootNav->parent()->name());
7477 ClassDef *cd=getClass(scope);
7479 if (!name.isEmpty())
7484 //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7485 QCString className=cd->name().copy();
7486 MemberName *mn=Doxygen::memberNameSDict->find(name);
7489 MemberNameIterator mni(*mn);
7491 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7493 ClassDef *cd=md->getClassDef();
7494 if (cd && cd->name()==className && md->isEnumerate())
7496 // documentation outside a compound overrides the documentation inside it
7498 if (!md->documentation() || rootNav->parent()->name().isEmpty())
7501 md->setDocumentation(root->doc,root->docFile,root->docLine);
7502 md->setDocsForDefinition(!root->proto);
7505 // brief descriptions inside a compound override the documentation
7508 if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7511 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7514 if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7516 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7519 if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7521 md->setMemberGroupId(root->mGrpId);
7524 md->addSectionsToDefinition(root->anchors);
7525 md->setRefItems(root->sli);
7527 GroupDef *gd=md->getGroupDef();
7528 if (gd==0 &&root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7530 addMemberToGroups(root,md);
7539 //printf("MemberName %s not found!\n",name.data());
7542 else // enum outside class
7544 //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7545 MemberName *mn=Doxygen::functionNameSDict->find(name);
7548 MemberNameIterator mni(*mn);
7550 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7552 if (md->isEnumerate())
7554 md->setDocumentation(root->doc,root->docFile,root->docLine);
7555 md->setDocsForDefinition(!root->proto);
7556 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7557 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7558 md->addSectionsToDefinition(root->anchors);
7559 md->setMemberGroupId(root->mGrpId);
7561 GroupDef *gd=md->getGroupDef();
7562 if (gd==0 && root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7564 addMemberToGroups(root,md);
7574 warn(root->fileName,root->startLine,
7575 "Documentation for undefined enum `%s' found.",
7581 rootNav->releaseEntry();
7583 RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7586 // search for each enum (member or function) in mnl if it has documented
7588 static void findDEV(const MemberNameSDict &mnsd)
7591 MemberNameSDict::Iterator mnli(mnsd);
7592 // for each member name
7593 for (mnli.toFirst();(mn=mnli.current());++mnli)
7596 MemberNameIterator mni(*mn);
7597 // for each member definition
7598 for (mni.toFirst();(md=mni.current());++mni)
7600 if (md->isEnumerate()) // member is an enum
7602 MemberList *fmdl = md->enumFieldList();
7603 int documentedEnumValues=0;
7604 if (fmdl) // enum has values
7606 MemberListIterator fmni(*fmdl);
7608 // for each enum value
7609 for (fmni.toFirst();(fmd=fmni.current());++fmni)
7611 if (fmd->isLinkableInProject()) documentedEnumValues++;
7614 // at least one enum value is documented
7615 if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7621 // search for each enum (member or function) if it has documented enum
7623 static void findDocumentedEnumValues()
7625 findDEV(*Doxygen::memberNameSDict);
7626 findDEV(*Doxygen::functionNameSDict);
7629 //----------------------------------------------------------------------
7631 static void addMembersToIndex()
7634 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7635 // for each member name
7636 for (mnli.toFirst();(mn=mnli.current());++mnli)
7639 MemberNameIterator mni(*mn);
7640 // for each member definition
7641 for (mni.toFirst();(md=mni.current());++mni)
7643 addClassMemberNameToIndex(md);
7646 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7647 // for each member name
7648 for (fnli.toFirst();(mn=fnli.current());++fnli)
7651 MemberNameIterator mni(*mn);
7652 // for each member definition
7653 for (mni.toFirst();(md=mni.current());++mni)
7655 if (md->getNamespaceDef())
7657 addNamespaceMemberNameToIndex(md);
7661 addFileMemberNameToIndex(md);
7667 //----------------------------------------------------------------------
7668 // computes the relation between all members. For each member `m'
7669 // the members that override the implementation of `m' are searched and
7670 // the member that `m' overrides is searched.
7672 static void computeMemberRelations()
7674 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7676 for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7678 MemberNameIterator mdi(*mn);
7679 MemberNameIterator bmdi(*mn);
7682 for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7684 for ( bmdi.toFirst() ; (bmd=bmdi.current()); ++bmdi ) // for each other member with the same name
7686 ClassDef *mcd = md->getClassDef();
7687 if (mcd && mcd->baseClasses())
7689 ClassDef *bmcd = bmd->getClassDef();
7690 //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7691 // mcd->name().data(),md->name().data(),md,
7692 // bmcd->name().data(),bmd->name().data(),bmd
7694 if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
7695 (bmd->virtualness()!=Normal ||
7696 bmcd->compoundType()==ClassDef::Interface ||
7697 bmcd->compoundType()==ClassDef::Protocol
7700 mcd->isLinkable() &&
7701 bmcd->isLinkable() &&
7702 mcd->isBaseClass(bmcd,TRUE))
7704 //printf(" derived scope\n");
7705 ArgumentList *bmdAl = bmd->argumentList();
7706 ArgumentList *mdAl = md->argumentList();
7707 //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7708 // argListToString(bmdAl.pointer()).data(),
7709 // argListToString(mdAl.pointer()).data()
7712 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl,
7713 md->getOuterScope(), md->getFileDef(), mdAl,
7719 if ((rmd=md->reimplements())==0 ||
7720 minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7723 //printf("setting (new) reimplements member\n");
7724 md->setReimplements(bmd);
7726 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7727 bmd->insertReimplementedBy(md);
7737 //----------------------------------------------------------------------------
7738 //static void computeClassImplUsageRelations()
7741 // ClassSDict::Iterator cli(*Doxygen::classSDict);
7742 // for (;(cd=cli.current());++cli)
7744 // cd->determineImplUsageRelation();
7748 //----------------------------------------------------------------------------
7750 static void createTemplateInstanceMembers()
7752 ClassSDict::Iterator cli(*Doxygen::classSDict);
7755 for (cli.toFirst();(cd=cli.current());++cli)
7757 // that is a template
7758 QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7761 QDictIterator<ClassDef> qdi(*templInstances);
7763 // for each instance of the template
7764 for (qdi.toFirst();(tcd=qdi.current());++qdi)
7766 tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7772 //----------------------------------------------------------------------------
7774 static void mergeCategories()
7777 ClassSDict::Iterator cli(*Doxygen::classSDict);
7778 // merge members of categories into the class they extend
7779 for (cli.toFirst();(cd=cli.current());++cli)
7781 int i=cd->name().find('(');
7782 if (i!=-1) // it is an Objective-C category
7784 QCString baseName=cd->name().left(i);
7785 ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7788 //printf("*** merging members of category %s into %s\n",
7789 // cd->name().data(),baseClass->name().data());
7790 baseClass->mergeCategory(cd);
7796 // builds the list of all members for each class
7798 static void buildCompleteMemberLists()
7801 ClassSDict::Iterator cli(*Doxygen::classSDict);
7802 // merge the member list of base classes into the inherited classes.
7803 for (cli.toFirst();(cd=cli.current());++cli)
7805 if (// !cd->isReference() && // not an external class
7806 cd->subClasses()==0 && // is a root of the hierarchy
7807 cd->baseClasses()) // and has at least one base class
7809 //printf("*** merging members for %s\n",cd->name().data());
7813 // now sort the member list of all classes.
7814 for (cli.toFirst();(cd=cli.current());++cli)
7816 if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7820 //----------------------------------------------------------------------------
7822 static void generateFileSources()
7824 if (Doxygen::inputNameList->count()>0)
7827 static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
7828 if (clangAssistedParsing)
7830 QDict<void> g_processedFiles(10007);
7832 // create a dictionary with files to process
7833 QDict<void> g_filesToProcess(10007);
7834 FileNameListIterator fnli(*Doxygen::inputNameList);
7836 for (fnli.toFirst();(fn=fnli.current());++fnli)
7838 FileNameIterator fni(*fn);
7840 for (;(fd=fni.current());++fni)
7842 g_filesToProcess.insert(fd->absFilePath(),(void*)0x8);
7845 // process source files (and their include dependencies)
7846 for (fnli.toFirst();(fn=fnli.current());++fnli)
7848 FileNameIterator fni(*fn);
7850 for (;(fd=fni.current());++fni)
7852 if (fd->isSource() && !fd->isReference())
7854 QStrList filesInSameTu;
7855 fd->getAllIncludeFilesRecursively(filesInSameTu);
7857 if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7859 msg("Generating code for file %s...\n",fd->docName().data());
7860 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7863 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7864 // we needed to parse the sources even if we do not show them
7866 msg("Parsing code for file %s...\n",fd->docName().data());
7867 fd->parseSource(FALSE,filesInSameTu);
7870 char *incFile = filesInSameTu.first();
7871 while (incFile && g_filesToProcess.find(incFile))
7873 if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile))
7877 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
7878 if (ifd && !ifd->isReference())
7880 if (ifd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7882 msg(" Generating code for file %s...\n",ifd->docName().data());
7883 ifd->writeSource(*g_outputList,TRUE,moreFiles);
7886 else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
7887 // we needed to parse the sources even if we do not show them
7889 msg(" Parsing code for file %s...\n",ifd->docName().data());
7890 ifd->parseSource(TRUE,moreFiles);
7892 g_processedFiles.insert(incFile,(void*)0x8);
7895 incFile = filesInSameTu.next();
7897 fd->finishParsing();
7898 g_processedFiles.insert(fd->absFilePath(),(void*)0x8);
7902 // process remaining files
7903 for (fnli.toFirst();(fn=fnli.current());++fnli)
7905 FileNameIterator fni(*fn);
7907 for (;(fd=fni.current());++fni)
7909 if (!g_processedFiles.find(fd->absFilePath())) // not yet processed
7911 QStrList filesInSameTu;
7913 if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7915 msg("Generating code for file %s...\n",fd->docName().data());
7916 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7919 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7920 // we needed to parse the sources even if we do not show them
7922 msg("Parsing code for file %s...\n",fd->docName().data());
7923 fd->parseSource(FALSE,filesInSameTu);
7925 fd->finishParsing();
7933 FileNameListIterator fnli(*Doxygen::inputNameList);
7935 for (;(fn=fnli.current());++fnli)
7937 FileNameIterator fni(*fn);
7939 for (;(fd=fni.current());++fni)
7941 QStrList filesInSameTu;
7943 if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7945 msg("Generating code for file %s...\n",fd->docName().data());
7946 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7949 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7950 // we needed to parse the sources even if we do not show them
7952 msg("Parsing code for file %s...\n",fd->docName().data());
7953 fd->parseSource(FALSE,filesInSameTu);
7955 fd->finishParsing();
7962 //----------------------------------------------------------------------------
7964 static void generateFileDocs()
7966 if (documentedHtmlFiles==0) return;
7968 if (Doxygen::inputNameList->count()>0)
7970 FileNameListIterator fnli(*Doxygen::inputNameList);
7972 for (fnli.toFirst();(fn=fnli.current());++fnli)
7974 FileNameIterator fni(*fn);
7976 for (fni.toFirst();(fd=fni.current());++fni)
7978 bool doc = fd->isLinkableInProject();
7981 msg("Generating docs for file %s...\n",fd->docName().data());
7982 fd->writeDocumentation(*g_outputList);
7989 //----------------------------------------------------------------------------
7991 static void addSourceReferences()
7993 // add source references for class definitions
7994 ClassSDict::Iterator cli(*Doxygen::classSDict);
7996 for (cli.toFirst();(cd=cli.current());++cli)
7998 FileDef *fd=cd->getBodyDef();
7999 if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
8001 fd->addSourceRef(cd->getStartBodyLine(),cd,0);
8004 // add source references for namespace definitions
8005 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8007 for (nli.toFirst();(nd=nli.current());++nli)
8009 FileDef *fd=nd->getBodyDef();
8010 if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
8012 fd->addSourceRef(nd->getStartBodyLine(),nd,0);
8016 // add source references for member names
8017 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8019 for (mnli.toFirst();(mn=mnli.current());++mnli)
8021 MemberNameIterator mni(*mn);
8023 for (mni.toFirst();(md=mni.current());++mni)
8025 //printf("class member %s: def=%s body=%d link?=%d\n",
8026 // md->name().data(),
8027 // md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
8028 // md->getStartBodyLine(),md->isLinkableInProject());
8029 FileDef *fd=md->getBodyDef();
8031 md->getStartBodyLine()!=-1 &&
8032 md->isLinkableInProject() &&
8033 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
8036 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8037 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8038 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8042 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8043 for (fnli.toFirst();(mn=fnli.current());++fnli)
8045 MemberNameIterator mni(*mn);
8047 for (mni.toFirst();(md=mni.current());++mni)
8049 FileDef *fd=md->getBodyDef();
8050 //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
8051 // md->name().data(),
8052 // md->getStartBodyLine(),md->getEndBodyLine(),fd,
8053 // md->isLinkableInProject(),
8054 // Doxygen::parseSourcesNeeded);
8056 md->getStartBodyLine()!=-1 &&
8057 md->isLinkableInProject() &&
8058 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
8061 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8062 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8063 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8069 //----------------------------------------------------------------------------
8071 static void sortMemberLists()
8073 // sort class member lists
8074 ClassSDict::Iterator cli(*Doxygen::classSDict);
8076 for (cli.toFirst();(cd=cli.current());++cli)
8078 cd->sortMemberLists();
8081 // sort namespace member lists
8082 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8084 for (nli.toFirst();(nd=nli.current());++nli)
8086 nd->sortMemberLists();
8089 // sort file member lists
8090 FileNameListIterator fnli(*Doxygen::inputNameList);
8092 for (;(fn=fnli.current());++fnli)
8094 FileNameIterator fni(*fn);
8096 for (;(fd=fni.current());++fni)
8098 fd->sortMemberLists();
8102 // sort group member lists
8103 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8105 for (gli.toFirst();(gd=gli.current());++gli)
8107 gd->sortMemberLists();
8111 //----------------------------------------------------------------------------
8112 // generate the documentation of all classes
8114 static void generateClassList(ClassSDict &classSDict)
8116 ClassSDict::Iterator cli(classSDict);
8117 for ( ; cli.current() ; ++cli )
8119 ClassDef *cd=cli.current();
8121 //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
8123 (cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8124 cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8125 ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8128 // skip external references, anonymous compounds and
8129 // template instances
8130 if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8132 msg("Generating docs for compound %s...\n",cd->name().data());
8134 cd->writeDocumentation(*g_outputList);
8135 cd->writeMemberList(*g_outputList);
8137 // even for undocumented classes, the inner classes can be documented.
8138 cd->writeDocumentationForInnerClasses(*g_outputList);
8143 static void generateClassDocs()
8145 generateClassList(*Doxygen::classSDict);
8146 generateClassList(*Doxygen::hiddenClasses);
8149 //----------------------------------------------------------------------------
8151 static void inheritDocumentation()
8153 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8156 for (;(mn=mnli.current());++mnli)
8158 MemberNameIterator mni(*mn);
8160 for (;(md=mni.current());++mni)
8162 //printf("%04d Member `%s'\n",count++,md->name().data());
8163 if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
8164 { // no documentation yet
8165 MemberDef *bmd = md->reimplements();
8166 while (bmd && bmd->documentation().isEmpty() &&
8167 bmd->briefDescription().isEmpty()
8169 { // search up the inheritance tree for a documentation member
8170 //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
8171 bmd = bmd->reimplements();
8173 if (bmd) // copy the documentation from the reimplemented member
8175 md->setInheritsDocsFrom(bmd);
8176 md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8177 md->setDocsForDefinition(bmd->isDocsForDefinition());
8178 md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8179 md->copyArgumentNames(bmd);
8180 md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
8187 //----------------------------------------------------------------------------
8189 static void combineUsingRelations()
8192 FileNameListIterator fnli(*Doxygen::inputNameList);
8194 for (fnli.toFirst();(fn=fnli.current());++fnli)
8196 FileNameIterator fni(*fn);
8198 for (fni.toFirst();(fd=fni.current());++fni)
8203 for (fnli.toFirst();(fn=fnli.current());++fnli)
8205 FileNameIterator fni(*fn);
8207 for (fni.toFirst();(fd=fni.current());++fni)
8209 fd->combineUsingRelations();
8213 // for each namespace
8214 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8216 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8220 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8222 nd->combineUsingRelations();
8226 //----------------------------------------------------------------------------
8228 static void addMembersToMemberGroup()
8231 ClassSDict::Iterator cli(*Doxygen::classSDict);
8233 for ( ; (cd=cli.current()) ; ++cli )
8235 cd->addMembersToMemberGroup();
8238 FileNameListIterator fnli(*Doxygen::inputNameList);
8240 for (fnli.toFirst();(fn=fnli.current());++fnli)
8242 FileNameIterator fni(*fn);
8244 for (fni.toFirst();(fd=fni.current());++fni)
8246 fd->addMembersToMemberGroup();
8249 // for each namespace
8250 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8252 for ( ; (nd=nli.current()) ; ++nli )
8254 nd->addMembersToMemberGroup();
8257 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8259 for (gli.toFirst();(gd=gli.current());++gli)
8261 gd->addMembersToMemberGroup();
8265 //----------------------------------------------------------------------------
8267 static void distributeMemberGroupDocumentation()
8270 ClassSDict::Iterator cli(*Doxygen::classSDict);
8272 for ( ; (cd=cli.current()) ; ++cli )
8274 cd->distributeMemberGroupDocumentation();
8277 FileNameListIterator fnli(*Doxygen::inputNameList);
8279 for (fnli.toFirst();(fn=fnli.current());++fnli)
8281 FileNameIterator fni(*fn);
8283 for (fni.toFirst();(fd=fni.current());++fni)
8285 fd->distributeMemberGroupDocumentation();
8288 // for each namespace
8289 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8291 for ( ; (nd=nli.current()) ; ++nli )
8293 nd->distributeMemberGroupDocumentation();
8296 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8298 for (gli.toFirst();(gd=gli.current());++gli)
8300 gd->distributeMemberGroupDocumentation();
8304 //----------------------------------------------------------------------------
8306 static void findSectionsInDocumentation()
8309 ClassSDict::Iterator cli(*Doxygen::classSDict);
8311 for ( ; (cd=cli.current()) ; ++cli )
8313 cd->findSectionsInDocumentation();
8316 FileNameListIterator fnli(*Doxygen::inputNameList);
8318 for (fnli.toFirst();(fn=fnli.current());++fnli)
8320 FileNameIterator fni(*fn);
8322 for (fni.toFirst();(fd=fni.current());++fni)
8324 fd->findSectionsInDocumentation();
8327 // for each namespace
8328 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8330 for ( ; (nd=nli.current()) ; ++nli )
8332 nd->findSectionsInDocumentation();
8335 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8337 for (gli.toFirst();(gd=gli.current());++gli)
8339 gd->findSectionsInDocumentation();
8342 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8344 for (pdi.toFirst();(pd=pdi.current());++pdi)
8346 pd->findSectionsInDocumentation();
8348 if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8351 static void flushCachedTemplateRelations()
8353 // remove all references to classes from the cache
8354 // as there can be new template instances in the inheritance path
8355 // to this class. Optimization: only remove those classes that
8356 // have inheritance instances as direct or indirect sub classes.
8357 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8359 for (ci.toFirst();(li=ci.current());++ci)
8363 Doxygen::lookupCache->remove(ci.currentKey());
8366 // remove all cached typedef resolutions whose target is a
8367 // template class as this may now be a template instance
8368 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8370 for (;(fn=fnli.current());++fnli) // for each global function name
8372 MemberNameIterator fni(*fn);
8374 for (;(fmd=fni.current());++fni) // for each function with that name
8376 if (fmd->isTypedefValCached())
8378 ClassDef *cd = fmd->getCachedTypedefVal();
8379 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8383 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8384 for (;(fn=mnli.current());++mnli) // for each class method name
8386 MemberNameIterator mni(*fn);
8388 for (;(fmd=mni.current());++mni) // for each function with that name
8390 if (fmd->isTypedefValCached())
8392 ClassDef *cd = fmd->getCachedTypedefVal();
8393 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8399 //----------------------------------------------------------------------------
8401 static void flushUnresolvedRelations()
8403 // Remove all unresolved references to classes from the cache.
8404 // This is needed before resolving the inheritance relations, since
8405 // it would otherwise not find the inheritance relation
8406 // for C in the example below, as B::I was already found to be unresolvable
8407 // (which is correct if you ignore the inheritance relation between A and B).
8409 // class A { class I {} };
8410 // class B : public A {};
8411 // class C : public B::I {};
8413 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8415 for (ci.toFirst();(li=ci.current());++ci)
8417 if (li->classDef==0 && li->typeDef==0)
8419 Doxygen::lookupCache->remove(ci.currentKey());
8423 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8425 for (;(fn=fnli.current());++fnli) // for each global function name
8427 MemberNameIterator fni(*fn);
8429 for (;(fmd=fni.current());++fni) // for each function with that name
8431 fmd->invalidateCachedArgumentTypes();
8434 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8435 for (;(fn=mnli.current());++mnli) // for each class method name
8437 MemberNameIterator mni(*fn);
8439 for (;(fmd=mni.current());++mni) // for each function with that name
8441 fmd->invalidateCachedArgumentTypes();
8447 //----------------------------------------------------------------------------
8449 static void findDefineDocumentation(EntryNav *rootNav)
8451 if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
8452 rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
8455 rootNav->loadEntry(g_storage);
8456 Entry *root = rootNav->entry();
8458 //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
8459 // root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
8461 if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8463 MemberDef *md=new MemberDef(rootNav->tagInfo()->tagName,1,1,
8464 "#define",root->name,root->args,0,
8465 Public,Normal,FALSE,Member,MemberType_Define,0,0);
8466 md->setTagInfo(rootNav->tagInfo());
8467 md->setLanguage(root->lang);
8468 //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
8469 md->setFileDef(rootNav->parent()->fileDef());
8470 //printf("Adding member=%s\n",md->name().data());
8472 if ((mn=Doxygen::functionNameSDict->find(root->name)))
8478 mn = new MemberName(root->name);
8480 Doxygen::functionNameSDict->append(root->name,mn);
8483 MemberName *mn=Doxygen::functionNameSDict->find(root->name);
8486 MemberNameIterator mni(*mn);
8489 for (;(md=mni.current());++mni)
8491 if (md->memberType()==MemberType_Define) count++;
8495 for (mni.toFirst();(md=mni.current());++mni)
8497 if (md->memberType()==MemberType_Define)
8499 md->setDocumentation(root->doc,root->docFile,root->docLine);
8500 md->setDocsForDefinition(!root->proto);
8501 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8502 if (md->inbodyDocumentation().isEmpty())
8504 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8506 md->setBodySegment(root->bodyLine,root->endBodyLine);
8507 md->setBodyDef(rootNav->fileDef());
8508 md->addSectionsToDefinition(root->anchors);
8509 md->setMaxInitLines(root->initLines);
8510 md->setRefItems(root->sli);
8511 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8512 addMemberToGroups(root,md);
8517 (!root->doc.isEmpty() ||
8518 !root->brief.isEmpty() ||
8522 // multiple defines don't know where to add docs
8523 // but maybe they are in different files together with their documentation
8525 for (mni.toFirst();(md=mni.current());++mni)
8527 if (md->memberType()==MemberType_Define)
8529 FileDef *fd=md->getFileDef();
8530 if (fd && fd->absFilePath()==root->fileName)
8531 // doc and define in the same file assume they belong together.
8534 if (md->documentation().isEmpty())
8537 md->setDocumentation(root->doc,root->docFile,root->docLine);
8538 md->setDocsForDefinition(!root->proto);
8541 if (md->briefDescription().isEmpty())
8544 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8546 if (md->inbodyDocumentation().isEmpty())
8548 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8550 md->setBodySegment(root->bodyLine,root->endBodyLine);
8551 md->setBodyDef(rootNav->fileDef());
8552 md->addSectionsToDefinition(root->anchors);
8553 md->setRefItems(root->sli);
8554 md->setLanguage(root->lang);
8555 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8556 addMemberToGroups(root,md);
8560 //warn("define %s found in the following files:\n",root->name.data());
8561 //warn("Cannot determine where to add the documentation found "
8562 // "at line %d of file %s. \n",
8563 // root->startLine,root->fileName.data());
8566 else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8568 static bool preEnabled = Config_getBool(ENABLE_PREPROCESSING);
8571 warn(root->fileName,root->startLine,
8572 "documentation for unknown define %s found.\n",
8578 warn(root->fileName,root->startLine,
8579 "found documented #define but ignoring it because "
8580 "ENABLE_PREPROCESSING is NO.\n",
8586 rootNav->releaseEntry();
8588 RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8591 //----------------------------------------------------------------------------
8593 static void findDirDocumentation(EntryNav *rootNav)
8595 if (rootNav->section() == Entry::DIRDOC_SEC)
8597 rootNav->loadEntry(g_storage);
8598 Entry *root = rootNav->entry();
8600 QCString normalizedName = root->name;
8601 normalizedName = substitute(normalizedName,"\\","/");
8602 //printf("root->docFile=%s normalizedName=%s\n",
8603 // root->docFile.data(),normalizedName.data());
8604 if (root->docFile==normalizedName) // current dir?
8606 int lastSlashPos=normalizedName.findRev('/');
8607 if (lastSlashPos!=-1) // strip file name
8609 normalizedName=normalizedName.left(lastSlashPos);
8612 if (normalizedName.at(normalizedName.length()-1)!='/')
8614 normalizedName+='/';
8616 DirDef *dir,*matchingDir=0;
8617 SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8618 for (sdi.toFirst();(dir=sdi.current());++sdi)
8620 //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8621 if (dir->name().right(normalizedName.length())==normalizedName)
8625 warn(root->fileName,root->startLine,
8626 "\\dir command matches multiple directories.\n"
8627 " Applying the command for directory %s\n"
8628 " Ignoring the command for directory %s\n",
8629 matchingDir->name().data(),dir->name().data()
8640 //printf("Match for with dir %s\n",matchingDir->name().data());
8641 matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8642 matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8643 matchingDir->setRefItems(root->sli);
8644 addDirToGroups(root,matchingDir);
8648 warn(root->fileName,root->startLine,"No matching "
8649 "directory found for command \\dir %s\n",normalizedName.data());
8651 rootNav->releaseEntry();
8653 RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8657 //----------------------------------------------------------------------------
8658 // create a (sorted) list of separate documentation pages
8660 static void buildPageList(EntryNav *rootNav)
8662 if (rootNav->section() == Entry::PAGEDOC_SEC)
8664 rootNav->loadEntry(g_storage);
8665 Entry *root = rootNav->entry();
8667 if (!root->name.isEmpty())
8669 addRelatedPage(rootNav);
8672 rootNav->releaseEntry();
8674 else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8676 rootNav->loadEntry(g_storage);
8677 Entry *root = rootNav->entry();
8679 QCString title=root->args.stripWhiteSpace();
8680 if (title.isEmpty()) title=theTranslator->trMainPage();
8681 //QCString name = Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8682 QCString name = "index";
8683 addRefItem(root->sli,
8691 rootNav->releaseEntry();
8693 RECURSE_ENTRYTREE(buildPageList,rootNav);
8696 // search for the main page defined in this project
8697 static void findMainPage(EntryNav *rootNav)
8699 if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8701 rootNav->loadEntry(g_storage);
8703 if (Doxygen::mainPage==0 && rootNav->tagInfo()==0)
8705 Entry *root = rootNav->entry();
8706 //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8707 QCString title=root->args.stripWhiteSpace();
8708 //QCString indexName=Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8709 QCString indexName="index";
8710 Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8711 indexName, root->brief+root->doc+root->inbodyDocs,title);
8712 //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8713 Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8714 Doxygen::mainPage->setFileName(indexName);
8715 Doxygen::mainPage->setShowToc(root->stat);
8716 addPageToContext(Doxygen::mainPage,rootNav);
8718 SectionInfo *si = Doxygen::sectionDict->find(Doxygen::mainPage->name());
8721 if (si->lineNr != -1)
8723 warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s, line %d)",Doxygen::mainPage->name().data(),si->fileName.data(),si->lineNr);
8727 warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s)",Doxygen::mainPage->name().data(),si->fileName.data());
8732 // a page name is a label as well! but should no be double either
8734 indexName, root->startLine,
8735 Doxygen::mainPage->name(),
8736 Doxygen::mainPage->title(),
8739 Doxygen::sectionDict->append(indexName,si);
8740 Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8743 else if (rootNav->tagInfo()==0)
8745 Entry *root = rootNav->entry();
8746 warn(root->fileName,root->startLine,
8747 "found more than one \\mainpage comment block! (first occurrence: %s, line %d), Skipping current block!",
8748 Doxygen::mainPage->docFile().data(),Doxygen::mainPage->docLine());
8751 rootNav->releaseEntry();
8753 RECURSE_ENTRYTREE(findMainPage,rootNav);
8756 // search for the main page imported via tag files and add only the section labels
8757 static void findMainPageTagFiles(EntryNav *rootNav)
8759 if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8761 rootNav->loadEntry(g_storage);
8763 if (Doxygen::mainPage && rootNav->tagInfo())
8765 Entry *root = rootNav->entry();
8766 Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8769 RECURSE_ENTRYTREE(findMainPageTagFiles,rootNav);
8772 static void computePageRelations(EntryNav *rootNav)
8774 if ((rootNav->section()==Entry::PAGEDOC_SEC ||
8775 rootNav->section()==Entry::MAINPAGEDOC_SEC
8777 && !rootNav->name().isEmpty()
8780 rootNav->loadEntry(g_storage);
8781 Entry *root = rootNav->entry();
8783 PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8784 Doxygen::pageSDict->find(root->name) :
8788 QListIterator<BaseInfo> bii(*root->extends);
8790 for (bii.toFirst();(bi=bii.current());++bii)
8792 PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8795 pd->addInnerCompound(subPd);
8796 //printf("*** Added subpage relation: %s->%s\n",
8797 // pd->name().data(),subPd->name().data());
8802 rootNav->releaseEntry();
8804 RECURSE_ENTRYTREE(computePageRelations,rootNav);
8807 static void checkPageRelations()
8809 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8811 for (pdi.toFirst();(pd=pdi.current());++pdi)
8813 Definition *ppd = pd->getOuterScope();
8818 err("page defined at line %d of file %s with label %s is a subpage "
8819 "of itself! Please remove this cyclic dependency.\n",
8820 pd->docLine(),pd->docFile().data(),pd->name().data());
8823 ppd=ppd->getOuterScope();
8828 //----------------------------------------------------------------------------
8830 static void resolveUserReferences()
8832 SDict<SectionInfo>::Iterator sdi(*Doxygen::sectionDict);
8834 for (;(si=sdi.current());++sdi)
8836 //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8837 // si->label.data(),si->definition?si->definition->name().data():"<none>",
8838 // si->fileName.data());
8841 // hack: the items of a todo/test/bug/deprecated list are all fragments from
8842 // different files, so the resulting section's all have the wrong file
8843 // name (not from the todo/test/bug/deprecated list, but from the file in
8844 // which they are defined). We correct this here by looking at the
8845 // generated section labels!
8846 QDictIterator<RefList> rli(*Doxygen::xrefLists);
8848 for (rli.toFirst();(rl=rli.current());++rli)
8850 QCString label="_"+rl->listName(); // "_todo", "_test", ...
8851 if (si->label.left(label.length())==label)
8853 si->fileName=rl->listName();
8859 //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8862 // if this section is in a page and the page is in a group, then we
8863 // have to adjust the link file name to point to the group.
8864 if (!si->fileName.isEmpty() &&
8865 (pd=Doxygen::pageSDict->find(si->fileName)) &&
8868 si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8873 // TODO: there should be one function in Definition that returns
8874 // the file to link to, so we can avoid the following tests.
8876 if (si->definition->definitionType()==Definition::TypeMember)
8878 gd = ((MemberDef *)si->definition)->getGroupDef();
8883 si->fileName=gd->getOutputFileBase().copy();
8887 //si->fileName=si->definition->getOutputFileBase().copy();
8888 //printf("Setting si->fileName to %s\n",si->fileName.data());
8892 //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8898 //----------------------------------------------------------------------------
8899 // generate all separate documentation pages
8902 static void generatePageDocs()
8904 //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8905 if (documentedPages==0) return;
8906 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8908 for (pdi.toFirst();(pd=pdi.current());++pdi)
8910 if (!pd->getGroupDef() && !pd->isReference())
8912 msg("Generating docs for page %s...\n",pd->name().data());
8913 Doxygen::insideMainPage=TRUE;
8914 pd->writeDocumentation(*g_outputList);
8915 Doxygen::insideMainPage=FALSE;
8920 //----------------------------------------------------------------------------
8921 // create a (sorted) list & dictionary of example pages
8923 static void buildExampleList(EntryNav *rootNav)
8925 if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty())
8927 rootNav->loadEntry(g_storage);
8928 Entry *root = rootNav->entry();
8930 if (Doxygen::exampleSDict->find(root->name))
8932 warn(root->fileName,root->startLine,
8933 "Example %s was already documented. Ignoring "
8934 "documentation found here.",
8940 PageDef *pd=new PageDef(root->fileName,root->startLine,
8941 root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8942 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8943 pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
8944 pd->addSectionsToDefinition(root->anchors);
8945 pd->setLanguage(root->lang);
8946 //pi->addSections(root->anchors);
8948 Doxygen::exampleSDict->inSort(root->name,pd);
8949 //we don't add example to groups
8950 //addExampleToGroups(root,pd);
8953 rootNav->releaseEntry();
8955 RECURSE_ENTRYTREE(buildExampleList,rootNav);
8958 //----------------------------------------------------------------------------
8959 // prints the Entry tree (for debugging)
8961 void printNavTree(EntryNav *rootNav,int indent)
8964 indentStr.fill(' ',indent);
8965 msg("%s%s (sec=0x%x)\n",
8966 indentStr.isEmpty()?"":indentStr.data(),
8967 rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8968 rootNav->section());
8969 if (rootNav->children())
8971 EntryNavListIterator eli(*rootNav->children());
8972 for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8977 //----------------------------------------------------------------------------
8978 // generate the example documentation
8980 static void generateExampleDocs()
8982 g_outputList->disable(OutputGenerator::Man);
8983 PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8985 for (pdi.toFirst();(pd=pdi.current());++pdi)
8987 msg("Generating docs for example %s...\n",pd->name().data());
8988 resetCCodeParserState();
8989 QCString n=pd->getOutputFileBase();
8990 startFile(*g_outputList,n,n,pd->name());
8991 startTitle(*g_outputList,n);
8992 g_outputList->docify(pd->name());
8993 endTitle(*g_outputList,n,0);
8994 g_outputList->startContents();
8995 g_outputList->generateDoc(pd->docFile(), // file
8996 pd->docLine(), // startLine
8999 pd->documentation()+"\n\n\\include "+pd->name(), // docs
9000 TRUE, // index words
9004 endFile(*g_outputList); // contains g_outputList->endContents()
9006 g_outputList->enable(OutputGenerator::Man);
9009 //----------------------------------------------------------------------------
9010 // generate module pages
9012 static void generateGroupDocs()
9014 GroupSDict::Iterator gli(*Doxygen::groupSDict);
9016 for (gli.toFirst();(gd=gli.current());++gli)
9018 if (!gd->isReference())
9020 gd->writeDocumentation(*g_outputList);
9025 //----------------------------------------------------------------------------
9027 //static void generatePackageDocs()
9029 // writePackageIndex(*g_outputList);
9031 // if (Doxygen::packageDict.count()>0)
9033 // PackageSDict::Iterator pdi(Doxygen::packageDict);
9035 // for (pdi.toFirst();(pd=pdi.current());++pdi)
9037 // pd->writeDocumentation(*g_outputList);
9042 //----------------------------------------------------------------------------
9043 // generate module pages
9045 static void generateNamespaceDocs()
9047 //writeNamespaceIndex(*g_outputList);
9049 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
9051 // for each namespace...
9052 for (;(nd=nli.current());++nli)
9055 if (nd->isLinkableInProject())
9057 msg("Generating docs for namespace %s\n",nd->name().data());
9058 nd->writeDocumentation(*g_outputList);
9061 // for each class in the namespace...
9062 ClassSDict::Iterator cli(*nd->getClassSDict());
9064 for ( ; (cd=cli.current()) ; ++cli )
9066 if ( ( cd->isLinkableInProject() &&
9067 cd->templateMaster()==0
9068 ) // skip external references, anonymous compounds and
9069 // template instances and nested classes
9070 && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
9073 msg("Generating docs for compound %s...\n",cd->name().data());
9075 cd->writeDocumentation(*g_outputList);
9076 cd->writeMemberList(*g_outputList);
9078 cd->writeDocumentationForInnerClasses(*g_outputList);
9084 static QCString fixSlashes(QCString &s)
9088 for (i=0;i<s.length();i++)
9105 //----------------------------------------------------------------------------
9107 /*! Generate a template version of the configuration file.
9108 * If the \a shortList parameter is TRUE a configuration file without
9109 * comments will be generated.
9111 static void generateConfigFile(const char *configFile,bool shortList,
9112 bool updateOnly=FALSE)
9115 bool fileOpened=openOutputFile(configFile,f);
9116 bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
9120 Config::writeTemplate(t,shortList,updateOnly);
9125 msg("\n\nConfiguration file `%s' created.\n\n",configFile);
9126 msg("Now edit the configuration file and enter\n\n");
9127 if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
9128 msg(" doxygen %s\n\n",configFile);
9130 msg(" doxygen\n\n");
9131 msg("to generate the documentation for your project\n\n");
9135 msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
9141 err("Cannot open file %s for writing\n",configFile);
9146 //----------------------------------------------------------------------------
9147 // read and parse a tag file
9149 //static bool readLineFromFile(QFile &f,QCString &s)
9153 // while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
9154 // return f.atEnd();
9157 //----------------------------------------------------------------------------
9159 static void readTagFile(Entry *root,const char *tl)
9161 QCString tagLine = tl;
9164 int eqPos = tagLine.find('=');
9165 if (eqPos!=-1) // tag command contains a destination
9167 fileName = tagLine.left(eqPos).stripWhiteSpace();
9168 destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9169 QFileInfo fi(fileName);
9170 Doxygen::tagDestinationDict.insert(fi.absFilePath().utf8(),new QCString(destName));
9171 //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
9178 QFileInfo fi(fileName);
9179 if (!fi.exists() || !fi.isFile())
9181 err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
9186 if (!destName.isEmpty())
9187 msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
9189 msg("Reading tag file `%s'...\n",fileName.data());
9191 parseTagFile(root,fi.absFilePath().utf8());
9194 //----------------------------------------------------------------------------
9195 static void copyLatexStyleSheet()
9197 QStrList latexExtraStyleSheet = Config_getList(LATEX_EXTRA_STYLESHEET);
9198 for (uint i=0; i<latexExtraStyleSheet.count(); ++i)
9200 QCString fileName(latexExtraStyleSheet.at(i));
9201 if (!fileName.isEmpty())
9203 QFileInfo fi(fileName);
9206 err("Style sheet '%s' specified by LATEX_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9210 QCString destFileName = Config_getString(LATEX_OUTPUT)+"/"+fi.fileName().data();
9211 if (!checkExtension(fi.fileName().data(), latexStyleExtension))
9213 destFileName += latexStyleExtension;
9215 copyFile(fileName, destFileName);
9221 //----------------------------------------------------------------------------
9222 static void copyStyleSheet()
9224 QCString &htmlStyleSheet = Config_getString(HTML_STYLESHEET);
9225 if (!htmlStyleSheet.isEmpty())
9227 QFileInfo fi(htmlStyleSheet);
9230 err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
9231 htmlStyleSheet.resize(0); // revert to the default
9235 QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9236 copyFile(htmlStyleSheet,destFileName);
9239 QStrList htmlExtraStyleSheet = Config_getList(HTML_EXTRA_STYLESHEET);
9240 for (uint i=0; i<htmlExtraStyleSheet.count(); ++i)
9242 QCString fileName(htmlExtraStyleSheet.at(i));
9243 if (!fileName.isEmpty())
9245 QFileInfo fi(fileName);
9248 err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9250 else if (fi.fileName()=="doxygen.css" || fi.fileName()=="tabs.css" || fi.fileName()=="navtree.css")
9252 err("Style sheet %s specified by HTML_EXTRA_STYLESHEET is already a built-in stylesheet. Please use a different name\n",fi.fileName().data());
9256 QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9257 copyFile(fileName, destFileName);
9263 static void copyLogo(const QCString &outputOption)
9265 QCString &projectLogo = Config_getString(PROJECT_LOGO);
9266 if (!projectLogo.isEmpty())
9268 QFileInfo fi(projectLogo);
9271 err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
9272 projectLogo.resize(0); // revert to the default
9276 QCString destFileName = outputOption+"/"+fi.fileName().data();
9277 copyFile(projectLogo,destFileName);
9278 Doxygen::indexList->addImageFile(fi.fileName().data());
9283 static void copyExtraFiles(QStrList files,const QString &filesOption,const QCString &outputOption)
9286 for (i=0; i<files.count(); ++i)
9288 QCString fileName(files.at(i));
9290 if (!fileName.isEmpty())
9292 QFileInfo fi(fileName);
9295 err("Extra file '%s' specified in %s does not exist!\n", fileName.data(),filesOption.data());
9299 QCString destFileName = outputOption+"/"+fi.fileName().data();
9300 Doxygen::indexList->addImageFile(fi.fileName().utf8());
9301 copyFile(fileName, destFileName);
9307 //----------------------------------------------------------------------------
9309 static ParserInterface *getParserForFile(const char *fn)
9311 QCString fileName=fn;
9313 int sep = fileName.findRev('/');
9314 int ei = fileName.findRev('.');
9315 if (ei!=-1 && (sep==-1 || ei>sep)) // matches dir/file.ext but not dir.1/file
9317 extension=fileName.right(fileName.length()-ei);
9321 extension = ".no_extension";
9324 return Doxygen::parserManager->getParser(extension);
9327 static void parseFile(ParserInterface *parser,
9328 Entry *root,EntryNav *rootNav,FileDef *fd,const char *fn,
9329 bool sameTu,QStrList &filesInSameTu)
9332 static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9334 static bool clangAssistedParsing = FALSE;
9336 QCString fileName=fn;
9338 int ei = fileName.findRev('.');
9341 extension=fileName.right(fileName.length()-ei);
9345 extension = ".no_extension";
9348 QFileInfo fi(fileName);
9349 BufStr preBuf(fi.size()+4096);
9351 if (Config_getBool(ENABLE_PREPROCESSING) &&
9352 parser->needsPreprocessing(extension))
9354 BufStr inBuf(fi.size()+4096);
9355 msg("Preprocessing %s...\n",fn);
9356 readInputFile(fileName,inBuf);
9357 preprocessFile(fileName,inBuf,preBuf);
9359 else // no preprocessing
9361 msg("Reading %s...\n",fn);
9362 readInputFile(fileName,preBuf);
9364 if (preBuf.data() && preBuf.curPos()>0 && *(preBuf.data()+preBuf.curPos()-1)!='\n')
9366 preBuf.addChar('\n'); // add extra newline to help parser
9369 BufStr convBuf(preBuf.curPos()+1024);
9371 // convert multi-line C++ comments to C style comments
9372 convertCppComments(&preBuf,&convBuf,fileName);
9374 convBuf.addChar('\0');
9376 if (clangAssistedParsing && !sameTu)
9378 fd->getAllIncludeFilesRecursively(filesInSameTu);
9381 // use language parse to parse the file
9382 parser->parseInput(fileName,convBuf.data(),root,sameTu,filesInSameTu);
9384 // store the Entry tree in a file and create an index to
9385 // navigate/load entries
9386 //printf("root->createNavigationIndex for %s\n",fd->name().data());
9387 root->createNavigationIndex(rootNav,g_storage,fd);
9390 //! parse the list of input files
9391 static void parseFiles(Entry *root,EntryNav *rootNav)
9394 static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9395 if (clangAssistedParsing)
9397 QDict<void> g_processedFiles(10007);
9399 // create a dictionary with files to process
9400 QDict<void> g_filesToProcess(10007);
9401 StringListIterator it(g_inputFiles);
9403 for (;(s=it.current());++it)
9405 g_filesToProcess.insert(*s,(void*)0x8);
9408 // process source files (and their include dependencies)
9409 for (it.toFirst();(s=it.current());++it)
9412 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9414 if (fd->isSource() && !fd->isReference()) // this is a source file
9416 QStrList filesInSameTu;
9417 ParserInterface * parser = getParserForFile(s->data());
9418 parser->startTranslationUnit(s->data());
9419 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9420 //printf(" got %d extra files in tu\n",filesInSameTu.count());
9422 // Now process any include files in the same translation unit
9423 // first. When libclang is used this is much more efficient.
9424 char *incFile = filesInSameTu.first();
9425 while (incFile && g_filesToProcess.find(incFile))
9427 if (qstrcmp(incFile,s->data()) && !g_processedFiles.find(incFile))
9429 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
9430 if (ifd && !ifd->isReference())
9433 //printf(" Processing %s in same translation unit as %s\n",incFile,s->data());
9434 parseFile(parser,root,rootNav,ifd,incFile,TRUE,moreFiles);
9435 g_processedFiles.insert(incFile,(void*)0x8);
9438 incFile = filesInSameTu.next();
9440 parser->finishTranslationUnit();
9441 g_processedFiles.insert(*s,(void*)0x8);
9444 // process remaining files
9445 for (it.toFirst();(s=it.current());++it)
9447 if (!g_processedFiles.find(*s)) // not yet processed
9450 QStrList filesInSameTu;
9451 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9453 ParserInterface * parser = getParserForFile(s->data());
9454 parser->startTranslationUnit(s->data());
9455 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9456 parser->finishTranslationUnit();
9457 g_processedFiles.insert(*s,(void*)0x8);
9461 else // normal pocessing
9464 StringListIterator it(g_inputFiles);
9466 for (;(s=it.current());++it)
9469 QStrList filesInSameTu;
9470 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9472 ParserInterface * parser = getParserForFile(s->data());
9473 parser->startTranslationUnit(s->data());
9474 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9479 // resolves a path that may include symlinks, if a recursive symlink is
9480 // found an empty string is returned.
9481 static QCString resolveSymlink(QCString path)
9486 QDict<void> nonSymlinks;
9488 QCString result = path;
9489 QCString oldPrefix = "/";
9493 // UNC path, skip server and share name
9494 if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
9495 sepPos = result.find('/',2);
9497 sepPos = result.find('/',sepPos+1);
9499 sepPos = result.find('/',sepPos+1);
9501 QCString prefix = sepPos==-1 ? result : result.left(sepPos);
9502 if (nonSymlinks.find(prefix)==0)
9507 QString target = fi.readLink();
9508 bool isRelative = QFileInfo(target).isRelative();
9511 target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
9515 if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
9519 target+=result.mid(sepPos);
9521 result = QDir::cleanDirPath(target).data();
9523 if (known.find(result)) return QCString(); // recursive symlink!
9524 known.insert(result,(void*)0x8);
9529 else // link to absolute path
9537 nonSymlinks.insert(prefix,(void*)0x8);
9544 return QDir::cleanDirPath(result).data();
9547 static QDict<void> g_pathsVisited(1009);
9549 //----------------------------------------------------------------------------
9550 // Read all files matching at least one pattern in `patList' in the
9551 // directory represented by `fi'.
9552 // The directory is read iff the recusiveFlag is set.
9553 // The contents of all files is append to the input string
9555 int readDir(QFileInfo *fi,
9556 FileNameList *fnList,
9557 FileNameDict *fnDict,
9558 StringDict *exclDict,
9560 QStrList *exclPatList,
9561 StringList *resultList,
9562 StringDict *resultDict,
9563 bool errorIfNotExist,
9565 QDict<void> *killDict,
9569 QCString dirName = fi->absFilePath().utf8();
9570 if (paths && paths->find(dirName)==0)
9572 paths->insert(dirName,(void*)0x8);
9574 if (fi->isSymLink())
9576 dirName = resolveSymlink(dirName.data());
9577 if (dirName.isEmpty()) return 0; // recusive symlink
9578 if (g_pathsVisited.find(dirName)) return 0; // already visited path
9579 g_pathsVisited.insert(dirName,(void*)0x8);
9582 dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
9584 msg("Searching for files in directory %s\n", fi->absFilePath().data());
9585 //printf("killDict=%p count=%d\n",killDict,killDict->count());
9587 const QFileInfoList *list = dir.entryInfoList();
9590 QFileInfoListIterator it( *list );
9593 while ((cfi=it.current()))
9595 if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0)
9596 { // file should not be excluded
9597 //printf("killDict->find(%s)\n",cfi->absFilePath().data());
9598 if (!cfi->exists() || !cfi->isReadable())
9600 if (errorIfNotExist)
9602 warn_uncond("source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
9605 else if (cfi->isFile() &&
9606 (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9607 (patList==0 || patternMatch(*cfi,patList)) &&
9608 !patternMatch(*cfi,exclPatList) &&
9609 (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
9612 totalSize+=cfi->size()+cfi->absFilePath().length()+4;
9613 QCString name=cfi->fileName().utf8();
9614 //printf("New file %s\n",name.data());
9617 FileDef *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
9619 if (!name.isEmpty() && (fn=(*fnDict)[name]))
9625 fn = new FileName(cfi->absFilePath().utf8(),name);
9627 if (fnList) fnList->inSort(fn);
9628 fnDict->insert(name,fn);
9632 if (resultList || resultDict)
9634 rs=new QCString(cfi->absFilePath().utf8());
9636 if (resultList) resultList->append(rs);
9637 if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
9638 if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
9640 else if (recursive &&
9641 (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9643 !patternMatch(*cfi,exclPatList) &&
9644 cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
9646 cfi->setFile(cfi->absFilePath());
9647 totalSize+=readDir(cfi,fnList,fnDict,exclDict,
9648 patList,exclPatList,resultList,resultDict,errorIfNotExist,
9649 recursive,killDict,paths);
9659 //----------------------------------------------------------------------------
9660 // read a file or all files in a directory and append their contents to the
9661 // input string. The names of the files are appended to the `fiList' list.
9663 int readFileOrDirectory(const char *s,
9664 FileNameList *fnList,
9665 FileNameDict *fnDict,
9666 StringDict *exclDict,
9668 QStrList *exclPatList,
9669 StringList *resultList,
9670 StringDict *resultDict,
9672 bool errorIfNotExist,
9673 QDict<void> *killDict,
9677 //printf("killDict=%p count=%d\n",killDict,killDict->count());
9678 // strip trailing slashes
9681 char lc = fs.at(fs.length()-1);
9682 if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9685 //printf("readFileOrDirectory(%s)\n",s);
9688 if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9690 if (!fi.exists() || !fi.isReadable())
9692 if (errorIfNotExist)
9694 warn_uncond("source %s is not a readable file or directory... skipping.\n",s);
9697 else if (!Config_getBool(EXCLUDE_SYMLINKS) || !fi.isSymLink())
9701 QCString dirPath = fi.dirPath(TRUE).utf8();
9702 QCString filePath = fi.absFilePath().utf8();
9703 if (paths && paths->find(dirPath))
9705 paths->insert(dirPath,(void*)0x8);
9707 //printf("killDict->find(%s)\n",fi.absFilePath().data());
9708 if (killDict==0 || killDict->find(filePath)==0)
9710 totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input);
9711 //fiList->inSort(new FileInfo(fi));
9712 QCString name=fi.fileName().utf8();
9713 //printf("New file %s\n",name.data());
9716 FileDef *fd=new FileDef(dirPath+"/",name);
9718 if (!name.isEmpty() && (fn=(*fnDict)[name]))
9724 fn = new FileName(filePath,name);
9726 if (fnList) fnList->inSort(fn);
9727 fnDict->insert(name,fn);
9731 if (resultList || resultDict)
9733 rs=new QCString(filePath);
9734 if (resultList) resultList->append(rs);
9735 if (resultDict) resultDict->insert(filePath,rs);
9738 if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9741 else if (fi.isDir()) // readable dir
9743 totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9744 exclPatList,resultList,resultDict,errorIfNotExist,
9745 recursive,killDict,paths);
9753 //----------------------------------------------------------------------------
9755 void readFormulaRepository()
9757 QFile f(Config_getString(HTML_OUTPUT)+"/formula.repository");
9758 if (f.open(IO_ReadOnly)) // open repository
9760 msg("Reading formula repository...\n");
9765 line=t.readLine().utf8();
9766 int se=line.find(':'); // find name and text separator.
9769 warn_uncond("formula.repository is corrupted!\n");
9774 QCString formName = line.left(se);
9775 QCString formText = line.right(line.length()-se-1);
9776 Formula *f=new Formula(formText);
9777 Doxygen::formulaList->setAutoDelete(TRUE);
9778 Doxygen::formulaList->append(f);
9779 Doxygen::formulaDict->insert(formText,f);
9780 Doxygen::formulaNameDict->insert(formName,f);
9786 //----------------------------------------------------------------------------
9788 static void expandAliases()
9790 QDictIterator<QCString> adi(Doxygen::aliasDict);
9792 for (adi.toFirst();(s=adi.current());++adi)
9794 *s = expandAlias(adi.currentKey(),*s);
9798 //----------------------------------------------------------------------------
9800 static void escapeAliases()
9802 QDictIterator<QCString> adi(Doxygen::aliasDict);
9804 for (adi.toFirst();(s=adi.current());++adi)
9806 QCString value=*s,newValue;
9808 // for each \n in the alias command value
9809 while ((in=value.find("\\n",p))!=-1)
9811 newValue+=value.mid(p,in-p);
9812 // expand \n's except if \n is part of a built-in command.
9813 if (value.mid(in,5)!="\\note" &&
9814 value.mid(in,5)!="\\name" &&
9815 value.mid(in,10)!="\\namespace" &&
9816 value.mid(in,14)!="\\nosubgrouping"
9819 newValue+="\\_linebr ";
9827 newValue+=value.mid(p,value.length()-p);
9831 while ((in=value.find("^^",p))!=-1)
9833 newValue+=value.mid(p,in-p);
9837 newValue+=value.mid(p,value.length()-p);
9839 //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9843 //----------------------------------------------------------------------------
9847 // add aliases to a dictionary
9848 Doxygen::aliasDict.setAutoDelete(TRUE);
9849 QStrList &aliasList = Config_getList(ALIASES);
9850 const char *s=aliasList.first();
9853 if (Doxygen::aliasDict[s]==0)
9856 int i=alias.find('=');
9859 QCString name=alias.left(i).stripWhiteSpace();
9860 QCString value=alias.right(alias.length()-i-1);
9861 //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
9862 if (!name.isEmpty())
9864 QCString *dn=Doxygen::aliasDict[name];
9865 if (dn==0) // insert new alias
9867 Doxygen::aliasDict.insert(name,new QCString(value));
9869 else // overwrite previous alias
9882 //----------------------------------------------------------------------------
9884 static void dumpSymbol(FTextStream &t,Definition *d)
9887 if (d->definitionType()==Definition::TypeMember)
9889 MemberDef *md = (MemberDef *)d;
9890 anchor=":"+md->anchor();
9893 if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope)
9895 scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
9897 t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9898 << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9900 << d->name() << "','"
9901 << d->getDefFileName() << "','"
9906 static void dumpSymbolMap()
9908 QFile f("symbols.sql");
9909 if (f.open(IO_WriteOnly))
9912 QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9913 DefinitionIntf *intf;
9914 for (;(intf=di.current());++di)
9916 if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9918 DefinitionListIterator dli(*(DefinitionList*)intf);
9921 for (dli.toFirst();(d=dli.current());++dli)
9926 else // single symbol
9928 Definition *d = (Definition *)intf;
9929 if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9935 // print developer options of doxygen
9936 static void devUsage()
9938 msg("Developer parameters:\n");
9939 msg(" -m dump symbol map\n");
9940 msg(" -b output to wizard\n");
9941 msg(" -T activates output generation via Django like template\n");
9942 msg(" -d <level> enable a debug level, such as (multiple invocations of -d are possible):\n");
9943 Debug::printFlags();
9947 //----------------------------------------------------------------------------
9948 // print the usage of doxygen
9950 static void usage(const char *name)
9952 msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2015\n\n",versionString);
9953 msg("You can use doxygen in a number of ways:\n\n");
9954 msg("1) Use doxygen to generate a template configuration file:\n");
9955 msg(" %s [-s] -g [configName]\n\n",name);
9956 msg(" If - is used for configName doxygen will write to standard output.\n\n");
9957 msg("2) Use doxygen to update an old configuration file:\n");
9958 msg(" %s [-s] -u [configName]\n\n",name);
9959 msg("3) Use doxygen to generate documentation using an existing ");
9960 msg("configuration file:\n");
9961 msg(" %s [configName]\n\n",name);
9962 msg(" If - is used for configName doxygen will read from standard input.\n\n");
9963 msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9964 msg(" generated documentation:\n");
9965 msg(" %s -l [layoutFileName.xml]\n\n",name);
9966 msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9967 msg(" RTF: %s -w rtf styleSheetFile\n",name);
9968 msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9969 msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9970 msg("6) Use doxygen to generate a rtf extensions file\n");
9971 msg(" RTF: %s -e rtf extensionsFile\n\n",name);
9972 msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
9973 msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9974 msg("-v print version string\n");
9977 //----------------------------------------------------------------------------
9978 // read the argument of option `c' from the comment argument list and
9979 // update the option index `optind'.
9981 static const char *getArg(int argc,char **argv,int &optind)
9984 if (qstrlen(&argv[optind][2])>0)
9986 else if (optind+1<argc && argv[optind+1][0]!='-')
9991 //----------------------------------------------------------------------------
9996 const char *lang = portable_getenv("LC_ALL");
9997 if (lang) portable_setenv("LANG",lang);
9998 setlocale(LC_ALL,"");
9999 setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
10000 setlocale(LC_NUMERIC,"C");
10002 portable_correct_path();
10004 Doxygen::runningTime.start();
10005 initPreprocessor();
10007 Doxygen::parserManager = new ParserManager;
10008 Doxygen::parserManager->registerDefaultParser( new FileParser);
10009 Doxygen::parserManager->registerParser("c", new CLanguageScanner);
10010 Doxygen::parserManager->registerParser("python", new PythonLanguageScanner);
10011 Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
10012 Doxygen::parserManager->registerParser("fortranfree", new FortranLanguageScannerFree);
10013 Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed);
10014 Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner);
10015 Doxygen::parserManager->registerParser("xml", new XMLScanner);
10016 Doxygen::parserManager->registerParser("sql", new SQLScanner);
10017 Doxygen::parserManager->registerParser("tcl", new TclLanguageScanner);
10018 Doxygen::parserManager->registerParser("md", new MarkdownFileParser);
10020 // register any additional parsers here...
10022 initDefaultExtensionMapping();
10023 initClassMemberIndices();
10024 initNamespaceMemberIndices();
10025 initFileMemberIndices();
10027 Doxygen::symbolMap = new QDict<DefinitionIntf>(50177);
10028 #ifdef USE_LIBCLANG
10029 Doxygen::clangUsrMap = new QDict<Definition>(50177);
10031 Doxygen::inputNameList = new FileNameList;
10032 Doxygen::inputNameList->setAutoDelete(TRUE);
10033 Doxygen::memberNameSDict = new MemberNameSDict(10000);
10034 Doxygen::memberNameSDict->setAutoDelete(TRUE);
10035 Doxygen::functionNameSDict = new MemberNameSDict(10000);
10036 Doxygen::functionNameSDict->setAutoDelete(TRUE);
10037 Doxygen::groupSDict = new GroupSDict(17);
10038 Doxygen::groupSDict->setAutoDelete(TRUE);
10039 Doxygen::namespaceSDict = new NamespaceSDict(20);
10040 Doxygen::namespaceSDict->setAutoDelete(TRUE);
10041 Doxygen::classSDict = new ClassSDict(1009);
10042 Doxygen::classSDict->setAutoDelete(TRUE);
10043 Doxygen::hiddenClasses = new ClassSDict(257);
10044 Doxygen::hiddenClasses->setAutoDelete(TRUE);
10045 Doxygen::directories = new DirSDict(17);
10046 Doxygen::directories->setAutoDelete(TRUE);
10047 Doxygen::pageSDict = new PageSDict(1009); // all doc pages
10048 Doxygen::pageSDict->setAutoDelete(TRUE);
10049 Doxygen::exampleSDict = new PageSDict(1009); // all examples
10050 Doxygen::exampleSDict->setAutoDelete(TRUE);
10051 Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
10052 Doxygen::tagDestinationDict.setAutoDelete(TRUE);
10053 Doxygen::dirRelations.setAutoDelete(TRUE);
10054 Doxygen::citeDict = new CiteDict(257);
10055 Doxygen::genericsDict = new GenericsSDict;
10056 Doxygen::indexList = new IndexList;
10057 Doxygen::formulaList = new FormulaList;
10058 Doxygen::formulaDict = new FormulaDict(1009);
10059 Doxygen::formulaNameDict = new FormulaDict(1009);
10060 Doxygen::sectionDict = new SectionDict(257);
10061 Doxygen::sectionDict->setAutoDelete(TRUE);
10063 // initialisation of these globals depends on
10064 // configuration switches so we need to postpone these
10065 Doxygen::globalScope = 0;
10066 Doxygen::inputNameDict = 0;
10067 Doxygen::includeNameDict = 0;
10068 Doxygen::exampleNameDict = 0;
10069 Doxygen::imageNameDict = 0;
10070 Doxygen::dotFileNameDict = 0;
10071 Doxygen::mscFileNameDict = 0;
10072 Doxygen::diaFileNameDict = 0;
10074 /**************************************************************************
10075 * Initialize some global constants
10076 **************************************************************************/
10078 g_compoundKeywordDict.insert("template class",(void *)8);
10079 g_compoundKeywordDict.insert("template struct",(void *)8);
10080 g_compoundKeywordDict.insert("class",(void *)8);
10081 g_compoundKeywordDict.insert("struct",(void *)8);
10082 g_compoundKeywordDict.insert("union",(void *)8);
10083 g_compoundKeywordDict.insert("interface",(void *)8);
10084 g_compoundKeywordDict.insert("exception",(void *)8);
10087 void cleanUpDoxygen()
10089 delete Doxygen::sectionDict;
10090 delete Doxygen::formulaNameDict;
10091 delete Doxygen::formulaDict;
10092 delete Doxygen::formulaList;
10093 delete Doxygen::indexList;
10094 delete Doxygen::genericsDict;
10095 delete Doxygen::inputNameDict;
10096 delete Doxygen::includeNameDict;
10097 delete Doxygen::exampleNameDict;
10098 delete Doxygen::imageNameDict;
10099 delete Doxygen::dotFileNameDict;
10100 delete Doxygen::mscFileNameDict;
10101 delete Doxygen::diaFileNameDict;
10102 delete Doxygen::mainPage;
10103 delete Doxygen::pageSDict;
10104 delete Doxygen::exampleSDict;
10105 delete Doxygen::globalScope;
10106 delete Doxygen::xrefLists;
10107 delete Doxygen::parserManager;
10108 cleanUpPreprocessor();
10109 delete theTranslator;
10110 delete g_outputList;
10111 Mappers::freeMappers();
10114 if (Doxygen::symbolMap)
10116 // iterate through Doxygen::symbolMap and delete all
10117 // DefinitionList objects, since they have no owner
10118 QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
10119 DefinitionIntf *di;
10120 for (dli.toFirst();(di=dli.current());)
10122 if (di->definitionType()==DefinitionIntf::TypeSymbolList)
10124 DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
10125 delete (DefinitionList *)tmp;
10134 delete Doxygen::inputNameList;
10135 delete Doxygen::memberNameSDict;
10136 delete Doxygen::functionNameSDict;
10137 delete Doxygen::groupSDict;
10138 delete Doxygen::classSDict;
10139 delete Doxygen::hiddenClasses;
10140 delete Doxygen::namespaceSDict;
10141 delete Doxygen::directories;
10143 //delete Doxygen::symbolMap; <- we cannot do this unless all static lists
10144 // (such as Doxygen::namespaceSDict)
10145 // with objects based on Definition are made
10149 static int computeIdealCacheParam(uint v)
10151 //printf("computeIdealCacheParam(v=%u)\n",v);
10154 while (v!=0) v>>=1,r++;
10157 // convert to a valid cache size value
10158 return QMAX(0,QMIN(r-16,9));
10161 void readConfiguration(int argc, char **argv)
10163 /**************************************************************************
10164 * Handle arguments *
10165 **************************************************************************/
10168 const char *configName=0;
10169 const char *layoutName=0;
10170 const char *debugLabel;
10171 const char *formatName;
10172 bool genConfig=FALSE;
10173 bool shortList=FALSE;
10174 bool updateConfig=FALSE;
10175 bool genLayout=FALSE;
10177 while (optind<argc && argv[optind][0]=='-' &&
10178 (isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
10179 argv[optind][1]=='-')
10182 switch(argv[optind][1])
10186 configName=getArg(argc,argv,optind);
10187 if (optind+1<argc && qstrcmp(argv[optind+1],"-")==0)
10188 { configName="-"; optind++; }
10190 { configName="Doxyfile"; }
10194 layoutName=getArg(argc,argv,optind);
10196 { layoutName="DoxygenLayout.xml"; }
10199 debugLabel=getArg(argc,argv,optind);
10202 err("option \"-d\" is missing debug specifier.\n");
10207 retVal = Debug::setFlag(debugLabel);
10210 err("option \"-d\" has unknown debug specifier: \"%s\".\n",debugLabel);
10222 formatName=getArg(argc,argv,optind);
10225 err("option \"-e\" is missing format specifier rtf.\n");
10229 if (qstricmp(formatName,"rtf")==0)
10231 if (optind+1>=argc)
10233 err("option \"-e rtf\" is missing an extensions file name\n");
10238 if (openOutputFile(argv[optind+1],f))
10240 RTFGenerator::writeExtensionsFile(f);
10245 err("option \"-e\" has invalid format specifier.\n");
10250 formatName=getArg(argc,argv,optind);
10253 err("option \"-w\" is missing format specifier rtf, html or latex\n");
10257 if (qstricmp(formatName,"rtf")==0)
10259 if (optind+1>=argc)
10261 err("option \"-w rtf\" is missing a style sheet file name\n");
10266 if (openOutputFile(argv[optind+1],f))
10268 RTFGenerator::writeStyleSheetFile(f);
10273 else if (qstricmp(formatName,"html")==0)
10276 if (optind+4<argc || QFileInfo("Doxyfile").exists())
10277 // explicit config file mentioned or default found on disk
10279 QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10280 if (!Config::parse(df)) // parse the config file
10282 err("error opening or reading configuration file %s!\n",argv[optind+4]);
10287 if (optind+3>=argc)
10289 err("option \"-w html\" does not have enough arguments\n");
10293 Config::postProcess(TRUE);
10294 Config::checkAndCorrect();
10296 QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10297 if (!setTranslator(outputLanguage))
10299 warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10303 if (openOutputFile(argv[optind+1],f))
10305 HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
10308 if (openOutputFile(argv[optind+2],f))
10310 HtmlGenerator::writeFooterFile(f);
10313 if (openOutputFile(argv[optind+3],f))
10315 HtmlGenerator::writeStyleSheetFile(f);
10320 else if (qstricmp(formatName,"latex")==0)
10323 if (optind+4<argc || QFileInfo("Doxyfile").exists())
10325 QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10326 if (!Config::parse(df))
10328 err("error opening or reading configuration file %s!\n",argv[optind+4]);
10333 if (optind+3>=argc)
10335 err("option \"-w latex\" does not have enough arguments\n");
10339 Config::postProcess(TRUE);
10340 Config::checkAndCorrect();
10342 QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10343 if (!setTranslator(outputLanguage))
10345 warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10349 if (openOutputFile(argv[optind+1],f))
10351 LatexGenerator::writeHeaderFile(f);
10354 if (openOutputFile(argv[optind+2],f))
10356 LatexGenerator::writeFooterFile(f);
10359 if (openOutputFile(argv[optind+3],f))
10361 LatexGenerator::writeStyleSheetFile(f);
10368 err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",formatName);
10374 g_dumpSymbolMap = TRUE;
10377 msg("%s\n",versionString);
10382 if (qstrcmp(&argv[optind][2],"help")==0)
10387 else if (qstrcmp(&argv[optind][2],"version")==0)
10389 msg("%s\n",versionString);
10395 err("Unknown option \"-%s\"\n",&argv[optind][1]);
10401 setvbuf(stdout,NULL,_IONBF,0);
10402 Doxygen::outputToWizard=TRUE;
10405 msg("Warning: this option activates output generation via Django like template files. "
10406 "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
10407 "Only use if you are a doxygen developer\n");
10408 g_useOutputTemplate=TRUE;
10416 err("Unknown option \"-%c\"\n",argv[optind][1]);
10423 /**************************************************************************
10424 * Parse or generate the config file *
10425 **************************************************************************/
10429 if (genConfig && g_useOutputTemplate)
10431 generateTemplateFiles("templates");
10438 generateConfigFile(configName,shortList);
10444 writeDefaultLayoutFile(layoutName);
10449 QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
10452 if (configFileInfo1.exists())
10454 configName="Doxyfile";
10456 else if (configFileInfo2.exists())
10458 configName="doxyfile";
10462 err("Doxyfile not found and no input file specified!\n");
10469 QFileInfo fi(argv[optind]);
10470 if (fi.exists() || qstrcmp(argv[optind],"-")==0)
10472 configName=argv[optind];
10476 err("configuration file %s not found!\n",argv[optind]);
10483 if (!Config::parse(configName,updateConfig))
10485 err("could not open or read configuration file %s!\n",configName);
10492 generateConfigFile(configName,shortList,TRUE);
10497 /* Perlmod wants to know the path to the config file.*/
10498 QFileInfo configFileInfo(configName);
10499 setPerlModDoxyfile(configFileInfo.absFilePath().data());
10503 /** check and resolve config options */
10504 void checkConfiguration()
10507 Config::postProcess(FALSE);
10508 Config::checkAndCorrect();
10509 initWarningFormat();
10512 /** adjust globals that depend on configuration settings. */
10513 void adjustConfiguration()
10515 Doxygen::globalScope = new NamespaceDef("<globalScope>",1,1,"<globalScope>");
10516 Doxygen::inputNameDict = new FileNameDict(10007);
10517 Doxygen::includeNameDict = new FileNameDict(10007);
10518 Doxygen::exampleNameDict = new FileNameDict(1009);
10519 Doxygen::exampleNameDict->setAutoDelete(TRUE);
10520 Doxygen::imageNameDict = new FileNameDict(257);
10521 Doxygen::imageNameDict->setAutoDelete(TRUE);
10522 Doxygen::dotFileNameDict = new FileNameDict(257);
10523 Doxygen::mscFileNameDict = new FileNameDict(257);
10524 Doxygen::diaFileNameDict = new FileNameDict(257);
10526 QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10527 if (!setTranslator(outputLanguage))
10529 warn_uncond("Output language %s not supported! Using English instead.\n",
10530 outputLanguage.data());
10532 QStrList &includePath = Config_getList(INCLUDE_PATH);
10533 char *s=includePath.first();
10537 addSearchDir(fi.absFilePath().utf8());
10538 s=includePath.next();
10541 /* Set the global html file extension. */
10542 Doxygen::htmlFileExtension = Config_getString(HTML_FILE_EXTENSION);
10545 Doxygen::xrefLists->setAutoDelete(TRUE);
10547 Doxygen::parseSourcesNeeded = Config_getBool(CALL_GRAPH) ||
10548 Config_getBool(CALLER_GRAPH) ||
10549 Config_getBool(REFERENCES_RELATION) ||
10550 Config_getBool(REFERENCED_BY_RELATION);
10552 Doxygen::markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
10554 /**************************************************************************
10555 * Add custom extension mappings
10556 **************************************************************************/
10558 QStrList &extMaps = Config_getList(EXTENSION_MAPPING);
10559 char *mapping = extMaps.first();
10562 QCString mapStr = mapping;
10564 if ((i=mapStr.find('='))!=-1)
10566 QCString ext=mapStr.left(i).stripWhiteSpace().lower();
10567 QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
10568 if (!updateLanguageMapping(ext,language))
10570 err("Failed to map file extension '%s' to unsupported language '%s'.\n"
10571 "Check the EXTENSION_MAPPING setting in the config file.\n",
10572 ext.data(),language.data());
10576 msg("Adding custom extension mapping: .%s will be treated as language %s\n",
10577 ext.data(),language.data());
10580 mapping = extMaps.next();
10584 // add predefined macro name to a dictionary
10585 QStrList &expandAsDefinedList =Config_getList(EXPAND_AS_DEFINED);
10586 s=expandAsDefinedList.first();
10589 if (Doxygen::expandAsDefinedDict[s]==0)
10591 Doxygen::expandAsDefinedDict.insert(s,(void *)666);
10593 s=expandAsDefinedList.next();
10596 // read aliases and store them in a dictionary
10599 // store number of spaces in a tab into Doxygen::spaces
10600 int &tabSize = Config_getInt(TAB_SIZE);
10601 Doxygen::spaces.resize(tabSize+1);
10602 int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
10603 Doxygen::spaces.at(tabSize)='\0';
10607 static void stopDoxygen(int)
10610 msg("Cleaning up...\n");
10611 if (!Doxygen::entryDBFileName.isEmpty())
10613 thisDir.remove(Doxygen::entryDBFileName);
10615 if (!Doxygen::objDBFileName.isEmpty())
10617 thisDir.remove(Doxygen::objDBFileName);
10624 static void writeTagFile()
10626 QCString &generateTagFile = Config_getString(GENERATE_TAGFILE);
10627 if (generateTagFile.isEmpty()) return;
10629 QFile tag(generateTagFile);
10630 if (!tag.open(IO_WriteOnly))
10632 err("cannot open tag file %s for writing\n",
10633 generateTagFile.data()
10637 FTextStream tagFile(&tag);
10638 tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
10639 tagFile << "<tagfile>" << endl;
10642 FileNameListIterator fnli(*Doxygen::inputNameList);
10644 for (fnli.toFirst();(fn=fnli.current());++fnli)
10646 FileNameIterator fni(*fn);
10648 for (fni.toFirst();(fd=fni.current());++fni)
10650 if (fd->isLinkableInProject()) fd->writeTagFile(tagFile);
10654 ClassSDict::Iterator cli(*Doxygen::classSDict);
10656 for ( ; (cd=cli.current()) ; ++cli )
10658 if (cd->isLinkableInProject()) cd->writeTagFile(tagFile);
10660 // for each namespace
10661 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
10663 for ( ; (nd=nli.current()) ; ++nli )
10665 if (nd->isLinkableInProject()) nd->writeTagFile(tagFile);
10668 GroupSDict::Iterator gli(*Doxygen::groupSDict);
10670 for (gli.toFirst();(gd=gli.current());++gli)
10672 if (gd->isLinkableInProject()) gd->writeTagFile(tagFile);
10675 PageSDict::Iterator pdi(*Doxygen::pageSDict);
10677 for (pdi.toFirst();(pd=pdi.current());++pdi)
10679 if (pd->isLinkableInProject()) pd->writeTagFile(tagFile);
10681 if (Doxygen::mainPage) Doxygen::mainPage->writeTagFile(tagFile);
10684 if (Doxygen::mainPage && !Config_getString(GENERATE_TAGFILE).isEmpty())
10686 tagFile << " <compound kind=\"page\">" << endl
10688 << convertToXML(Doxygen::mainPage->name())
10689 << "</name>" << endl
10691 << convertToXML(Doxygen::mainPage->title())
10692 << "</title>" << endl
10694 << convertToXML(Doxygen::mainPage->getOutputFileBase())
10695 << "</filename>" << endl;
10697 mainPage->writeDocAnchorsToTagFile();
10698 tagFile << " </compound>" << endl;
10702 tagFile << "</tagfile>" << endl;
10705 static void exitDoxygen()
10707 if (!g_successfulRun) // premature exit
10710 msg("Exiting...\n");
10711 if (!Doxygen::entryDBFileName.isEmpty())
10713 thisDir.remove(Doxygen::entryDBFileName);
10715 if (!Doxygen::objDBFileName.isEmpty())
10717 thisDir.remove(Doxygen::objDBFileName);
10722 static QCString createOutputDirectory(const QCString &baseDirName,
10723 QCString &formatDirName,
10724 const char *defaultDirName)
10726 // Note the & on the next line, we modify the formatDirOption!
10727 if (formatDirName.isEmpty())
10729 formatDirName = baseDirName + defaultDirName;
10731 else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
10733 formatDirName.prepend(baseDirName+'/');
10735 QDir formatDir(formatDirName);
10736 if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
10738 err("Could not create output directory %s\n", formatDirName.data());
10742 return formatDirName;
10745 static QCString getQchFileName()
10747 QCString const & qchFile = Config_getString(QCH_FILE);
10748 if (!qchFile.isEmpty())
10753 QCString const & projectName = Config_getString(PROJECT_NAME);
10754 QCString const & versionText = Config_getString(PROJECT_NUMBER);
10756 return QCString("../qch/")
10757 + (projectName.isEmpty() ? QCString("index") : projectName)
10758 + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
10759 + QCString(".qch");
10762 void searchInputFiles()
10764 QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
10765 bool alwaysRecursive = Config_getBool(RECURSIVE);
10766 StringDict excludeNameDict(1009);
10767 excludeNameDict.setAutoDelete(TRUE);
10769 // gather names of all files in the include path
10770 g_s.begin("Searching for include files...\n");
10771 QStrList &includePathList = Config_getList(INCLUDE_PATH);
10772 char *s=includePathList.first();
10775 QStrList &pl = Config_getList(INCLUDE_FILE_PATTERNS);
10778 pl = Config_getList(FILE_PATTERNS);
10780 readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
10783 s=includePathList.next();
10787 g_s.begin("Searching for example files...\n");
10788 QStrList &examplePathList = Config_getList(EXAMPLE_PATH);
10789 s=examplePathList.first();
10792 readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
10793 &Config_getList(EXAMPLE_PATTERNS),
10795 (alwaysRecursive || Config_getBool(EXAMPLE_RECURSIVE)));
10796 s=examplePathList.next();
10800 g_s.begin("Searching for images...\n");
10801 QStrList &imagePathList=Config_getList(IMAGE_PATH);
10802 s=imagePathList.first();
10805 readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
10808 s=imagePathList.next();
10812 g_s.begin("Searching for dot files...\n");
10813 QStrList &dotFileList=Config_getList(DOTFILE_DIRS);
10814 s=dotFileList.first();
10817 readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
10820 s=dotFileList.next();
10824 g_s.begin("Searching for msc files...\n");
10825 QStrList &mscFileList=Config_getList(MSCFILE_DIRS);
10826 s=mscFileList.first();
10829 readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
10832 s=mscFileList.next();
10836 g_s.begin("Searching for dia files...\n");
10837 QStrList &diaFileList=Config_getList(DIAFILE_DIRS);
10838 s=diaFileList.first();
10841 readFileOrDirectory(s,0,Doxygen::diaFileNameDict,0,0,
10844 s=diaFileList.next();
10848 g_s.begin("Searching for files to exclude\n");
10849 QStrList &excludeList = Config_getList(EXCLUDE);
10850 s=excludeList.first();
10853 readFileOrDirectory(s,0,0,0,&Config_getList(FILE_PATTERNS),
10854 0,0,&excludeNameDict,
10857 s=excludeList.next();
10861 /**************************************************************************
10862 * Determine Input Files *
10863 **************************************************************************/
10865 g_s.begin("Searching INPUT for files to process...\n");
10866 QDict<void> *killDict = new QDict<void>(10007);
10867 QStrList &inputList=Config_getList(INPUT);
10868 g_inputFiles.setAutoDelete(TRUE);
10869 s=inputList.first();
10873 uint l = path.length();
10876 // strip trailing slashes
10877 if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
10879 readFileOrDirectory(
10881 Doxygen::inputNameList,
10882 Doxygen::inputNameDict,
10884 &Config_getList(FILE_PATTERNS),
10890 &Doxygen::inputPaths);
10892 s=inputList.next();
10901 atexit(exitDoxygen);
10904 /**************************************************************************
10905 * Make sure the output directory exists
10906 **************************************************************************/
10907 QCString &outputDirectory = Config_getString(OUTPUT_DIRECTORY);
10908 if (outputDirectory.isEmpty())
10910 outputDirectory=QDir::currentDirPath().utf8();
10914 QDir dir(outputDirectory);
10917 dir.setPath(QDir::currentDirPath());
10918 if (!dir.mkdir(outputDirectory))
10920 err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
10921 "exist and cannot be created\n",outputDirectory.data());
10927 msg("Notice: Output directory `%s' does not exist. "
10928 "I have created it for you.\n", outputDirectory.data());
10930 dir.cd(outputDirectory);
10932 outputDirectory=dir.absPath().utf8();
10935 /**************************************************************************
10936 * Initialize global lists and dictionaries
10937 **************************************************************************/
10939 Doxygen::symbolStorage = new Store;
10941 // also scale lookup cache with SYMBOL_CACHE_SIZE
10942 int cacheSize = Config_getInt(LOOKUP_CACHE_SIZE);
10943 if (cacheSize<0) cacheSize=0;
10944 if (cacheSize>9) cacheSize=9;
10945 uint lookupSize = 65536 << cacheSize;
10946 Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
10947 Doxygen::lookupCache->setAutoDelete(TRUE);
10950 signal(SIGINT, stopDoxygen);
10953 uint pid = portable_pid();
10954 Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10955 Doxygen::objDBFileName.prepend(outputDirectory+"/");
10956 Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10957 Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10959 if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10961 err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10967 /**************************************************************************
10968 * Check/create output directorties *
10969 **************************************************************************/
10971 QCString htmlOutput;
10972 bool &generateHtml = Config_getBool(GENERATE_HTML);
10973 if (generateHtml || g_useOutputTemplate /* TODO: temp hack */)
10974 htmlOutput = createOutputDirectory(outputDirectory,Config_getString(HTML_OUTPUT),"/html");
10976 QCString docbookOutput;
10977 bool &generateDocbook = Config_getBool(GENERATE_DOCBOOK);
10978 if (generateDocbook)
10979 docbookOutput = createOutputDirectory(outputDirectory,Config_getString(DOCBOOK_OUTPUT),"/docbook");
10981 QCString xmlOutput;
10982 bool &generateXml = Config_getBool(GENERATE_XML);
10984 xmlOutput = createOutputDirectory(outputDirectory,Config_getString(XML_OUTPUT),"/xml");
10986 QCString latexOutput;
10987 bool &generateLatex = Config_getBool(GENERATE_LATEX);
10989 latexOutput = createOutputDirectory(outputDirectory,Config_getString(LATEX_OUTPUT),"/latex");
10991 QCString rtfOutput;
10992 bool &generateRtf = Config_getBool(GENERATE_RTF);
10994 rtfOutput = createOutputDirectory(outputDirectory,Config_getString(RTF_OUTPUT),"/rtf");
10996 QCString manOutput;
10997 bool &generateMan = Config_getBool(GENERATE_MAN);
10999 manOutput = createOutputDirectory(outputDirectory,Config_getString(MAN_OUTPUT),"/man");
11001 //QCString sqlOutput;
11002 //bool &generateSql = Config_getBool(GENERATE_SQLITE3);
11004 // sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3");
11006 if (Config_getBool(HAVE_DOT))
11008 QCString curFontPath = Config_getString(DOT_FONTPATH);
11009 if (curFontPath.isEmpty())
11011 portable_getenv("DOTFONTPATH");
11012 QCString newFontPath = ".";
11013 if (!curFontPath.isEmpty())
11015 newFontPath+=portable_pathListSeparator();
11016 newFontPath+=curFontPath;
11018 portable_setenv("DOTFONTPATH",newFontPath);
11022 portable_setenv("DOTFONTPATH",curFontPath);
11028 /**************************************************************************
11029 * Handle layout file *
11030 **************************************************************************/
11032 LayoutDocManager::instance().init();
11033 QCString &layoutFileName = Config_getString(LAYOUT_FILE);
11034 bool defaultLayoutUsed = FALSE;
11035 if (layoutFileName.isEmpty())
11037 layoutFileName = "DoxygenLayout.xml";
11038 defaultLayoutUsed = TRUE;
11041 QFile layoutFile(layoutFileName);
11042 if (layoutFile.open(IO_ReadOnly))
11044 msg("Parsing layout file %s...\n",layoutFileName.data());
11045 QTextStream t(&layoutFile);
11046 t.setEncoding(QTextStream::Latin1);
11047 LayoutDocManager::instance().parse(t,layoutFileName);
11049 else if (!defaultLayoutUsed)
11051 warn_uncond("failed to open layout file '%s' for reading!\n",layoutFileName.data());
11054 /**************************************************************************
11055 * Read and preprocess input *
11056 **************************************************************************/
11058 // prevent search in the output directories
11059 QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
11060 if (generateHtml) exclPatterns.append(htmlOutput);
11061 if (generateDocbook) exclPatterns.append(docbookOutput);
11062 if (generateXml) exclPatterns.append(xmlOutput);
11063 if (generateLatex) exclPatterns.append(latexOutput);
11064 if (generateRtf) exclPatterns.append(rtfOutput);
11065 if (generateMan) exclPatterns.append(manOutput);
11067 searchInputFiles();
11069 // Notice: the order of the function calls below is very important!
11071 if (Config_getBool(GENERATE_HTML))
11073 readFormulaRepository();
11076 /**************************************************************************
11077 * Handle Tag Files *
11078 **************************************************************************/
11080 g_storage = new FileStorage;
11081 g_storage->setName(Doxygen::entryDBFileName);
11082 if (!g_storage->open(IO_WriteOnly))
11084 err("Failed to create temporary storage file %s\n",
11085 Doxygen::entryDBFileName.data());
11088 Entry *root=new Entry;
11089 EntryNav *rootNav = new EntryNav(0,root);
11090 rootNav->setEntry(root);
11091 msg("Reading and parsing tag files\n");
11093 QStrList &tagFileList = Config_getList(TAGFILES);
11094 char *s=tagFileList.first();
11097 readTagFile(root,s);
11098 root->createNavigationIndex(rootNav,g_storage,0);
11099 s=tagFileList.next();
11102 /**************************************************************************
11103 * Parse source files *
11104 **************************************************************************/
11106 if (Config_getBool(BUILTIN_STL_SUPPORT))
11108 addSTLClasses(rootNav);
11111 g_s.begin("Parsing files\n");
11112 parseFiles(root,rootNav);
11113 g_storage->close();
11116 // we are done with input scanning now, so free up the buffers used by flex
11117 // (can be around 4MB)
11120 pyscanFreeScanner();
11122 if (!g_storage->open(IO_ReadOnly))
11124 err("Failed to open temporary storage file %s for reading",
11125 Doxygen::entryDBFileName.data());
11129 /**************************************************************************
11130 * Gather information *
11131 **************************************************************************/
11133 g_s.begin("Building group list...\n");
11134 buildGroupList(rootNav);
11135 organizeSubGroups(rootNav);
11138 g_s.begin("Building directory list...\n");
11139 buildDirectories();
11140 findDirDocumentation(rootNav);
11143 g_s.begin("Building namespace list...\n");
11144 buildNamespaceList(rootNav);
11145 findUsingDirectives(rootNav);
11148 g_s.begin("Building file list...\n");
11149 buildFileList(rootNav);
11151 //generateFileTree();
11153 g_s.begin("Building class list...\n");
11154 buildClassList(rootNav);
11157 g_s.begin("Associating documentation with classes...\n");
11158 buildClassDocList(rootNav);
11160 // build list of using declarations here (global list)
11161 buildListOfUsingDecls(rootNav);
11164 g_s.begin("Computing nesting relations for classes...\n");
11165 resolveClassNestingRelations();
11167 // 1.8.2-20121111: no longer add nested classes to the group as well
11168 //distributeClassGroupRelations();
11170 // calling buildClassList may result in cached relations that
11171 // become invalid after resolveClassNestingRelations(), that's why
11172 // we need to clear the cache here
11173 Doxygen::lookupCache->clear();
11174 // we don't need the list of using declaration anymore
11175 g_usingDeclarations.clear();
11177 g_s.begin("Building example list...\n");
11178 buildExampleList(rootNav);
11181 g_s.begin("Searching for enumerations...\n");
11182 findEnums(rootNav);
11185 // Since buildVarList calls isVarWithConstructor
11186 // and this calls getResolvedClass we need to process
11187 // typedefs first so the relations between classes via typedefs
11188 // are properly resolved. See bug 536385 for an example.
11189 g_s.begin("Searching for documented typedefs...\n");
11190 buildTypedefList(rootNav);
11193 g_s.begin("Searching for members imported via using declarations...\n");
11194 // this should be after buildTypedefList in order to properly import
11196 findUsingDeclarations(rootNav);
11199 g_s.begin("Searching for included using directives...\n");
11200 findIncludedUsingDirectives();
11203 g_s.begin("Searching for documented variables...\n");
11204 buildVarList(rootNav);
11207 g_s.begin("Building interface member list...\n");
11208 buildInterfaceAndServiceList(rootNav); // UNO IDL
11210 g_s.begin("Building member list...\n"); // using class info only !
11211 buildFunctionList(rootNav);
11214 g_s.begin("Searching for friends...\n");
11218 g_s.begin("Searching for documented defines...\n");
11219 findDefineDocumentation(rootNav);
11222 g_s.begin("Computing class inheritance relations...\n");
11223 findClassEntries(rootNav);
11224 findInheritedTemplateInstances();
11227 g_s.begin("Computing class usage relations...\n");
11228 findUsedTemplateInstances();
11231 if (Config_getBool(INLINE_SIMPLE_STRUCTS))
11233 g_s.begin("Searching for tag less structs...\n");
11234 findTagLessClasses();
11238 g_s.begin("Flushing cached template relations that have become invalid...\n");
11239 flushCachedTemplateRelations();
11242 g_s.begin("Computing class relations...\n");
11243 computeTemplateClassRelations();
11244 flushUnresolvedRelations();
11245 if (Config_getBool(OPTIMIZE_OUTPUT_VHDL))
11247 VhdlDocGen::computeVhdlComponentRelations();
11249 computeClassRelations();
11250 g_classEntries.clear();
11253 g_s.begin("Add enum values to enums...\n");
11254 addEnumValuesToEnums(rootNav);
11255 findEnumDocumentation(rootNav);
11258 g_s.begin("Searching for member function documentation...\n");
11259 findObjCMethodDefinitions(rootNav);
11260 findMemberDocumentation(rootNav); // may introduce new members !
11261 findUsingDeclImports(rootNav); // may introduce new members !
11263 transferRelatedFunctionDocumentation();
11264 transferFunctionDocumentation();
11267 // moved to after finding and copying documentation,
11268 // as this introduces new members see bug 722654
11269 g_s.begin("Creating members for template instances...\n");
11270 createTemplateInstanceMembers();
11273 g_s.begin("Building page list...\n");
11274 buildPageList(rootNav);
11277 g_s.begin("Search for main page...\n");
11278 findMainPage(rootNav);
11279 findMainPageTagFiles(rootNav);
11282 g_s.begin("Computing page relations...\n");
11283 computePageRelations(rootNav);
11284 checkPageRelations();
11287 g_s.begin("Determining the scope of groups...\n");
11288 findGroupScope(rootNav);
11291 g_s.begin("Sorting lists...\n");
11292 Doxygen::memberNameSDict->sort();
11293 Doxygen::functionNameSDict->sort();
11294 Doxygen::hiddenClasses->sort();
11295 Doxygen::classSDict->sort();
11298 msg("Freeing entry tree\n");
11300 g_storage->close();
11305 thisDir.remove(Doxygen::entryDBFileName);
11307 g_s.begin("Determining which enums are documented\n");
11308 findDocumentedEnumValues();
11311 g_s.begin("Computing member relations...\n");
11313 computeMemberRelations();
11316 g_s.begin("Building full member lists recursively...\n");
11317 buildCompleteMemberLists();
11320 g_s.begin("Adding members to member groups.\n");
11321 addMembersToMemberGroup();
11324 if (Config_getBool(DISTRIBUTE_GROUP_DOC))
11326 g_s.begin("Distributing member group documentation.\n");
11327 distributeMemberGroupDocumentation();
11331 g_s.begin("Computing member references...\n");
11332 computeMemberReferences();
11335 if (Config_getBool(INHERIT_DOCS))
11337 g_s.begin("Inheriting documentation...\n");
11338 inheritDocumentation();
11342 // compute the shortest possible names of all files
11343 // without losing the uniqueness of the file names.
11344 g_s.begin("Generating disk names...\n");
11345 Doxygen::inputNameList->generateDiskNames();
11348 g_s.begin("Adding source references...\n");
11349 addSourceReferences();
11352 g_s.begin("Adding xrefitems...\n");
11353 addListReferences();
11354 generateXRefPages();
11357 g_s.begin("Sorting member lists...\n");
11361 if (Config_getBool(DIRECTORY_GRAPH))
11363 g_s.begin("Computing dependencies between directories...\n");
11364 computeDirDependencies();
11368 //g_s.begin("Resolving citations...\n");
11369 //Doxygen::citeDict->resolve();
11371 g_s.begin("Generating citations page...\n");
11372 Doxygen::citeDict->generatePage();
11375 g_s.begin("Counting data structures...\n");
11376 countDataStructures();
11379 g_s.begin("Resolving user defined references...\n");
11380 resolveUserReferences();
11383 g_s.begin("Finding anchors and sections in the documentation...\n");
11384 findSectionsInDocumentation();
11387 g_s.begin("Transferring function references...\n");
11388 transferFunctionReferences();
11391 g_s.begin("Combining using relations...\n");
11392 combineUsingRelations();
11395 g_s.begin("Adding members to index pages...\n");
11396 addMembersToIndex();
11400 void generateOutput()
11402 /**************************************************************************
11403 * Initialize output generators *
11404 **************************************************************************/
11406 /// add extra languages for which we can only produce syntax highlighted code
11407 addCodeOnlyMappings();
11409 //// dump all symbols
11410 if (g_dumpSymbolMap)
11416 initSearchIndexer();
11418 bool generateHtml = Config_getBool(GENERATE_HTML);
11419 bool generateLatex = Config_getBool(GENERATE_LATEX);
11420 bool generateMan = Config_getBool(GENERATE_MAN);
11421 bool generateRtf = Config_getBool(GENERATE_RTF);
11424 g_outputList = new OutputList(TRUE);
11427 g_outputList->add(new HtmlGenerator);
11428 HtmlGenerator::init();
11430 // add HTML indexers that are enabled
11431 bool generateHtmlHelp = Config_getBool(GENERATE_HTMLHELP);
11432 bool generateEclipseHelp = Config_getBool(GENERATE_ECLIPSEHELP);
11433 bool generateQhp = Config_getBool(GENERATE_QHP);
11434 bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
11435 bool generateDocSet = Config_getBool(GENERATE_DOCSET);
11436 if (generateEclipseHelp) Doxygen::indexList->addIndex(new EclipseHelp);
11437 if (generateHtmlHelp) Doxygen::indexList->addIndex(new HtmlHelp);
11438 if (generateQhp) Doxygen::indexList->addIndex(new Qhp);
11439 if (generateTreeView) Doxygen::indexList->addIndex(new FTVHelp(TRUE));
11440 if (generateDocSet) Doxygen::indexList->addIndex(new DocSets);
11441 Doxygen::indexList->initialize();
11442 HtmlGenerator::writeTabData();
11446 g_outputList->add(new LatexGenerator);
11447 LatexGenerator::init();
11451 g_outputList->add(new ManGenerator);
11452 ManGenerator::init();
11456 g_outputList->add(new RTFGenerator);
11457 RTFGenerator::init();
11459 if (Config_getBool(USE_HTAGS))
11461 Htags::useHtags = TRUE;
11462 QCString htmldir = Config_getString(HTML_OUTPUT);
11463 if (!Htags::execute(htmldir))
11464 err("USE_HTAGS is YES but htags(1) failed. \n");
11465 if (!Htags::loadFilemap(htmldir))
11466 err("htags(1) ended normally but failed to load the filemap. \n");
11469 /**************************************************************************
11470 * Generate documentation *
11471 **************************************************************************/
11473 if (generateHtml) writeDoxFont(Config_getString(HTML_OUTPUT));
11474 if (generateLatex) writeDoxFont(Config_getString(LATEX_OUTPUT));
11475 if (generateRtf) writeDoxFont(Config_getString(RTF_OUTPUT));
11477 g_s.begin("Generating style sheet...\n");
11478 //printf("writing style info\n");
11479 g_outputList->writeStyleInfo(0); // write first part
11482 static bool searchEngine = Config_getBool(SEARCHENGINE);
11483 static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
11485 g_s.begin("Generating search indices...\n");
11486 if (searchEngine && !serverBasedSearch && (generateHtml || g_useOutputTemplate))
11488 createJavascriptSearchIndex();
11491 // generate search indices (need to do this before writing other HTML
11492 // pages as these contain a drop down menu with options depending on
11493 // what categories we find in this function.
11494 if (generateHtml && searchEngine)
11496 QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search";
11497 QDir searchDir(searchDirName);
11498 if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
11500 err("Could not create search results directory '%s' $PWD='%s'\n",
11501 searchDirName.data(),QDir::currentDirPath().data());
11504 HtmlGenerator::writeSearchData(searchDirName);
11505 if (!serverBasedSearch) // client side search index
11507 writeJavascriptSearchIndex();
11512 g_s.begin("Generating example documentation...\n");
11513 generateExampleDocs();
11516 if (!Htags::useHtags)
11518 g_s.begin("Generating file sources...\n");
11519 generateFileSources();
11523 g_s.begin("Generating file documentation...\n");
11524 generateFileDocs();
11527 g_s.begin("Generating page documentation...\n");
11528 generatePageDocs();
11531 g_s.begin("Generating group documentation...\n");
11532 generateGroupDocs();
11535 g_s.begin("Generating class documentation...\n");
11536 generateClassDocs();
11539 g_s.begin("Generating namespace index...\n");
11540 generateNamespaceDocs();
11543 if (Config_getBool(GENERATE_LEGEND))
11545 g_s.begin("Generating graph info page...\n");
11546 writeGraphInfo(*g_outputList);
11550 g_s.begin("Generating directory documentation...\n");
11551 generateDirDocs(*g_outputList);
11554 if (Doxygen::formulaList->count()>0 && generateHtml
11555 && !Config_getBool(USE_MATHJAX))
11557 g_s.begin("Generating bitmaps for formulas in HTML...\n");
11558 Doxygen::formulaList->generateBitmaps(Config_getString(HTML_OUTPUT));
11562 if (Config_getBool(SORT_GROUP_NAMES))
11564 Doxygen::groupSDict->sort();
11565 GroupSDict::Iterator gli(*Doxygen::groupSDict);
11567 for (gli.toFirst();(gd=gli.current());++gli)
11569 gd->sortSubGroups();
11573 if (g_outputList->count()>0)
11575 writeIndexHierarchy(*g_outputList);
11578 g_s.begin("finalizing index lists...\n");
11579 Doxygen::indexList->finalize();
11582 g_s.begin("writing tag file...\n");
11586 if (Config_getBool(DOT_CLEANUP))
11589 removeDoxFont(Config_getString(HTML_OUTPUT));
11591 removeDoxFont(Config_getString(RTF_OUTPUT));
11593 removeDoxFont(Config_getString(LATEX_OUTPUT));
11596 if (Config_getBool(GENERATE_XML))
11598 g_s.begin("Generating XML output...\n");
11599 Doxygen::generatingXmlOutput=TRUE;
11601 Doxygen::generatingXmlOutput=FALSE;
11606 g_s.begin("Generating SQLITE3 output...\n");
11611 if (Config_getBool(GENERATE_DOCBOOK))
11613 g_s.begin("Generating Docbook output...\n");
11618 if (Config_getBool(GENERATE_AUTOGEN_DEF))
11620 g_s.begin("Generating AutoGen DEF output...\n");
11624 if (Config_getBool(GENERATE_PERLMOD))
11626 g_s.begin("Generating Perl module output...\n");
11630 if (generateHtml && searchEngine && serverBasedSearch)
11632 g_s.begin("Generating search index\n");
11633 if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
11635 HtmlGenerator::writeSearchPage();
11636 Doxygen::searchIndex->write(Config_getString(HTML_OUTPUT)+"/search/search.idx");
11638 else // write data for external search index
11640 HtmlGenerator::writeExternalSearchPage();
11641 QCString searchDataFile = Config_getString(SEARCHDATA_FILE);
11642 if (searchDataFile.isEmpty())
11644 searchDataFile="searchdata.xml";
11646 if (!portable_isAbsolutePath(searchDataFile))
11648 searchDataFile.prepend(Config_getString(OUTPUT_DIRECTORY)+"/");
11650 Doxygen::searchIndex->write(searchDataFile);
11655 if (g_useOutputTemplate) generateOutputViaTemplate();
11659 g_s.begin("Combining RTF output...\n");
11660 if (!RTFGenerator::preProcessFileInplace(Config_getString(RTF_OUTPUT),"refman.rtf"))
11662 err("An error occurred during post-processing the RTF files!\n");
11667 if (Config_getBool(HAVE_DOT))
11669 g_s.begin("Running dot...\n");
11670 DotManager::instance()->run();
11674 // copy static stuff
11677 FTVHelp::generateTreeViewImages();
11679 copyLogo(Config_getString(HTML_OUTPUT));
11680 copyExtraFiles(Config_getList(HTML_EXTRA_FILES),"HTML_EXTRA_FILES",Config_getString(HTML_OUTPUT));
11684 copyLatexStyleSheet();
11685 copyLogo(Config_getString(LATEX_OUTPUT));
11686 copyExtraFiles(Config_getList(LATEX_EXTRA_FILES),"LATEX_EXTRA_FILES",Config_getString(LATEX_OUTPUT));
11690 copyLogo(Config_getString(RTF_OUTPUT));
11693 if (generateHtml &&
11694 Config_getBool(GENERATE_HTMLHELP) &&
11695 !Config_getString(HHC_LOCATION).isEmpty())
11697 g_s.begin("Running html help compiler...\n");
11698 QString oldDir = QDir::currentDirPath();
11699 QDir::setCurrent(Config_getString(HTML_OUTPUT));
11700 portable_sysTimerStart();
11701 if (portable_system(Config_getString(HHC_LOCATION), "index.hhp", Debug::isFlagSet(Debug::ExtCmd))!=1)
11703 err("failed to run html help compiler on index.hhp\n");
11705 portable_sysTimerStop();
11706 QDir::setCurrent(oldDir);
11709 if ( generateHtml &&
11710 Config_getBool(GENERATE_QHP) &&
11711 !Config_getString(QHG_LOCATION).isEmpty())
11713 g_s.begin("Running qhelpgenerator...\n");
11714 QCString const qhpFileName = Qhp::getQhpFileName();
11715 QCString const qchFileName = getQchFileName();
11717 QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
11718 QString const oldDir = QDir::currentDirPath();
11719 QDir::setCurrent(Config_getString(HTML_OUTPUT));
11720 portable_sysTimerStart();
11721 if (portable_system(Config_getString(QHG_LOCATION), args.data(), FALSE))
11723 err("failed to run qhelpgenerator on index.qhp\n");
11725 portable_sysTimerStop();
11726 QDir::setCurrent(oldDir);
11731 msg("lookup cache used %d/%d hits=%d misses=%d\n",
11732 Doxygen::lookupCache->count(),
11733 Doxygen::lookupCache->size(),
11734 Doxygen::lookupCache->hits(),
11735 Doxygen::lookupCache->misses());
11736 cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
11737 if (cacheParam>Config_getInt(LOOKUP_CACHE_SIZE))
11739 msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
11742 if (Debug::isFlagSet(Debug::Time))
11744 msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
11745 ((double)Doxygen::runningTime.elapsed())/1000.0,
11746 portable_getSysElapsedTime()
11752 msg("finished...\n");
11756 /**************************************************************************
11757 * Start cleaning up *
11758 **************************************************************************/
11762 finializeSearchIndexer();
11763 Doxygen::symbolStorage->close();
11765 thisDir.remove(Doxygen::objDBFileName);
11767 QTextCodec::deleteAllCodecs();
11768 delete Doxygen::symbolMap;
11769 delete Doxygen::clangUsrMap;
11770 delete Doxygen::symbolStorage;
11771 g_successfulRun=TRUE;