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.
16 #if !defined(_WIN32) || defined(__CYGWIN__)
17 #define _DEFAULT_SOURCE 1
22 #include <qfileinfo.h>
31 #include <qtextcodec.h>
34 #include <qtextstream.h>
46 #include "tagreader.h"
49 #include "docparser.h"
51 #include "outputlist.h"
63 #include "sqlite3gen.h"
65 #include "docbookgen.h"
67 #include "perlmodgen.h"
71 #include "commentcnv.h"
72 #include "cmdmapper.h"
73 #include "searchindex.h"
74 #include "parserintf.h"
76 #include "pyscanner.h"
77 #include "fortranscanner.h"
78 #include "xmlscanner.h"
79 #include "sqlscanner.h"
80 #include "tclscanner.h"
86 #include "vhdljjparser.h"
87 #include "vhdldocgen.h"
88 #include "eclipsehelp.h"
90 #include "filestorage.h"
92 #include "arguments.h"
93 #include "memberlist.h"
96 #include "classlist.h"
97 #include "namespacedef.h"
99 #include "membername.h"
100 #include "membergroup.h"
103 #include "settings.h"
105 #include "fileparser.h"
108 // provided by the generated file resources.cpp
109 extern void initResources();
111 #define RECURSE_ENTRYTREE(func,var) \
112 do { if (var->children()) { \
113 EntryNavListIterator eli(*var->children()); \
114 for (;eli.current();++eli) func(eli.current()); \
118 #if !defined(_WIN32) || defined(__CYGWIN__)
123 // globally accessible variables
124 ClassSDict *Doxygen::classSDict = 0;
125 ClassSDict *Doxygen::hiddenClasses = 0;
126 NamespaceSDict *Doxygen::namespaceSDict = 0;
127 MemberNameSDict *Doxygen::memberNameSDict = 0;
128 MemberNameSDict *Doxygen::functionNameSDict = 0;
129 FileNameList *Doxygen::inputNameList = 0; // all input files
130 FileNameDict *Doxygen::inputNameDict = 0;
131 GroupSDict *Doxygen::groupSDict = 0;
132 FormulaList *Doxygen::formulaList = 0; // all formulas
133 FormulaDict *Doxygen::formulaDict = 0; // all formulas
134 FormulaDict *Doxygen::formulaNameDict = 0; // the label name of all formulas
135 PageSDict *Doxygen::pageSDict = 0;
136 PageSDict *Doxygen::exampleSDict = 0;
137 SectionDict *Doxygen::sectionDict = 0; // all page sections
138 CiteDict *Doxygen::citeDict=0; // database of bibliographic references
139 StringDict Doxygen::aliasDict(257); // aliases
140 QDict<void> Doxygen::inputPaths(1009);
141 FileNameDict *Doxygen::includeNameDict = 0; // include names
142 FileNameDict *Doxygen::exampleNameDict = 0; // examples
143 FileNameDict *Doxygen::imageNameDict = 0; // images
144 FileNameDict *Doxygen::dotFileNameDict = 0; // dot files
145 FileNameDict *Doxygen::mscFileNameDict = 0; // msc files
146 FileNameDict *Doxygen::diaFileNameDict = 0; // dia files
147 StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases
148 StringDict Doxygen::tagDestinationDict(257); // all tag locations
149 QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
150 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
151 PageDef *Doxygen::mainPage = 0;
152 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
153 NamespaceDef *Doxygen::globalScope = 0;
154 QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
155 bool Doxygen::parseSourcesNeeded = FALSE;
156 QTime Doxygen::runningTime;
157 SearchIndexIntf *Doxygen::searchIndex=0;
158 QDict<DefinitionIntf> *Doxygen::symbolMap = 0;
159 QDict<Definition> *Doxygen::clangUsrMap = 0;
160 bool Doxygen::outputToWizard=FALSE;
161 QDict<int> * Doxygen::htmlDirMap = 0;
162 QCache<LookupInfo> *Doxygen::lookupCache;
163 DirSDict *Doxygen::directories;
164 SDict<DirRelation> Doxygen::dirRelations(257);
165 ParserManager *Doxygen::parserManager = 0;
166 QCString Doxygen::htmlFileExtension;
167 bool Doxygen::suppressDocWarnings = FALSE;
168 Store *Doxygen::symbolStorage;
169 QCString Doxygen::objDBFileName;
170 QCString Doxygen::entryDBFileName;
171 QCString Doxygen::filterDBFileName;
172 bool Doxygen::gatherDefines = TRUE;
173 IndexList *Doxygen::indexList;
174 int Doxygen::subpageNestingLevel = 0;
175 bool Doxygen::userComments = FALSE;
176 QCString Doxygen::spaces;
177 bool Doxygen::generatingXmlOutput = FALSE;
178 bool Doxygen::markdownSupport = TRUE;
179 GenericsSDict *Doxygen::genericsDict;
181 // locally accessible globals
182 static QDict<EntryNav> g_classEntries(1009);
183 static StringList g_inputFiles;
184 static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds
185 static OutputList *g_outputList = 0; // list of output generating objects
186 static QDict<FileDef> g_usingDeclarations(1009); // used classes
187 static FileStorage *g_storage = 0;
188 static bool g_successfulRun = FALSE;
189 static bool g_dumpSymbolMap = FALSE;
190 static bool g_useOutputTemplate = FALSE;
194 g_inputFiles.clear();
195 //g_excludeNameDict.clear();
196 //delete g_outputList; g_outputList=0;
198 Doxygen::classSDict->clear();
199 Doxygen::namespaceSDict->clear();
200 Doxygen::pageSDict->clear();
201 Doxygen::exampleSDict->clear();
202 Doxygen::inputNameList->clear();
203 Doxygen::formulaList->clear();
204 Doxygen::sectionDict->clear();
205 Doxygen::inputNameDict->clear();
206 Doxygen::includeNameDict->clear();
207 Doxygen::exampleNameDict->clear();
208 Doxygen::imageNameDict->clear();
209 Doxygen::dotFileNameDict->clear();
210 Doxygen::mscFileNameDict->clear();
211 Doxygen::diaFileNameDict->clear();
212 Doxygen::formulaDict->clear();
213 Doxygen::formulaNameDict->clear();
214 Doxygen::tagDestinationDict.clear();
215 delete Doxygen::citeDict;
216 delete Doxygen::mainPage; Doxygen::mainPage=0;
222 Statistics() { stats.setAutoDelete(TRUE); }
223 void begin(const char *name)
226 stat *entry= new stat(name,0);
232 stats.getLast()->elapsed=((double)time.elapsed())/1000.0;
237 if (Debug::isFlagSet(Debug::Time))
239 Debug::clearFlag("time");
242 msg("----------------------\n");
243 QListIterator<stat> sli(stats);
245 for ( sli.toFirst(); (s=sli.current()); ++sli )
247 msg("Spent %.3f seconds in %s",s->elapsed,s->name);
249 if (restore) Debug::setFlag("time");
256 stat() : name(NULL),elapsed(0) {}
257 stat(const char *n, double el) : name(n),elapsed(el) {}
266 fprintf(stderr,"--- inputNameDict stats ----\n");
267 Doxygen::inputNameDict->statistics();
268 fprintf(stderr,"--- includeNameDict stats ----\n");
269 Doxygen::includeNameDict->statistics();
270 fprintf(stderr,"--- exampleNameDict stats ----\n");
271 Doxygen::exampleNameDict->statistics();
272 fprintf(stderr,"--- imageNameDict stats ----\n");
273 Doxygen::imageNameDict->statistics();
274 fprintf(stderr,"--- dotFileNameDict stats ----\n");
275 Doxygen::dotFileNameDict->statistics();
276 fprintf(stderr,"--- mscFileNameDict stats ----\n");
277 Doxygen::mscFileNameDict->statistics();
278 fprintf(stderr,"--- diaFileNameDict stats ----\n");
279 Doxygen::diaFileNameDict->statistics();
280 //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
281 //g_excludeNameDict.statistics();
282 fprintf(stderr,"--- aliasDict stats ----\n");
283 Doxygen::aliasDict.statistics();
284 fprintf(stderr,"--- typedefDict stats ----\n");
285 fprintf(stderr,"--- namespaceAliasDict stats ----\n");
286 Doxygen::namespaceAliasDict.statistics();
287 fprintf(stderr,"--- formulaDict stats ----\n");
288 Doxygen::formulaDict->statistics();
289 fprintf(stderr,"--- formulaNameDict stats ----\n");
290 Doxygen::formulaNameDict->statistics();
291 fprintf(stderr,"--- tagDestinationDict stats ----\n");
292 Doxygen::tagDestinationDict.statistics();
293 fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
294 g_compoundKeywordDict.statistics();
295 fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
296 Doxygen::expandAsDefinedDict.statistics();
297 fprintf(stderr,"--- memGrpInfoDict stats ----\n");
298 Doxygen::memGrpInfoDict.statistics();
303 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
304 ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
305 static void findMember(EntryNav *rootNav,
311 enum FindBaseClassRelation_Mode
318 static bool findClassRelation(
323 QDict<int> *templateNames,
324 /*bool insertUndocumented*/
325 FindBaseClassRelation_Mode mode,
329 /** A struct contained the data for an STL class */
332 const char *className;
333 const char *baseClass1;
334 const char *baseClass2;
335 const char *templType1;
336 const char *templName1;
337 const char *templType2;
338 const char *templName2;
339 bool virtualInheritance;
343 static STLInfo g_stlinfo[] =
345 // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators
346 { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
347 { "array", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, // C++11
348 { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // deprecated
349 { "smart_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
350 { "unique_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
351 { "shared_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++14
352 { "weak_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
353 { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
354 { "error_code", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
355 { "error_category", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
356 { "system_error", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
357 { "error_condition", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
358 { "thread", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
359 { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE },
360 { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
361 { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
362 { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE },
363 { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
364 { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
365 { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
366 { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
367 { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
368 { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
369 { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
370 { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
371 { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
372 { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
373 { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
374 { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
375 { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
376 { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
377 { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
378 { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
379 { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
380 { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
381 { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
382 { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
383 { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
384 { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
385 { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
386 { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
387 { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE },
388 { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE },
389 { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE },
390 { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
391 { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE },
392 { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
393 { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
394 { "forward_list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, // C++11
395 { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
396 { "unordered_map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
397 { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
398 { "unordered_multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
399 { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
400 { "unordered_set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
401 { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
402 { "unordered_multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
403 { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
404 { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
405 { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
406 { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
407 { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
408 { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
409 { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
410 { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
411 { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
412 { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
413 { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
414 { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
415 { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
416 { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
417 { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
418 { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
419 { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
420 { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
421 { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
422 { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
423 { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE }
426 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
428 Entry *memEntry = new Entry;
429 memEntry->name = name;
430 memEntry->type = type;
431 memEntry->protection = Public;
432 memEntry->section = Entry::VARIABLE_SEC;
433 memEntry->brief = "STL member";
434 memEntry->hidden = FALSE;
435 memEntry->artificial = TRUE;
436 //memEntry->parent = root;
437 //root->addSubEntry(memEntry);
438 EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
439 memEntryNav->setEntry(memEntry);
440 rootNav->addChild(memEntryNav);
443 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
445 Entry *iteratorClassEntry = new Entry;
446 iteratorClassEntry->fileName = "[STL]";
447 iteratorClassEntry->startLine = 1;
448 iteratorClassEntry->name = name;
449 iteratorClassEntry->section = Entry::CLASS_SEC;
450 iteratorClassEntry->brief = "STL iterator class";
451 iteratorClassEntry->hidden = FALSE;
452 iteratorClassEntry->artificial= TRUE;
453 EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
454 iteratorClassEntryNav->setEntry(iteratorClassEntry);
455 classEntryNav->addChild(iteratorClassEntryNav);
459 static void addSTLClasses(EntryNav *rootNav)
461 Entry *namespaceEntry = new Entry;
462 namespaceEntry->fileName = "[STL]";
463 namespaceEntry->startLine = 1;
464 //namespaceEntry->parent = rootNav->entry();
465 namespaceEntry->name = "std";
466 namespaceEntry->section = Entry::NAMESPACE_SEC;
467 namespaceEntry->brief = "STL namespace";
468 namespaceEntry->hidden = FALSE;
469 namespaceEntry->artificial= TRUE;
470 //root->addSubEntry(namespaceEntry);
471 EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
472 namespaceEntryNav->setEntry(namespaceEntry);
473 rootNav->addChild(namespaceEntryNav);
475 STLInfo *info = g_stlinfo;
476 while (info->className)
478 //printf("Adding STL class %s\n",info->className);
479 QCString fullName = info->className;
480 fullName.prepend("std::");
482 // add fake Entry for the class
483 Entry *classEntry = new Entry;
484 classEntry->fileName = "[STL]";
485 classEntry->startLine = 1;
486 classEntry->name = fullName;
487 //classEntry->parent = namespaceEntry;
488 classEntry->section = Entry::CLASS_SEC;
489 classEntry->brief = "STL class";
490 classEntry->hidden = FALSE;
491 classEntry->artificial= TRUE;
492 //namespaceEntry->addSubEntry(classEntry);
493 EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
494 classEntryNav->setEntry(classEntry);
495 namespaceEntryNav->addChild(classEntryNav);
497 // add template arguments to class
498 if (info->templType1)
500 ArgumentList *al = new ArgumentList;
501 Argument *a=new Argument;
503 a->name=info->templType1;
505 if (info->templType2) // another template argument
509 a->name=info->templType2;
512 classEntry->tArgLists = new QList<ArgumentList>;
513 classEntry->tArgLists->setAutoDelete(TRUE);
514 classEntry->tArgLists->append(al);
516 // add member variables
517 if (info->templName1)
519 addSTLMember(classEntryNav,info->templType1,info->templName1);
521 if (info->templName2)
523 addSTLMember(classEntryNav,info->templType2,info->templName2);
525 if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" || fullName=="std::shared_ptr" ||
526 fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
528 Entry *memEntry = new Entry;
529 memEntry->name = "operator->";
530 memEntry->args = "()";
531 memEntry->type = "T*";
532 memEntry->protection = Public;
533 memEntry->section = Entry::FUNCTION_SEC;
534 memEntry->brief = "STL member";
535 memEntry->hidden = FALSE;
536 memEntry->artificial = FALSE;
537 EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
538 memEntryNav->setEntry(memEntry);
539 classEntryNav->addChild(memEntryNav);
541 if (info->baseClass1)
543 classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
545 if (info->baseClass2)
547 classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
551 // add iterator class
552 addSTLIterator(classEntryNav,fullName+"::iterator");
553 addSTLIterator(classEntryNav,fullName+"::const_iterator");
554 addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
555 addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
561 //----------------------------------------------------------------------------
563 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
564 FileDef *fileScope,TagInfo *tagInfo);
566 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
568 if (rootNav->parent()) // add the page to it's scope
570 QCString scope = rootNav->parent()->name();
571 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
573 scope=substitute(scope,".","::");
575 scope = stripAnonymousNamespaceScope(scope);
576 scope+="::"+pd->name();
577 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
585 static void addRelatedPage(EntryNav *rootNav)
587 Entry *root = rootNav->entry();
589 QListIterator<Grouping> gli(*root->groups);
591 for (;(g=gli.current());++gli)
593 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
595 //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
597 if (root->brief.isEmpty())
599 doc=root->doc+root->inbodyDocs;
603 doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
605 PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
606 root->docFile,root->docLine,
608 gd,rootNav->tagInfo(),
613 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
614 pd->addSectionsToDefinition(root->anchors);
615 pd->setLocalToc(root->localToc);
616 addPageToContext(pd,rootNav);
620 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
622 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
623 ((!includeExternal && rootNav->tagInfo()==0) ||
624 ( includeExternal && rootNav->tagInfo()!=0))
627 rootNav->loadEntry(g_storage);
628 Entry *root = rootNav->entry();
630 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
631 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
633 GroupDef *gd = Doxygen::groupSDict->find(root->name);
634 //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
635 // root->type.data(),root->name.data(),additional,includeExternal,gd);
639 if ( !gd->hasGroupTitle() )
641 gd->setGroupTitle( root->type );
643 else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
645 warn( root->fileName,root->startLine,
646 "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
647 qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
649 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
650 gd->setDocumentation( root->doc, root->docFile, root->docLine );
651 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
652 gd->addSectionsToDefinition(root->anchors);
653 gd->setRefItems(root->sli);
654 gd->setLanguage(root->lang);
658 if (rootNav->tagInfo())
660 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
661 gd->setReference(rootNav->tagInfo()->tagName);
665 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
667 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
668 // allow empty docs for group
669 gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
670 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
671 gd->addSectionsToDefinition(root->anchors);
672 Doxygen::groupSDict->append(root->name,gd);
673 gd->setRefItems(root->sli);
674 gd->setLanguage(root->lang);
678 rootNav->releaseEntry();
680 if (rootNav->children())
682 EntryNavListIterator eli(*rootNav->children());
684 for (;(e=eli.current());++eli)
686 buildGroupListFiltered(e,additional,includeExternal);
691 static void buildGroupList(EntryNav *rootNav)
693 // --- first process only local groups
694 // first process the @defgroups blocks
695 buildGroupListFiltered(rootNav,FALSE,FALSE);
696 // then process the @addtogroup, @weakgroup blocks
697 buildGroupListFiltered(rootNav,TRUE,FALSE);
699 // --- then also process external groups
700 // first process the @defgroups blocks
701 buildGroupListFiltered(rootNav,FALSE,TRUE);
702 // then process the @addtogroup, @weakgroup blocks
703 buildGroupListFiltered(rootNav,TRUE,TRUE);
706 static void findGroupScope(EntryNav *rootNav)
708 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
709 rootNav->parent() && !rootNav->parent()->name().isEmpty())
712 if ((gd=Doxygen::groupSDict->find(rootNav->name())))
714 QCString scope = rootNav->parent()->name();
715 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
717 scope=substitute(scope,".","::");
719 scope = stripAnonymousNamespaceScope(scope);
720 scope+="::"+gd->name();
721 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope,0,rootNav->tagInfo());
724 gd->setGroupScope(d);
728 RECURSE_ENTRYTREE(findGroupScope,rootNav);
731 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
733 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
735 rootNav->loadEntry(g_storage);
736 Entry *root = rootNav->entry();
738 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
739 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
742 if ((gd=Doxygen::groupSDict->find(root->name)))
744 //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
745 addGroupToGroups(root,gd);
749 rootNav->releaseEntry();
751 if (rootNav->children())
753 EntryNavListIterator eli(*rootNav->children());
755 for (;(e=eli.current());++eli)
757 organizeSubGroupsFiltered(e,additional);
762 static void organizeSubGroups(EntryNav *rootNav)
764 //printf("Defining groups\n");
765 // first process the @defgroups blocks
766 organizeSubGroupsFiltered(rootNav,FALSE);
767 //printf("Additional groups\n");
768 // then process the @addtogroup, @weakgroup blocks
769 organizeSubGroupsFiltered(rootNav,TRUE);
772 //----------------------------------------------------------------------
774 static void buildFileList(EntryNav *rootNav)
776 if (((rootNav->section()==Entry::FILEDOC_SEC) ||
777 ((rootNav->section() & Entry::FILE_MASK) && Config_getBool(EXTRACT_ALL))) &&
778 !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
781 rootNav->loadEntry(g_storage);
782 Entry *root = rootNav->entry();
785 FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
786 //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
790 if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
791 (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
794 root->fileName,root->startLine,
795 "file %s already documented. "
796 "Skipping documentation.",
803 //printf("Adding documentation!\n");
804 // using FALSE in setDocumentation is small hack to make sure a file
805 // is documented even if a \file command is used without further
807 fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
808 fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
809 fd->addSectionsToDefinition(root->anchors);
810 fd->setRefItems(root->sli);
811 QListIterator<Grouping> gli(*root->groups);
813 for (;(g=gli.current());++gli)
816 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
819 fd->makePartOfGroup(gd);
820 //printf("File %s: in group %s\n",fd->name().data(),s->data());
827 const char *fn = root->fileName.data();
829 text.sprintf("the name `%s' supplied as "
830 "the second argument in the \\file statement ",
832 if (ambig) // name is ambiguous
834 text+="matches the following input files:\n";
835 text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
836 text+="Please use a more specific name by "
837 "including a (larger) part of the path!";
839 else // name is not an input file
841 text+="is not an input file";
843 warn(fn,root->startLine,text);
846 rootNav->releaseEntry();
848 RECURSE_ENTRYTREE(buildFileList,rootNav);
851 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
854 (!root->doc.stripWhiteSpace().isEmpty() ||
855 !root->brief.stripWhiteSpace().isEmpty() ||
856 Config_getBool(EXTRACT_ALL)
857 ) && root->protection!=Private
860 //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
862 bool local=Config_getBool(FORCE_LOCAL_INCLUDES);
863 QCString includeFile = root->includeFile;
864 if (!includeFile.isEmpty() && includeFile.at(0)=='"')
867 includeFile=includeFile.mid(1,includeFile.length()-2);
869 else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
872 includeFile=includeFile.mid(1,includeFile.length()-2);
877 // see if we need to include a verbatim copy of the header file
878 //printf("root->includeFile=%s\n",root->includeFile.data());
879 if (!includeFile.isEmpty() &&
880 (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
882 { // explicit request
884 text.sprintf("the name `%s' supplied as "
885 "the argument of the \\class, \\struct, \\union, or \\include command ",
888 if (ambig) // name is ambiguous
890 text+="matches the following input files:\n";
891 text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
892 text+="Please use a more specific name by "
893 "including a (larger) part of the path!";
895 else // name is not an input file
897 text+="is not an input file";
899 warn(root->fileName,root->startLine,text);
901 else if (includeFile.isEmpty() && ifd &&
902 // see if the file extension makes sense
903 guessSection(ifd->name())==Entry::HEADER_SEC)
904 { // implicit assumption
908 // if a file is found, we mark it as a source file.
911 QCString iName = !root->includeName.isEmpty() ?
912 root->includeName : includeFile;
913 if (!iName.isEmpty()) // user specified include file
915 if (iName.at(0)=='<') local=FALSE; // explicit override
916 else if (iName.at(0)=='"') local=TRUE;
917 if (iName.at(0)=='"' || iName.at(0)=='<')
919 iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
926 else if (!Config_getList(STRIP_FROM_INC_PATH).isEmpty())
928 iName=stripFromIncludePath(fd->absFilePath());
930 else // use name of the file containing the class definition
934 if (fd->generateSourceFile()) // generate code for header
936 cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
938 else // put #include in the class documentation without link
940 cd->setIncludeFile(0,iName,local,TRUE);
947 static bool addNamespace(Entry *root,ClassDef *cd)
949 // see if this class is defined inside a namespace
950 if (root->section & Entry::COMPOUND_MASK)
952 Entry *e = root->parent;
955 if (e->section==Entry::NAMESPACE_SEC)
958 QCString nsName = stripAnonymousNamespaceScope(e->name);
959 //printf("addNameSpace() trying: %s\n",nsName.data());
960 if (!nsName.isEmpty() && nsName.at(0)!='@' &&
961 (nd=getResolvedNamespace(nsName))
964 cd->setNamespace(nd);
965 cd->setOuterScope(nd);
978 static Definition *findScope(Entry *root,int level=0)
980 if (root==0) return 0;
981 //printf("start findScope name=%s\n",root->name.data());
982 Definition *result=0;
983 if (root->section&Entry::SCOPE_MASK)
985 result = findScope(root->parent,level+1); // traverse to the root of the tree
988 //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
989 // TODO: look at template arguments
990 result = result->findInnerCompound(root->name);
992 else // reached the global scope
994 // TODO: look at template arguments
995 result = Doxygen::globalScope->findInnerCompound(root->name);
996 //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
999 //printf("end findScope(%s,%d)=%s\n",root->name.data(),
1000 // level,result==0 ? "<none>" : result->name().data());
1005 /*! returns the Definition object belonging to the first \a level levels of
1006 * full qualified name \a name. Creates an artificial scope if the scope is
1007 * not found and set the parent/child scope relation if the scope is found.
1009 static Definition *buildScopeFromQualifiedName(const QCString name,
1010 int level,SrcLangExt lang,TagInfo *tagInfo)
1012 //printf("buildScopeFromQualifiedName(%s) level=%d\n",name.data(),level);
1015 Definition *prevScope=Doxygen::globalScope;
1019 int idx=getScopeFragment(name,p,&l);
1020 if (idx==-1) return prevScope;
1021 QCString nsName = name.mid(idx,l);
1022 if (nsName.isEmpty()) return prevScope;
1023 if (!fullScope.isEmpty()) fullScope+="::";
1025 NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
1026 Definition *innerScope = nd;
1028 if (nd==0) cd = getClass(fullScope);
1029 if (nd==0 && cd) // scope is a class
1033 else if (nd==0 && cd==0 && fullScope.find('<')==-1) // scope is not known and could be a namespace!
1035 // introduce bogus namespace
1036 //printf("++ adding dummy namespace %s to %s tagInfo=%p\n",nsName.data(),prevScope->name().data(),tagInfo);
1037 nd=new NamespaceDef(
1038 "[generated]",1,1,fullScope,
1039 tagInfo?tagInfo->tagName:QCString(),
1040 tagInfo?tagInfo->fileName:QCString());
1041 nd->setLanguage(lang);
1043 // add namespace to the list
1044 Doxygen::namespaceSDict->inSort(fullScope,nd);
1047 else // scope is a namespace
1052 // make the parent/child scope relation
1053 prevScope->addInnerCompound(innerScope);
1054 innerScope->setOuterScope(prevScope);
1056 else // current scope is a class, so return only the namespace part...
1060 // proceed to the next scope fragment
1062 prevScope=innerScope;
1068 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
1069 FileDef *fileScope,TagInfo *tagInfo)
1071 //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
1072 Definition *resultScope=startScope;
1073 if (resultScope==0) resultScope=Doxygen::globalScope;
1074 QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
1076 i1=getScopeFragment(scope,0,&l1);
1079 //printf(">no fragments!\n");
1082 int p=i1+l1,l2=0,i2;
1083 while ((i2=getScopeFragment(scope,p,&l2))!=-1)
1085 QCString nestedNameSpecifier = scope.mid(i1,l1);
1086 Definition *orgScope = resultScope;
1087 //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
1088 resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
1089 //printf(" resultScope=%p\n",resultScope);
1092 NamespaceSDict *usedNamespaces;
1093 if (orgScope==Doxygen::globalScope && fileScope &&
1094 (usedNamespaces = fileScope->getUsedNamespaces()))
1095 // also search for used namespaces
1097 NamespaceSDict::Iterator ni(*usedNamespaces);
1099 for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
1101 // restart search within the used namespace
1102 resultScope = findScopeFromQualifiedName(nd,n,fileScope,tagInfo);
1106 // for a nested class A::I in used namespace N, we get
1107 // N::A::I while looking for A, so we should compare
1108 // resultScope->name() against scope.left(i2+l2)
1109 //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1110 if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1118 // also search for used classes. Complication: we haven't been able
1119 // to put them in the right scope yet, because we are still resolving
1120 // the scope relations!
1121 // Therefore loop through all used classes and see if there is a right
1122 // scope match between the used class and nestedNameSpecifier.
1123 QDictIterator<FileDef> ui(g_usingDeclarations);
1125 for (ui.toFirst();(usedFd=ui.current());++ui)
1127 //printf("Checking using class %s\n",ui.currentKey());
1128 if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1130 // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1131 // so use this instead.
1132 QCString fqn = QCString(ui.currentKey())+
1133 scope.right(scope.length()-p);
1134 resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),
1135 startScope->getLanguage(),0);
1136 //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1139 //printf("> Match! resultScope=%s\n",resultScope->name().data());
1145 //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1153 //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1157 ArgumentList *getTemplateArgumentsFromName(
1158 const QCString &name,
1159 const QList<ArgumentList> *tArgLists)
1161 if (tArgLists==0) return 0;
1163 QListIterator<ArgumentList> ali(*tArgLists);
1164 // for each scope fragment, check if it is a template and advance through
1167 while ((i=name.find("::",p))!=-1)
1169 NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1172 ClassDef *cd = getClass(name.left(i));
1175 if (cd->templateArguments())
1183 return ali.current();
1187 ClassDef::CompoundType convertToCompoundType(int section,uint64 specifier)
1189 ClassDef::CompoundType sec=ClassDef::Class;
1190 if (specifier&Entry::Struct)
1191 sec=ClassDef::Struct;
1192 else if (specifier&Entry::Union)
1193 sec=ClassDef::Union;
1194 else if (specifier&Entry::Category)
1195 sec=ClassDef::Category;
1196 else if (specifier&Entry::Interface)
1197 sec=ClassDef::Interface;
1198 else if (specifier&Entry::Protocol)
1199 sec=ClassDef::Protocol;
1200 else if (specifier&Entry::Exception)
1201 sec=ClassDef::Exception;
1202 else if (specifier&Entry::Service)
1203 sec=ClassDef::Service;
1204 else if (specifier&Entry::Singleton)
1205 sec=ClassDef::Singleton;
1209 //case Entry::UNION_SEC:
1210 case Entry::UNIONDOC_SEC:
1211 sec=ClassDef::Union;
1213 //case Entry::STRUCT_SEC:
1214 case Entry::STRUCTDOC_SEC:
1215 sec=ClassDef::Struct;
1217 //case Entry::INTERFACE_SEC:
1218 case Entry::INTERFACEDOC_SEC:
1219 sec=ClassDef::Interface;
1221 //case Entry::PROTOCOL_SEC:
1222 case Entry::PROTOCOLDOC_SEC:
1223 sec=ClassDef::Protocol;
1225 //case Entry::CATEGORY_SEC:
1226 case Entry::CATEGORYDOC_SEC:
1227 sec=ClassDef::Category;
1229 //case Entry::EXCEPTION_SEC:
1230 case Entry::EXCEPTIONDOC_SEC:
1231 sec=ClassDef::Exception;
1233 case Entry::SERVICEDOC_SEC:
1234 sec=ClassDef::Service;
1236 case Entry::SINGLETONDOC_SEC:
1237 sec=ClassDef::Singleton;
1244 static void addClassToContext(EntryNav *rootNav)
1246 //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1247 rootNav->loadEntry(g_storage);
1248 Entry *root = rootNav->entry();
1250 //NamespaceDef *nd = 0;
1251 FileDef *fd = rootNav->fileDef();
1254 if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1256 scName=rootNav->parent()->name();
1258 // name without parent's scope
1259 QCString fullName = root->name;
1261 // strip off any template parameters (but not those for specializations)
1262 fullName=stripTemplateSpecifiersFromScope(fullName);
1264 // name with scope (if not present already)
1265 QCString qualifiedName = fullName;
1266 if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1268 qualifiedName.prepend(scName+"::");
1271 // see if we already found the class before
1272 ClassDef *cd = getClass(qualifiedName);
1274 Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1275 cd ? qPrint(cd->name()) : qPrint(root->name), qPrint(qualifiedName),cd);
1279 fullName=cd->name();
1280 Debug::print(Debug::Classes,0," Existing class %s!\n",qPrint(cd->name()));
1281 //if (cd->templateArguments()==0)
1283 // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1284 // cd->setTemplateArguments(tArgList);
1287 cd->setDocumentation(root->doc,root->docFile,root->docLine);
1288 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1290 if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1292 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1295 //cd->setName(fullName); // change name to match docs
1297 if (cd->templateArguments()==0 || (cd->isForwardDeclared() && (root->spec&Entry::ForwardDecl)==0))
1299 // this happens if a template class declared with @class is found
1300 // before the actual definition or if a forward declaration has different template
1302 ArgumentList *tArgList =
1303 getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1304 cd->setTemplateArguments(tArgList);
1307 cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1309 cd->setMetaData(root->metaData);
1313 ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1316 QCString namespaceName;
1317 extractNamespaceName(fullName,className,namespaceName);
1319 //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1320 // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1323 QCString refFileName;
1324 TagInfo *tagInfo = rootNav->tagInfo();
1328 tagName = tagInfo->tagName;
1329 refFileName = tagInfo->fileName;
1330 if (fullName.find("::")!=-1)
1331 // symbols imported via tag files may come without the parent scope,
1332 // so we artificially create it here
1334 buildScopeFromQualifiedName(fullName,fullName.contains("::"),root->lang,tagInfo);
1337 ArgumentList *tArgList = 0;
1338 if ((root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java) && (i=fullName.find('<'))!=-1)
1340 // a Java/C# generic class looks like a C++ specialization, so we need to split the
1341 // name and template arguments here
1342 tArgList = new ArgumentList;
1343 stringToArgumentList(fullName.mid(i),tArgList);
1344 fullName=fullName.left(i);
1348 tArgList = getTemplateArgumentsFromName(fullName,root->tArgLists);
1350 cd=new ClassDef(tagInfo?tagName:root->fileName,root->startLine,root->startColumn,
1351 fullName,sec,tagName,refFileName,TRUE,root->spec&Entry::Enum);
1352 Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d tagInfo=%p\n",
1353 qPrint(fullName),sec,root->tArgLists ? (int)root->tArgLists->count() : -1, tagInfo);
1354 cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1355 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1356 cd->setLanguage(root->lang);
1357 cd->setId(root->id);
1358 cd->setHidden(root->hidden);
1359 cd->setArtificial(root->artificial);
1360 cd->setClassSpecifier(root->spec);
1361 cd->setTypeConstraints(root->typeConstr);
1362 //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1364 //printf("class %s template args=%s\n",fullName.data(),
1365 // tArgList ? tempArgListToString(tArgList,root->lang).data() : "<none>");
1366 cd->setTemplateArguments(tArgList);
1367 cd->setProtection(root->protection);
1368 cd->setIsStatic(root->stat);
1370 // file definition containing the class cd
1371 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1374 cd->setMetaData(root->metaData);
1376 // see if the class is found inside a namespace
1377 //bool found=addNamespace(root,cd);
1379 cd->insertUsedFile(fd);
1381 // add class to the list
1382 //printf("ClassDict.insert(%s)\n",fullName.data());
1383 Doxygen::classSDict->append(fullName,cd);
1385 if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1387 //printf("inserting generic '%s' cd=%p\n",fullName.data(),cd);
1388 Doxygen::genericsDict->insert(fullName,cd);
1392 cd->addSectionsToDefinition(root->anchors);
1393 if (!root->subGrouping) cd->setSubGrouping(FALSE);
1394 if (cd->hasDocumentation())
1396 addIncludeFile(cd,fd,root);
1398 if (fd && (root->section & Entry::COMPOUND_MASK))
1400 //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1401 // cd->name().data(),
1402 // fd->name().data(),
1403 // root->fileName.data()
1406 fd->insertClass(cd);
1408 addClassToGroups(root,cd);
1409 cd->setRefItems(root->sli);
1411 rootNav->releaseEntry();
1414 //----------------------------------------------------------------------
1415 // build a list of all classes mentioned in the documentation
1416 // and all classes that have a documentation block before their definition.
1417 static void buildClassList(EntryNav *rootNav)
1420 ((rootNav->section() & Entry::COMPOUND_MASK) ||
1421 rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1424 addClassToContext(rootNav);
1426 RECURSE_ENTRYTREE(buildClassList,rootNav);
1429 static void buildClassDocList(EntryNav *rootNav)
1432 (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1435 addClassToContext(rootNav);
1437 RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1440 static void resolveClassNestingRelations()
1442 ClassSDict::Iterator cli(*Doxygen::classSDict);
1443 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1452 for (cli.toFirst();(cd=cli.current());++cli)
1456 QCString name = stripAnonymousNamespaceScope(cd->name());
1457 //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1458 // also add class to the correct structural context
1459 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1460 name,cd->getFileDef(),0);
1463 //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1464 d->addInnerCompound(cd);
1465 cd->setOuterScope(d);
1471 // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1477 //give warnings for unresolved compounds
1479 for (cli.toFirst();(cd=cli.current());++cli)
1483 QCString name = stripAnonymousNamespaceScope(cd->name());
1484 //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1485 /// create the scope artificially
1486 // anyway, so we can at least relate scopes properly.
1487 Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage(),0);
1488 if (d!=cd && !cd->getDefFileName().isEmpty())
1489 // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1490 // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1491 // also avoid warning for stuff imported via a tagfile.
1493 d->addInnerCompound(cd);
1494 cd->setOuterScope(d);
1495 warn(cd->getDefFileName(),cd->getDefLine(),
1496 "Internal inconsistency: scope for class %s not "
1497 "found!",name.data()
1504 void distributeClassGroupRelations()
1506 //static bool inlineGroupedClasses = Config_getBool(INLINE_GROUPED_CLASSES);
1507 //if (!inlineGroupedClasses) return;
1508 //printf("** distributeClassGroupRelations()\n");
1510 ClassSDict::Iterator cli(*Doxygen::classSDict);
1511 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1514 for (cli.toFirst();(cd=cli.current());++cli)
1516 //printf("Checking %s\n",cd->name().data());
1517 // distribute the group to nested classes as well
1518 if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1520 //printf(" Candidate for merging\n");
1521 ClassSDict::Iterator ncli(*cd->getClassSDict());
1523 GroupDef *gd = cd->partOfGroups()->at(0);
1524 for (ncli.toFirst();(ncd=ncli.current());++ncli)
1526 if (ncd->partOfGroups()==0)
1528 //printf(" Adding %s to group '%s'\n",ncd->name().data(),
1529 // gd->groupTitle());
1530 ncd->makePartOfGroup(gd);
1534 cd->visited=TRUE; // only visit every class once
1539 //----------------------------
1541 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1543 QCString fullName = removeAnonymousScopes(templ->name());
1544 if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1545 fullName+="."+fieldName;
1546 ClassDef *cd = new ClassDef(templ->getDefFileName(),
1547 templ->getDefLine(),
1548 templ->getDefColumn(),
1550 templ->compoundType());
1551 cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1552 cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1553 cd->setLanguage(templ->getLanguage());
1554 cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1555 cd->setBodyDef(templ->getBodyDef());
1557 cd->setOuterScope(rootCd->getOuterScope());
1558 if (rootCd->getOuterScope()!=Doxygen::globalScope)
1560 rootCd->getOuterScope()->addInnerCompound(cd);
1563 FileDef *fd = templ->getFileDef();
1567 fd->insertClass(cd);
1569 GroupList *groups = rootCd->partOfGroups();
1572 GroupListIterator gli(*groups);
1574 for (gli.toFirst();(gd=gli.current());++gli)
1576 cd->makePartOfGroup(gd);
1580 //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1581 Doxygen::classSDict->append(fullName,cd);
1583 MemberList *ml = templ->getMemberList(MemberListType_pubAttribs);
1586 MemberListIterator li(*ml);
1588 for (li.toFirst();(md=li.current());++li)
1590 //printf(" Member %s type=%s\n",md->name().data(),md->typeString());
1591 MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),md->getDefColumn(),
1592 md->typeString(),md->name(),md->argsString(),md->excpString(),
1593 md->protection(),md->virtualness(),md->isStatic(),Member,
1596 imd->setMemberClass(cd);
1597 imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1598 imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1599 imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1600 imd->setMemberSpecifiers(md->getMemberSpecifiers());
1601 imd->setMemberGroupId(md->getMemberGroupId());
1602 imd->setInitializer(md->initializer());
1603 imd->setMaxInitLines(md->initializerLines());
1604 imd->setBitfields(md->bitfieldString());
1605 imd->setLanguage(md->getLanguage());
1606 cd->insertMember(imd);
1612 /** Look through the members of class \a cd and its public members.
1613 * If there is a member m of a tag less struct/union,
1614 * then we create a duplicate of the struct/union with the name of the
1615 * member to identify it.
1616 * So if cd has name S, then the tag less struct/union will get name S.m
1617 * Since tag less structs can be nested we need to call this function
1618 * recursively. Later on we need to patch the member types so we keep
1619 * track of the hierarchy of classes we create.
1621 static void processTagLessClasses(ClassDef *rootCd,
1623 ClassDef *tagParentCd,
1624 const QCString &prefix,int count)
1626 //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1627 //printf("checking members for %s\n",cd->name().data());
1628 if (cd->getClassSDict())
1630 MemberList *ml = cd->getMemberList(MemberListType_pubAttribs);
1633 MemberListIterator li(*ml);
1635 for (li.toFirst();(md=li.current());++li)
1637 QCString type = md->typeString();
1638 if (type.find("::@")!=-1) // member of tag less struct/union
1640 ClassSDict::Iterator it(*cd->getClassSDict());
1642 for (it.toFirst();(icd=it.current());++it)
1644 //printf(" member %s: type='%s'\n",md->name().data(),type.data());
1645 //printf(" comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1646 if (type.find(icd->name())!=-1) // matching tag less struct/union
1648 QCString name = md->name();
1649 if (name.at(0)=='@') name = "__unnamed__";
1650 if (!prefix.isEmpty()) name.prepend(prefix+".");
1651 //printf(" found %s for class %s\n",name.data(),cd->name().data());
1652 ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1653 processTagLessClasses(rootCd,icd,ncd,name,count+1);
1654 //printf(" addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1655 tagParentCd->addTaggedInnerClass(ncd);
1656 ncd->setTagLessReference(icd);
1658 // replace tag-less type for generated/original member
1659 // by newly created class name.
1660 // note the difference between changing cd and tagParentCd.
1661 // for the initial call this is the same pointer, but for
1662 // recursive calls cd is the original tag-less struct (of which
1663 // there is only one instance) and tagParentCd is the newly
1664 // generated tagged struct of which there can be multiple instances!
1665 MemberList *pml = tagParentCd->getMemberList(MemberListType_pubAttribs);
1668 MemberListIterator pli(*pml);
1670 for (pli.toFirst();(pmd=pli.current());++pli)
1672 if (pmd->name()==md->name())
1674 pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1675 //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1687 static void findTagLessClasses(ClassDef *cd)
1689 if (cd->getClassSDict())
1691 ClassSDict::Iterator it(*cd->getClassSDict());
1693 for (it.toFirst();(icd=it.current());++it)
1695 if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1697 findTagLessClasses(icd);
1702 processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1705 static void findTagLessClasses()
1707 ClassSDict::Iterator cli(*Doxygen::classSDict);
1709 for (cli.toFirst();(cd=cli.current());++cli) // for each class
1711 Definition *scope = cd->getOuterScope();
1712 if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1714 findTagLessClasses(cd);
1720 //----------------------------------------------------------------------
1721 // build a list of all namespaces mentioned in the documentation
1722 // and all namespaces that have a documentation block before their definition.
1723 static void buildNamespaceList(EntryNav *rootNav)
1726 (rootNav->section()==Entry::NAMESPACE_SEC ||
1727 rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1728 rootNav->section()==Entry::PACKAGEDOC_SEC
1730 !rootNav->name().isEmpty()
1733 rootNav->loadEntry(g_storage);
1734 Entry *root = rootNav->entry();
1736 //printf("** buildNamespaceList(%s)\n",root->name.data());
1738 QCString fName = root->name;
1739 if (root->section==Entry::PACKAGEDOC_SEC)
1741 fName=substitute(fName,".","::");
1744 QCString fullName = stripAnonymousNamespaceScope(fName);
1745 if (!fullName.isEmpty())
1747 //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1748 // root->fileName.data(), root->startLine);
1750 if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1752 nd->setDocumentation(root->doc,root->docFile,root->docLine);
1753 nd->setName(fullName); // change name to match docs
1754 nd->addSectionsToDefinition(root->anchors);
1755 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1756 if (nd->getLanguage()==SrcLangExt_Unknown)
1758 nd->setLanguage(root->lang);
1760 if (rootNav->tagInfo()==0) // if we found the namespace in a tag file
1761 // and also in a project file, then remove
1762 // the tag file reference
1764 nd->setReference("");
1765 nd->setFileName(fullName);
1767 nd->setMetaData(root->metaData);
1769 // file definition containing the namespace nd
1770 FileDef *fd=rootNav->fileDef();
1771 // insert the namespace in the file definition
1772 if (fd) fd->insertNamespace(nd);
1773 addNamespaceToGroups(root,nd);
1774 nd->setRefItems(root->sli);
1776 else // fresh namespace
1779 QCString tagFileName;
1780 TagInfo *tagInfo = rootNav->tagInfo();
1783 tagName = tagInfo->tagName;
1784 tagFileName = tagInfo->fileName;
1786 //printf("++ new namespace %s lang=%s tagName=%s\n",fullName.data(),langToString(root->lang).data(),tagName.data());
1787 NamespaceDef *nd=new NamespaceDef(tagInfo?tagName:root->fileName,root->startLine,
1788 root->startColumn,fullName,tagName,tagFileName,
1789 root->type,root->spec&Entry::Published);
1790 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1791 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1792 nd->addSectionsToDefinition(root->anchors);
1793 nd->setHidden(root->hidden);
1794 nd->setArtificial(root->artificial);
1795 nd->setLanguage(root->lang);
1796 nd->setId(root->id);
1797 nd->setMetaData(root->metaData);
1799 //printf("Adding namespace to group\n");
1800 addNamespaceToGroups(root,nd);
1801 nd->setRefItems(root->sli);
1803 // file definition containing the namespace nd
1804 FileDef *fd=rootNav->fileDef();
1805 // insert the namespace in the file definition
1806 if (fd) fd->insertNamespace(nd);
1808 // the empty string test is needed for extract all case
1809 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1810 nd->insertUsedFile(fd);
1811 nd->setBodySegment(root->bodyLine,root->endBodyLine);
1813 // add class to the list
1814 Doxygen::namespaceSDict->inSort(fullName,nd);
1816 // also add namespace to the correct structural context
1817 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName,0,tagInfo);
1818 //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1819 if (d==0) // we didn't find anything, create the scope artificially
1820 // anyway, so we can at least relate scopes properly.
1822 Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage(),tagInfo);
1823 d->addInnerCompound(nd);
1824 nd->setOuterScope(d);
1825 // TODO: Due to the order in which the tag file is written
1826 // a nested class can be found before its parent!
1830 d->addInnerCompound(nd);
1831 nd->setOuterScope(d);
1836 rootNav->releaseEntry();
1838 RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1841 //----------------------------------------------------------------------
1843 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1844 const QCString &name)
1846 NamespaceDef *usingNd =0;
1849 //printf("Found namespace dict %d\n",unl->count());
1850 NamespaceSDict::Iterator unli(*unl);
1852 for (unli.toFirst();(und=unli.current());++unli)
1854 QCString uScope=und->name()+"::";
1855 usingNd = getResolvedNamespace(uScope+name);
1856 //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1862 static void findUsingDirectives(EntryNav *rootNav)
1864 if (rootNav->section()==Entry::USINGDIR_SEC)
1866 rootNav->loadEntry(g_storage);
1867 Entry *root = rootNav->entry();
1869 //printf("Found using directive %s at line %d of %s\n",
1870 // root->name.data(),root->startLine,root->fileName.data());
1871 QCString name=substitute(root->name,".","::");
1872 if (name.right(2)=="::")
1874 name=name.left(name.length()-2);
1876 if (!name.isEmpty())
1878 NamespaceDef *usingNd = 0;
1879 NamespaceDef *nd = 0;
1880 FileDef *fd = rootNav->fileDef();
1883 // see if the using statement was found inside a namespace or inside
1884 // the global file scope.
1885 if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1886 (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1889 nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1890 if (!nsName.isEmpty())
1892 nd = getResolvedNamespace(nsName);
1896 // find the scope in which the `using' namespace is defined by prepending
1897 // the possible scopes in which the using statement was found, starting
1898 // with the most inner scope and going to the most outer scope (i.e.
1900 int scopeOffset = nsName.length();
1903 QCString scope=scopeOffset>0 ?
1904 nsName.left(scopeOffset)+"::" : QCString();
1905 usingNd = getResolvedNamespace(scope+name);
1906 //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1911 else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1915 } while (scopeOffset>=0 && usingNd==0);
1917 if (usingNd==0 && nd) // not found, try used namespaces in this scope
1918 // or in one of the parent namespace scopes
1920 NamespaceDef *pnd = nd;
1921 while (pnd && usingNd==0)
1923 // also try with one of the used namespaces found earlier
1924 usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1927 Definition *s = pnd->getOuterScope();
1928 if (s && s->definitionType()==Definition::TypeNamespace)
1930 pnd = (NamespaceDef*)s;
1938 if (usingNd==0 && fd) // still nothing, also try used namespace in the
1941 usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1944 //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1946 // add the namespace the correct scope
1949 //printf("using fd=%p nd=%p\n",fd,nd);
1952 //printf("Inside namespace %s\n",nd->name().data());
1953 nd->addUsingDirective(usingNd);
1957 //printf("Inside file %s\n",fd->name().data());
1958 fd->addUsingDirective(usingNd);
1961 else // unknown namespace, but add it anyway.
1963 //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1964 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,root->startColumn,name);
1965 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1966 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1967 nd->addSectionsToDefinition(root->anchors);
1968 //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1969 nd->setHidden(root->hidden);
1970 nd->setArtificial(TRUE);
1971 nd->setLanguage(root->lang);
1972 nd->setId(root->id);
1973 nd->setMetaData(root->metaData);
1975 QListIterator<Grouping> gli(*root->groups);
1977 for (;(g=gli.current());++gli)
1980 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1981 gd->addNamespace(nd);
1984 // insert the namespace in the file definition
1987 fd->insertNamespace(nd);
1988 fd->addUsingDirective(nd);
1991 // the empty string test is needed for extract all case
1992 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1993 nd->insertUsedFile(fd);
1994 // add class to the list
1995 Doxygen::namespaceSDict->inSort(name,nd);
1996 nd->setRefItems(root->sli);
2000 rootNav->releaseEntry();
2002 RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
2005 //----------------------------------------------------------------------
2007 static void buildListOfUsingDecls(EntryNav *rootNav)
2009 if (rootNav->section()==Entry::USINGDECL_SEC &&
2010 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2013 rootNav->loadEntry(g_storage);
2014 Entry *root = rootNav->entry();
2016 QCString name = substitute(root->name,".","::");
2018 if (g_usingDeclarations.find(name)==0)
2020 FileDef *fd = rootNav->fileDef();
2023 g_usingDeclarations.insert(name,fd);
2027 rootNav->releaseEntry();
2029 RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
2033 static void findUsingDeclarations(EntryNav *rootNav)
2035 if (rootNav->section()==Entry::USINGDECL_SEC &&
2036 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
2039 rootNav->loadEntry(g_storage);
2040 Entry *root = rootNav->entry();
2042 //printf("Found using declaration %s at line %d of %s inside section %x\n",
2043 // root->name.data(),root->startLine,root->fileName.data(),
2044 // rootNav->parent()->section());
2045 if (!root->name.isEmpty())
2047 ClassDef *usingCd = 0;
2048 NamespaceDef *nd = 0;
2049 FileDef *fd = rootNav->fileDef();
2052 // see if the using statement was found inside a namespace or inside
2053 // the global file scope.
2054 if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
2056 scName=rootNav->parent()->name();
2057 if (!scName.isEmpty())
2059 nd = getResolvedNamespace(scName);
2063 // Assume the using statement was used to import a class.
2064 // Find the scope in which the `using' namespace is defined by prepending
2065 // the possible scopes in which the using statement was found, starting
2066 // with the most inner scope and going to the most outer scope (i.e.
2069 QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
2070 usingCd = getClass(name); // try direct lookup first, this is needed to get
2071 // builtin STL classes to properly resolve, e.g.
2072 // vector -> std::vector
2075 usingCd = getResolvedClass(nd,fd,name); // try via resolving (see also bug757509)
2079 usingCd = Doxygen::hiddenClasses->find(name); // check if it is already hidden
2082 //printf("%s -> %p\n",root->name.data(),usingCd);
2083 if (usingCd==0) // definition not in the input => add an artificial class
2085 Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
2086 qPrint(name),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
2087 usingCd = new ClassDef(
2091 Doxygen::hiddenClasses->append(root->name,usingCd);
2092 usingCd->setArtificial(TRUE);
2093 usingCd->setLanguage(root->lang);
2097 Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",
2098 qPrint(usingCd->name()),
2099 nd?qPrint(nd->name()):
2100 fd?qPrint(fd->name()):
2106 //printf("Inside namespace %s\n",nd->name().data());
2107 nd->addUsingDeclaration(usingCd);
2111 //printf("Inside file %s\n",fd->name().data());
2112 fd->addUsingDeclaration(usingCd);
2116 rootNav->releaseEntry();
2118 RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
2121 //----------------------------------------------------------------------
2123 static void findUsingDeclImports(EntryNav *rootNav)
2125 if (rootNav->section()==Entry::USINGDECL_SEC &&
2126 (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
2129 //printf("Found using declaration %s inside section %x\n",
2130 // rootNav->name().data(), rootNav->parent()->section());
2131 QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
2132 fullName=stripAnonymousNamespaceScope(fullName);
2133 fullName=stripTemplateSpecifiersFromScope(fullName);
2134 ClassDef *cd = getClass(fullName);
2137 //printf("found class %s\n",cd->name().data());
2138 int i=rootNav->name().find("::");
2141 QCString scope=rootNav->name().left(i);
2142 QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
2143 ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2146 //printf("found class %s memName=%s\n",bcd->name().data(),memName.data());
2147 MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2150 MemberNameInfo *mni = mndict->find(memName);
2153 MemberNameInfoIterator mnii(*mni);
2155 for ( ; (mi=mnii.current()) ; ++mnii )
2157 MemberDef *md = mi->memberDef;
2158 if (md && md->protection()!=Private)
2161 rootNav->loadEntry(g_storage);
2162 Entry *root = rootNav->entry();
2164 //printf("found member %s\n",mni->memberName());
2165 MemberDef *newMd = 0;
2167 QCString fileName = root->fileName;
2168 if (fileName.isEmpty() && rootNav->tagInfo())
2170 fileName = rootNav->tagInfo()->tagName;
2172 ArgumentList *templAl = md->templateArguments();
2173 ArgumentList *al = md->templateArguments();
2174 newMd = new MemberDef(
2175 fileName,root->startLine,root->startColumn,
2176 md->typeString(),memName,md->argsString(),
2177 md->excpString(),root->protection,root->virt,
2178 md->isStatic(),Member,md->memberType(),
2179 templAl,al,root->metaData
2182 newMd->setMemberClass(cd);
2183 cd->insertMember(newMd);
2184 if (!root->doc.isEmpty() || !root->brief.isEmpty())
2186 newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2187 newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2188 newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2192 newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2193 newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2194 newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2196 newMd->setDefinition(md->definition());
2197 newMd->enableCallGraph(root->callGraph);
2198 newMd->enableCallerGraph(root->callerGraph);
2199 newMd->enableReferencedByRelation(root->referencedByRelation);
2200 newMd->enableReferencesRelation(root->referencesRelation);
2201 newMd->setBitfields(md->bitfieldString());
2202 newMd->addSectionsToDefinition(root->anchors);
2203 newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2204 newMd->setBodyDef(md->getBodyDef());
2205 newMd->setInitializer(md->initializer());
2206 newMd->setMaxInitLines(md->initializerLines());
2207 newMd->setMemberGroupId(root->mGrpId);
2208 newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2209 newMd->setLanguage(root->lang);
2210 newMd->setId(root->id);
2212 rootNav->releaseEntry();
2222 RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2225 //----------------------------------------------------------------------
2227 static void findIncludedUsingDirectives()
2229 // first mark all files as not visited
2230 FileNameListIterator fnli(*Doxygen::inputNameList);
2232 for (fnli.toFirst();(fn=fnli.current());++fnli)
2234 FileNameIterator fni(*fn);
2236 for (;(fd=fni.current());++fni)
2241 // then recursively add using directives found in #include files
2242 // to files that have not been visited.
2243 for (fnli.toFirst();(fn=fnli.current());++fnli)
2245 FileNameIterator fni(*fn);
2247 for (fni.toFirst();(fd=fni.current());++fni)
2251 //printf("----- adding using directives for file %s\n",fd->name().data());
2252 fd->addIncludedUsingDirectives();
2258 //----------------------------------------------------------------------
2260 static MemberDef *addVariableToClass(
2264 const QCString &name,
2266 MemberDef *fromAnnMemb,
2268 Relationship related)
2270 Entry *root = rootNav->entry();
2272 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2273 QCString scopeSeparator="::";
2274 SrcLangExt lang = cd->getLanguage();
2275 if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2277 qualScope = substitute(qualScope,"::",".");
2280 Debug::print(Debug::Variables,0,
2281 " class variable:\n"
2282 " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2289 qPrint(root->initializer)
2293 if (!root->type.isEmpty())
2295 if (related || mtype==MemberType_Friend || Config_getBool(HIDE_SCOPE_NAMES))
2297 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2299 def="using "+name+" = "+root->type.mid(7);
2303 def=root->type+" "+name+root->args;
2308 if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2310 def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2314 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2320 if (Config_getBool(HIDE_SCOPE_NAMES))
2322 def=name+root->args;
2326 def=qualScope+scopeSeparator+name+root->args;
2329 def.stripPrefix("static ");
2331 // see if the member is already found in the same scope
2332 // (this may be the case for a static member that is initialized
2333 // outside the class)
2334 MemberName *mn=Doxygen::memberNameSDict->find(name);
2337 MemberNameIterator mni(*mn);
2339 for (mni.toFirst();(md=mni.current());++mni)
2341 //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2342 // md->getClassDef(),cd,root->type.data(),md->typeString());
2343 if (md->getClassDef()==cd &&
2344 removeRedundantWhiteSpace(root->type)==md->typeString())
2345 // member already in the scope
2348 if (root->lang==SrcLangExt_ObjC &&
2349 root->mtype==Property &&
2350 md->memberType()==MemberType_Variable)
2351 { // Objective-C 2.0 property
2352 // turn variable into a property
2353 md->setProtection(root->protection);
2354 cd->reclassifyMember(md,MemberType_Property);
2356 addMemberDocs(rootNav,md,def,0,FALSE);
2357 //printf(" Member already found!\n");
2363 QCString fileName = root->fileName;
2364 if (fileName.isEmpty() && rootNav->tagInfo())
2366 fileName = rootNav->tagInfo()->tagName;
2369 // new member variable, typedef or enum value
2370 MemberDef *md=new MemberDef(
2371 fileName,root->startLine,root->startColumn,
2372 root->type,name,root->args,root->exception,
2373 prot,Normal,root->stat,related,
2374 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0, root->metaData);
2375 md->setTagInfo(rootNav->tagInfo());
2376 md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2377 //md->setDefFile(root->fileName);
2378 //md->setDefLine(root->startLine);
2379 md->setDocumentation(root->doc,root->docFile,root->docLine);
2380 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2381 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2382 md->setDefinition(def);
2383 md->setBitfields(root->bitfields);
2384 md->addSectionsToDefinition(root->anchors);
2385 md->setFromAnonymousScope(fromAnnScope);
2386 md->setFromAnonymousMember(fromAnnMemb);
2387 //md->setIndentDepth(indentDepth);
2388 md->setBodySegment(root->bodyLine,root->endBodyLine);
2389 md->setInitializer(root->initializer);
2390 md->setMaxInitLines(root->initLines);
2391 md->setMemberGroupId(root->mGrpId);
2392 md->setMemberSpecifiers(root->spec);
2393 md->setReadAccessor(root->read);
2394 md->setWriteAccessor(root->write);
2395 md->enableCallGraph(root->callGraph);
2396 md->enableCallerGraph(root->callerGraph);
2397 md->enableReferencedByRelation(root->referencedByRelation);
2398 md->enableReferencesRelation(root->referencesRelation);
2399 md->setHidden(root->hidden);
2400 md->setArtificial(root->artificial);
2401 md->setLanguage(root->lang);
2402 md->setId(root->id);
2403 addMemberToGroups(root,md);
2404 //if (root->mGrpId!=-1)
2406 // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2407 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
2409 md->setBodyDef(rootNav->fileDef());
2411 //printf(" Adding member=%s\n",md->name().data());
2412 // add the member to the global list
2417 else // new variable name
2419 mn = new MemberName(name);
2421 //printf("Adding memberName=%s\n",mn->memberName());
2422 //Doxygen::memberNameDict.insert(name,mn);
2423 //Doxygen::memberNameList.append(mn);
2424 Doxygen::memberNameSDict->append(name,mn);
2425 // add the member to the class
2427 //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd);
2428 cd->insertMember(md);
2429 md->setRefItems(root->sli);
2431 //TODO: insert FileDef instead of filename strings.
2432 cd->insertUsedFile(rootNav->fileDef());
2433 rootNav->changeSection(Entry::EMPTY_SEC);
2437 //----------------------------------------------------------------------
2439 static MemberDef *addVariableToFile(
2442 const QCString &scope,
2443 const QCString &name,
2445 /*int indentDepth,*/
2446 MemberDef *fromAnnMemb)
2448 Entry *root = rootNav->entry();
2449 Debug::print(Debug::Variables,0,
2450 " global variable:\n"
2451 " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2461 FileDef *fd = rootNav->fileDef();
2463 // see if we have a typedef that should hide a struct or union
2464 if (mtype==MemberType_Typedef && Config_getBool(TYPEDEF_HIDES_STRUCT))
2466 QCString type = root->type;
2467 type.stripPrefix("typedef ");
2468 if (type.left(7)=="struct " || type.left(6)=="union ")
2470 type.stripPrefix("struct ");
2471 type.stripPrefix("union ");
2472 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2474 s = re.match(type,0,&l);
2477 QCString typeValue = type.mid(s,l);
2478 ClassDef *cd = getClass(typeValue);
2481 // this typedef should hide compound name cd, so we
2482 // change the name that is displayed from cd.
2483 cd->setClassName(name);
2484 cd->setDocumentation(root->doc,root->docFile,root->docLine);
2485 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2492 // see if the function is inside a namespace
2493 NamespaceDef *nd = 0;
2494 if (!scope.isEmpty())
2496 if (scope.find('@')!=-1) return 0; // anonymous scope!
2497 //nscope=removeAnonymousScopes(scope);
2498 //if (!nscope.isEmpty())
2500 nd = getResolvedNamespace(scope);
2505 // determine the definition of the global variable
2506 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' &&
2507 !Config_getBool(HIDE_SCOPE_NAMES)
2509 // variable is inside a namespace, so put the scope before the name
2511 SrcLangExt lang = nd->getLanguage();
2512 QCString sep=getLanguageSpecificSeparator(lang);
2514 if (!root->type.isEmpty())
2516 if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2518 def="using "+nd->name()+sep+name+" = "+root->type;
2520 else // normal member
2522 def=root->type+" "+nd->name()+sep+name+root->args;
2527 def=nd->name()+sep+name+root->args;
2532 if (!root->type.isEmpty() && !root->name.isEmpty())
2534 if (name.at(0)=='@') // dummy variable representing anonymous union
2540 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2542 def="using "+root->name+" = "+root->type.mid(7);
2544 else // normal member
2546 def=root->type+" "+name+root->args;
2552 def=name+root->args;
2555 def.stripPrefix("static ");
2557 MemberName *mn=Doxygen::functionNameSDict->find(name);
2560 //QCString nscope=removeAnonymousScopes(scope);
2561 //NamespaceDef *nd=0;
2562 //if (!nscope.isEmpty())
2563 if (!scope.isEmpty())
2565 nd = getResolvedNamespace(scope);
2567 MemberNameIterator mni(*mn);
2569 for (mni.toFirst();(md=mni.current());++mni)
2572 ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2573 root->fileName==md->getFileDef()->absFilePath()
2574 ) // both variable names in the same file
2575 || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2577 && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2578 && !md->isEnumerate() // in C# an enum value and enum can have the same name
2580 // variable already in the scope
2582 bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2583 md->argsString()!=root->args &&
2584 root->args.find('[')!=-1;
2585 bool staticsInDifferentFiles =
2586 root->stat && md->isStatic() &&
2587 root->fileName!=md->getDefFileName();
2589 if (md->getFileDef() &&
2590 !isPHPArray && // not a php array
2591 !staticsInDifferentFiles
2593 // not a php array variable
2596 Debug::print(Debug::Variables,0,
2597 " variable already found: scope=%s\n",qPrint(md->getOuterScope()->name()));
2598 addMemberDocs(rootNav,md,def,0,FALSE);
2599 md->setRefItems(root->sli);
2606 QCString fileName = root->fileName;
2607 if (fileName.isEmpty() && rootNav->tagInfo())
2609 fileName = rootNav->tagInfo()->tagName;
2612 Debug::print(Debug::Variables,0,
2613 " new variable, nd=%s tagInfo=%p!\n",nd?qPrint(nd->name()):"<global>",rootNav->tagInfo());
2614 // new global variable, enum value or typedef
2615 MemberDef *md=new MemberDef(
2616 fileName,root->startLine,root->startColumn,
2617 root->type,name,root->args,0,
2618 root->protection, Normal,root->stat,Member,
2619 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,0, root->metaData);
2620 md->setTagInfo(rootNav->tagInfo());
2621 md->setMemberSpecifiers(root->spec);
2622 md->setDocumentation(root->doc,root->docFile,root->docLine);
2623 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2624 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2625 md->addSectionsToDefinition(root->anchors);
2626 md->setFromAnonymousScope(fromAnnScope);
2627 md->setFromAnonymousMember(fromAnnMemb);
2628 md->setInitializer(root->initializer);
2629 md->setMaxInitLines(root->initLines);
2630 md->setMemberGroupId(root->mGrpId);
2631 md->setDefinition(def);
2632 md->setLanguage(root->lang);
2633 md->setId(root->id);
2634 md->enableCallGraph(root->callGraph);
2635 md->enableCallerGraph(root->callerGraph);
2636 md->enableReferencedByRelation(root->referencedByRelation);
2637 md->enableReferencesRelation(root->referencesRelation);
2638 md->setExplicitExternal(root->explicitExternal);
2639 //md->setOuterScope(fd);
2640 if (!root->explicitExternal)
2642 md->setBodySegment(root->bodyLine,root->endBodyLine);
2645 addMemberToGroups(root,md);
2647 md->setRefItems(root->sli);
2648 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2650 md->setNamespace(nd);
2651 nd->insertMember(md);
2654 // add member to the file (we do this even if we have already inserted
2655 // it into the namespace.
2659 fd->insertMember(md);
2662 // add member definition to the list of globals
2669 mn = new MemberName(name);
2671 Doxygen::functionNameSDict->append(name,mn);
2673 rootNav->changeSection(Entry::EMPTY_SEC);
2677 /*! See if the return type string \a type is that of a function pointer
2678 * \returns -1 if this is not a function pointer variable or
2679 * the index at which the closing brace of (...*name) was found.
2681 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2683 if (lang == SrcLangExt_Fortran || lang == SrcLangExt_VHDL)
2685 return -1; // Fortran and VHDL do not have function pointers
2687 static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2689 int bb=type.find('<');
2690 int be=type.findRev('>');
2691 if (!type.isEmpty() && // return type is non-empty
2692 (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2693 type.find("operator")==-1 && // not an operator
2694 (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2695 // not a function pointer return type
2696 !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2699 if (pLength) *pLength=l;
2700 //printf("findFunctionPtr=%d\n",i);
2705 //printf("findFunctionPtr=%d\n",-1);
2711 /*! Returns TRUE iff \a type is a class within scope \a context.
2712 * Used to detect variable declarations that look like function prototypes.
2714 static bool isVarWithConstructor(EntryNav *rootNav)
2716 static QRegExp initChars("[0-9\"'&*!^]+");
2717 static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2721 Definition *ctx = 0;
2725 //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2726 rootNav->loadEntry(g_storage);
2727 Entry *root = rootNav->entry();
2729 if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2734 else if ((fd = rootNav->fileDef()) &&
2735 (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2737 { // inside a .c file
2741 if (root->type.isEmpty())
2746 if (!rootNav->parent()->name().isEmpty())
2748 ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2751 // remove qualifiers
2752 findAndRemoveWord(type,"const");
2753 findAndRemoveWord(type,"static");
2754 findAndRemoveWord(type,"volatile");
2755 //if (type.left(6)=="const ") type=type.right(type.length()-6);
2756 typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2757 if (!typeIsClass && (ti=type.find('<'))!=-1)
2759 typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2761 if (typeIsClass) // now we still have to check if the arguments are
2762 // types or values. Since we do not have complete type info
2763 // we need to rely on heuristics :-(
2765 //printf("typeIsClass\n");
2766 ArgumentList *al = root->argList;
2767 if (al==0 || al->isEmpty())
2769 result=FALSE; // empty arg list -> function prototype.
2772 ArgumentListIterator ali(*al);
2774 for (ali.toFirst();(a=ali.current());++ali)
2776 if (!a->name.isEmpty() || !a->defval.isEmpty())
2778 if (a->name.find(initChars)==0)
2784 result=FALSE; // arg has (type,name) pair -> function prototype
2788 if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0)
2790 result=FALSE; // arg type is a known type
2793 if (checkIfTypedef(ctx,fd,a->type))
2795 //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2796 result=FALSE; // argument is a typedef
2799 if (a->type.at(a->type.length()-1)=='*' ||
2800 a->type.at(a->type.length()-1)=='&')
2801 // type ends with * or & => pointer or reference
2806 if (a->type.find(initChars)==0)
2808 result=TRUE; // argument type starts with typical initializer char
2811 QCString resType=resolveTypeDef(ctx,a->type);
2812 if (resType.isEmpty()) resType=a->type;
2814 if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2816 resType=resType.left(len);
2817 //printf("resType=%s\n",resType.data());
2818 if (resType=="int" || resType=="long" || resType=="float" ||
2819 resType=="double" || resType=="char" || resType=="signed" ||
2820 resType=="const" || resType=="unsigned" || resType=="void")
2822 result=FALSE; // type keyword -> function prototype
2831 //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2832 // root->type.data(),result);
2833 rootNav->releaseEntry();
2837 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2839 static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE);
2841 rootNav->loadEntry(g_storage);
2842 Entry *root = rootNav->entry();
2844 Debug::print(Debug::Variables,0,
2846 " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2852 qPrint(root->relates)
2854 //printf("root->parent->name=%s\n",root->parent->name.data());
2856 if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2857 (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2859 // recover from parse error caused by redundant braces
2860 // like in "int *(var[10]);", which is parsed as
2861 // type="" name="int *" args="(var[10])"
2863 root->type=root->name;
2864 static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2866 int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2869 root->name=root->args.mid(i,l);
2870 root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2872 //printf("new: type=`%s' name=`%s' args=`%s'\n",
2873 // root->type.data(),root->name.data(),root->args.data());
2878 if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2879 Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no");
2880 if (i!=-1) // function pointer
2882 int ai = root->type.find('[',i);
2883 if (ai>i) // function pointer array
2885 root->args.prepend(root->type.right(root->type.length()-ai));
2886 root->type=root->type.left(ai);
2888 else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2890 root->type=root->type.left(root->type.length()-1);
2891 root->args.prepend(") ");
2892 //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2897 QCString scope,name=removeRedundantWhiteSpace(root->name);
2899 // find the scope of this variable
2900 EntryNav *p = rootNav->parent();
2901 while ((p->section() & Entry::SCOPE_MASK))
2903 QCString scopeName = p->name();
2904 if (!scopeName.isEmpty())
2906 scope.prepend(scopeName);
2913 QCString type=root->type.stripWhiteSpace();
2915 bool isRelated=FALSE;
2916 bool isMemberOf=FALSE;
2918 QCString classScope=stripAnonymousNamespaceScope(scope);
2919 classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2920 QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2922 if (root->name.findRev("::")!=-1)
2924 if (root->type=="friend class" || root->type=="friend struct" ||
2925 root->type=="friend union")
2930 addVariableToClass(rootNav, // entry
2931 cd, // class to add member to
2932 MemberType_Friend, // type of member
2933 name, // name of the member
2934 FALSE, // from Anonymous scope
2935 0, // anonymous member
2936 Public, // protection
2937 Member // related to a class
2942 /* skip this member, because it is a
2943 * static variable definition (always?), which will be
2944 * found in a class scope as well, but then we know the
2945 * correct protection level, so only then it will be
2946 * inserted in the correct list!
2951 mtype=MemberType_EnumValue;
2952 else if (type.left(8)=="typedef ")
2953 mtype=MemberType_Typedef;
2954 else if (type.left(7)=="friend ")
2955 mtype=MemberType_Friend;
2956 else if (root->mtype==Property)
2957 mtype=MemberType_Property;
2958 else if (root->mtype==Event)
2959 mtype=MemberType_Event;
2960 else if (type.find("sequence<") != -1)
2961 mtype=sliceOpt ? MemberType_Sequence : MemberType_Typedef;
2962 else if (type.find("dictionary<") != -1)
2963 mtype=sliceOpt ? MemberType_Dictionary : MemberType_Typedef;
2965 mtype=MemberType_Variable;
2967 if (!root->relates.isEmpty()) // related variable
2970 isMemberOf=(root->relatesType == MemberOf);
2971 if (getClass(root->relates)==0 && !scope.isEmpty())
2972 scope=mergeScopes(scope,root->relates);
2974 scope=root->relates;
2978 if (cd==0 && classScope!=scope) cd=getClass(classScope);
2983 // if cd is an anonymous (=tag less) scope we insert the member
2984 // into a non-anonymous parent scope as well. This is needed to
2985 // be able to refer to it using \var or \fn
2987 //int indentDepth=0;
2988 int si=scope.find('@');
2989 //int anonyScopes = 0;
2992 static bool inlineSimpleStructs = Config_getBool(INLINE_SIMPLE_STRUCTS);
2993 if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2997 pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2998 if (!pScope.isEmpty())
2999 pScope.prepend(annScopePrefix);
3000 else if (annScopePrefix.length()>2)
3001 pScope=annScopePrefix.left(annScopePrefix.length()-2);
3002 if (name.at(0)!='@')
3004 if (!pScope.isEmpty() && (pcd=getClass(pScope)))
3006 md=addVariableToClass(rootNav, // entry
3007 pcd, // class to add member to
3008 mtype, // member type
3009 name, // member name
3010 TRUE, // from anonymous scope
3011 0, // from anonymous member
3013 isMemberOf ? Foreign : isRelated ? Related : Member
3017 else // anonymous scope inside namespace or file => put variable in the global scope
3019 if (mtype==MemberType_Variable)
3021 md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0);
3028 //printf("name=`%s' scope=%s scope.right=%s\n",
3029 // name.data(),scope.data(),
3030 // scope.right(scope.length()-si).data());
3031 addVariableToClass(rootNav, // entry
3032 cd, // class to add member to
3033 mtype, // member type
3034 name, // name of the member
3035 FALSE, // from anonymous scope
3036 md, // from anonymous member
3038 isMemberOf ? Foreign : isRelated ? Related : Member);
3040 else if (!name.isEmpty()) // global variable
3042 //printf("Inserting member in global scope %s!\n",scope.data());
3043 addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
3047 rootNav->releaseEntry();
3050 //----------------------------------------------------------------------
3051 // Searches the Entry tree for typedef documentation sections.
3052 // If found they are stored in their class or in the global list.
3053 static void buildTypedefList(EntryNav *rootNav)
3055 //printf("buildVarList(%s)\n",rootNav->name().data());
3056 if (!rootNav->name().isEmpty() &&
3057 rootNav->section()==Entry::VARIABLE_SEC &&
3058 rootNav->type().find("typedef ")!=-1 // its a typedef
3061 addVariable(rootNav);
3063 if (rootNav->children())
3065 EntryNavListIterator eli(*rootNav->children());
3067 for (;(e=eli.current());++eli)
3069 if (e->section()!=Entry::ENUM_SEC)
3071 buildTypedefList(e);
3077 //----------------------------------------------------------------------
3078 // Searches the Entry tree for sequence documentation sections.
3079 // If found they are stored in the global list.
3080 static void buildSequenceList(EntryNav *rootNav)
3082 if (!rootNav->name().isEmpty() &&
3083 rootNav->section()==Entry::VARIABLE_SEC &&
3084 rootNav->type().find("sequence<")!=-1 // it's a sequence
3087 addVariable(rootNav);
3089 if (rootNav->children())
3091 EntryNavListIterator eli(*rootNav->children());
3093 for (;(e=eli.current());++eli)
3095 if (e->section()!=Entry::ENUM_SEC)
3097 buildSequenceList(e);
3103 //----------------------------------------------------------------------
3104 // Searches the Entry tree for dictionary documentation sections.
3105 // If found they are stored in the global list.
3106 static void buildDictionaryList(EntryNav *rootNav)
3108 if (!rootNav->name().isEmpty() &&
3109 rootNav->section()==Entry::VARIABLE_SEC &&
3110 rootNav->type().find("dictionary<")!=-1 // it's a dictionary
3113 addVariable(rootNav);
3115 if (rootNav->children())
3117 EntryNavListIterator eli(*rootNav->children());
3119 for (;(e=eli.current());++eli)
3121 if (e->section()!=Entry::ENUM_SEC)
3123 buildDictionaryList(e);
3129 //----------------------------------------------------------------------
3130 // Searches the Entry tree for Variable documentation sections.
3131 // If found they are stored in their class or in the global list.
3133 static void buildVarList(EntryNav *rootNav)
3135 //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
3137 if (!rootNav->name().isEmpty() &&
3138 (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
3140 (rootNav->section()==Entry::VARIABLE_SEC // it's a variable
3142 (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable
3143 (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
3145 (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
3146 isVarWithConstructor(rootNav)
3149 ) // documented variable
3151 addVariable(rootNav,isFuncPtr);
3153 if (rootNav->children())
3155 EntryNavListIterator eli(*rootNav->children());
3157 for (;(e=eli.current());++eli)
3159 if (e->section()!=Entry::ENUM_SEC)
3167 //----------------------------------------------------------------------
3168 // Searches the Entry tree for Interface sections (UNO IDL only).
3169 // If found they are stored in their service or in the global list.
3172 static void addInterfaceOrServiceToServiceOrSingleton(
3173 EntryNav *const rootNav,
3175 QCString const& rname)
3177 Entry *const root = rootNav->entry();
3178 FileDef *const fd = rootNav->fileDef();
3179 enum MemberType const type = (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC)
3180 ? MemberType_Interface
3181 : MemberType_Service;
3182 QCString fileName = root->fileName;
3183 if (fileName.isEmpty() && rootNav->tagInfo())
3185 fileName = rootNav->tagInfo()->tagName;
3187 MemberDef *const md = new MemberDef(
3188 fileName, root->startLine, root->startColumn, root->type, rname,
3189 "", "", root->protection, root->virt, root->stat, Member,
3190 type, 0, root->argList, root->metaData);
3191 md->setTagInfo(rootNav->tagInfo());
3192 md->setMemberClass(cd);
3193 md->setDocumentation(root->doc,root->docFile,root->docLine);
3194 md->setDocsForDefinition(false);
3195 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3196 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3197 md->setBodySegment(root->bodyLine,root->endBodyLine);
3198 md->setMemberSpecifiers(root->spec);
3199 md->setMemberGroupId(root->mGrpId);
3200 md->setTypeConstraints(root->typeConstr);
3201 md->setLanguage(root->lang);
3204 md->addSectionsToDefinition(root->anchors);
3205 QCString const def = root->type + " " + rname;
3206 md->setDefinition(def);
3207 md->enableCallGraph(root->callGraph);
3208 md->enableCallerGraph(root->callerGraph);
3209 md->enableReferencedByRelation(root->referencedByRelation);
3210 md->enableReferencesRelation(root->referencesRelation);
3212 Debug::print(Debug::Functions,0,
3213 " Interface Member:\n"
3214 " `%s' `%s' proto=%d\n"
3222 // add member to the global list of all members
3224 if ((mn=Doxygen::memberNameSDict->find(rname)))
3230 mn = new MemberName(rname);
3232 Doxygen::memberNameSDict->append(rname,mn);
3235 // add member to the class cd
3236 cd->insertMember(md);
3237 // also add the member as a "base" (to get nicer diagrams)
3238 // "optional" interface/service get Protected which turns into dashed line
3239 BaseInfo base(rname,
3240 (root->spec & (Entry::Optional)) ? Protected : Public,Normal);
3241 findClassRelation(rootNav,cd,cd,&base,0,DocumentedOnly,true)
3242 || findClassRelation(rootNav,cd,cd,&base,0,Undocumented,true);
3243 // add file to list of used files
3244 cd->insertUsedFile(fd);
3246 addMemberToGroups(root,md);
3247 rootNav->changeSection(Entry::EMPTY_SEC);
3248 md->setRefItems(root->sli);
3251 static void buildInterfaceAndServiceList(EntryNav *const rootNav)
3253 if (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
3254 rootNav->section()==Entry::INCLUDED_SERVICE_SEC)
3256 rootNav->loadEntry(g_storage);
3257 Entry *const root = rootNav->entry();
3259 Debug::print(Debug::Functions,0,
3260 "EXPORTED_INTERFACE_SEC:\n"
3261 " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3263 qPrint(rootNav->parent()->name()),
3266 qPrint(root->relates),
3268 qPrint(root->fileName),
3271 root->tArgLists ? (int)root->tArgLists->count() : -1,
3275 qPrint(root->docFile)
3278 QCString const rname = removeRedundantWhiteSpace(root->name);
3280 if (!rname.isEmpty())
3282 QCString const scope = rootNav->parent()->name();
3283 ClassDef *const cd = getClass(scope);
3285 if (cd && ((ClassDef::Interface == cd->compoundType()) ||
3286 (ClassDef::Service == cd->compoundType()) ||
3287 (ClassDef::Singleton == cd->compoundType())))
3289 addInterfaceOrServiceToServiceOrSingleton(rootNav,cd,rname);
3293 assert(false); // was checked by scanner.l
3296 else if (rname.isEmpty())
3298 warn(root->fileName,root->startLine,
3299 "Illegal member name found.");
3302 rootNav->releaseEntry();
3304 // can only have these in IDL anyway
3305 switch (rootNav->lang())
3307 case SrcLangExt_Unknown: // fall through (root node always is Unknown)
3308 case SrcLangExt_IDL:
3309 RECURSE_ENTRYTREE(buildInterfaceAndServiceList,rootNav);
3312 return; // nothing to do here
3317 //----------------------------------------------------------------------
3318 // Searches the Entry tree for Function sections.
3319 // If found they are stored in their class or in the global list.
3321 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
3322 const QCString &rname,bool isFriend)
3324 Entry *root = rootNav->entry();
3325 FileDef *fd=rootNav->fileDef();
3328 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3329 int ts=root->type.find('<');
3330 int te=root->type.findRev('>');
3331 int i=re.match(root->type,0,&l);
3332 if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
3337 if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
3338 !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
3340 root->args+=root->type.right(root->type.length()-i-l);
3341 root->type=root->type.left(i+l);
3344 QCString name=removeRedundantWhiteSpace(rname);
3345 if (name.left(2)=="::") name=name.right(name.length()-2);
3348 if (isFriend) mtype=MemberType_Friend;
3349 else if (root->mtype==Signal) mtype=MemberType_Signal;
3350 else if (root->mtype==Slot) mtype=MemberType_Slot;
3351 else if (root->mtype==DCOP) mtype=MemberType_DCOP;
3352 else mtype=MemberType_Function;
3354 // strip redundant template specifier for constructors
3355 if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
3356 name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
3361 QCString fileName = root->fileName;
3362 if (fileName.isEmpty() && rootNav->tagInfo())
3364 fileName = rootNav->tagInfo()->tagName;
3367 //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
3368 // root->name.data(),root->args.data(),argListToString(root->argList).data()
3371 // adding class member
3372 MemberDef *md=new MemberDef(
3373 fileName,root->startLine,root->startColumn,
3374 root->type,name,root->args,root->exception,
3375 root->protection,root->virt,
3376 root->stat && root->relatesType != MemberOf,
3377 root->relates.isEmpty() ? Member :
3378 root->relatesType == MemberOf ? Foreign : Related,
3379 mtype,root->tArgLists ? root->tArgLists->getLast() : 0,root->argList, root->metaData);
3380 md->setTagInfo(rootNav->tagInfo());
3381 md->setMemberClass(cd);
3382 md->setDocumentation(root->doc,root->docFile,root->docLine);
3383 md->setDocsForDefinition(!root->proto);
3384 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3385 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3386 md->setBodySegment(root->bodyLine,root->endBodyLine);
3387 md->setMemberSpecifiers(root->spec);
3388 md->setMemberGroupId(root->mGrpId);
3389 md->setTypeConstraints(root->typeConstr);
3390 md->setLanguage(root->lang);
3391 md->setId(root->id);
3394 //md->setScopeTemplateArguments(root->tArgList);
3395 md->addSectionsToDefinition(root->anchors);
3397 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3398 SrcLangExt lang = cd->getLanguage();
3399 QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3400 if (scopeSeparator!="::")
3402 qualScope = substitute(qualScope,"::",scopeSeparator);
3404 if (lang==SrcLangExt_PHP)
3406 // for PHP we use Class::method and Namespace\method
3407 scopeSeparator="::";
3409 if (!root->relates.isEmpty() || isFriend || Config_getBool(HIDE_SCOPE_NAMES))
3411 if (!root->type.isEmpty())
3415 def=root->type+" "+name;
3419 def=root->type+" "+name+root->args;
3430 def=name+root->args;
3436 if (!root->type.isEmpty())
3440 def=root->type+" "+qualScope+scopeSeparator+name;
3444 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3451 def=qualScope+scopeSeparator+name;
3455 def=qualScope+scopeSeparator+name+root->args;
3459 if (def.left(7)=="friend ") def=def.right(def.length()-7);
3460 md->setDefinition(def);
3461 md->enableCallGraph(root->callGraph);
3462 md->enableCallerGraph(root->callerGraph);
3463 md->enableReferencedByRelation(root->referencedByRelation);
3464 md->enableReferencesRelation(root->referencesRelation);
3466 Debug::print(Debug::Functions,0,
3468 " `%s' `%s'::`%s' `%s' proto=%d\n"
3478 // add member to the global list of all members
3479 //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3481 if ((mn=Doxygen::memberNameSDict->find(name)))
3487 mn = new MemberName(name);
3489 Doxygen::memberNameSDict->append(name,mn);
3492 // add member to the class cd
3493 cd->insertMember(md);
3494 // add file to list of used files
3495 cd->insertUsedFile(fd);
3497 addMemberToGroups(root,md);
3498 rootNav->changeSection(Entry::EMPTY_SEC);
3499 md->setRefItems(root->sli);
3503 static void buildFunctionList(EntryNav *rootNav)
3505 if (rootNav->section()==Entry::FUNCTION_SEC)
3507 rootNav->loadEntry(g_storage);
3508 Entry *root = rootNav->entry();
3510 Debug::print(Debug::Functions,0,
3512 " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%lld proto=%d docFile=%s\n",
3514 qPrint(rootNav->parent()->name()),
3517 qPrint(root->relates),
3519 qPrint(root->fileName),
3522 root->tArgLists ? (int)root->tArgLists->count() : -1,
3526 qPrint(root->docFile)
3529 bool isFriend=root->type.find("friend ")!=-1;
3530 QCString rname = removeRedundantWhiteSpace(root->name);
3531 //printf("rname=%s\n",rname.data());
3533 QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3534 if (!rname.isEmpty() && scope.find('@')==-1)
3537 // check if this function's parent is a class
3538 scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3540 FileDef *rfd=rootNav->fileDef();
3542 int memIndex=rname.findRev("::");
3545 if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3547 // strip scope from name
3548 rname=rname.right(rname.length()-rootNav->parent()->name().length()-2);
3551 NamespaceDef *nd = 0;
3552 bool isMember=FALSE;
3555 int ts=rname.find('<');
3556 int te=rname.find('>');
3557 if (memIndex>0 && (ts==-1 || te==-1))
3559 // note: the following code was replaced by inMember=TRUE to deal with a
3560 // function rname='X::foo' of class X inside a namespace also called X...
3562 //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3566 // // strip namespace scope from name
3567 // scope=rname.left(memIndex);
3568 // rname=rname.right(rname.length()-memIndex-2);
3574 isMember=memIndex<ts || memIndex>te;
3578 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3579 int ts=root->type.find('<');
3580 int te=root->type.findRev('>');
3582 if (!rootNav->parent()->name().isEmpty() &&
3583 (rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
3585 // do some fuzzy things to exclude function pointers
3586 (root->type.isEmpty() ||
3587 ((ti=root->type.find(re,0))==-1 || // type does not contain ..(..*
3588 (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3589 root->args.find(")[")!=-1) || // and args not )[.. -> function pointer
3590 root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3591 cd->getLanguage()!=SrcLangExt_Cpp // language other than C
3595 Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
3596 qPrint(rname),qPrint(cd->name()));
3597 addMethodToClass(rootNav,cd,rname,isFriend);
3599 else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK)
3600 || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3603 (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3604 root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3606 // no member => unrelated function
3608 /* check the uniqueness of the function name in the file.
3609 * A file could contain a function prototype and a function definition
3610 * or even multiple function prototypes.
3615 if ((mn=Doxygen::functionNameSDict->find(rname)))
3617 Debug::print(Debug::Functions,0," --> function %s already found!\n",qPrint(rname));
3618 MemberNameIterator mni(*mn);
3619 for (mni.toFirst();(!found && (md=mni.current()));++mni)
3621 NamespaceDef *mnd = md->getNamespaceDef();
3622 NamespaceDef *rnd = 0;
3623 //printf("root namespace=%s\n",rootNav->parent()->name().data());
3624 QCString fullScope = scope;
3625 QCString parentScope = rootNav->parent()->name();
3626 if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3628 if (!scope.isEmpty()) fullScope.prepend("::");
3629 fullScope.prepend(parentScope);
3631 //printf("fullScope=%s\n",fullScope.data());
3632 rnd = getResolvedNamespace(fullScope);
3633 FileDef *mfd = md->getFileDef();
3634 QCString nsName,rnsName;
3635 if (mnd) nsName = mnd->name().copy();
3636 if (rnd) rnsName = rnd->name().copy();
3637 //printf("matching arguments for %s%s %s%s\n",
3638 // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3639 ArgumentList *mdAl = md->argumentList();
3640 ArgumentList *mdTempl = md->templateArguments();
3642 // in case of template functions, we need to check if the
3643 // functions have the same number of template parameters
3644 bool sameNumTemplateArgs = TRUE;
3645 bool matchingReturnTypes = TRUE;
3646 if (mdTempl!=0 && root->tArgLists)
3648 if (mdTempl->count()!=root->tArgLists->getLast()->count())
3650 sameNumTemplateArgs = FALSE;
3652 if (md->typeString()!=removeRedundantWhiteSpace(root->type))
3654 matchingReturnTypes = FALSE;
3658 bool staticsInDifferentFiles =
3659 root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3662 matchArguments2(md->getOuterScope(),mfd,mdAl,
3663 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3665 sameNumTemplateArgs &&
3666 matchingReturnTypes &&
3667 !staticsInDifferentFiles
3671 if (root->groups->getFirst()!=0)
3673 gd = Doxygen::groupSDict->find(root->groups->getFirst()->groupname.data());
3675 //printf("match!\n");
3676 //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3677 // see if we need to create a new member
3678 found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace
3679 ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and
3680 mfd->absFilePath()==root->fileName // prototype in the same file
3683 // otherwise, allow a duplicate global member with the same argument list
3684 if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3686 // member is already in the group, so we don't want to add it again.
3690 //printf("combining function with prototype found=%d in namespace %s\n",
3691 // found,nsName.data());
3695 // merge argument lists
3696 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
3697 // merge documentation
3698 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3700 ArgumentList *argList = new ArgumentList;
3701 stringToArgumentList(root->args,argList);
3704 //printf("setDeclArgumentList to %p\n",argList);
3705 md->setDeclArgumentList(argList);
3709 md->setArgumentList(argList);
3713 md->setDocumentation(root->doc,root->docFile,root->docLine);
3714 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3715 md->setDocsForDefinition(!root->proto);
3716 if (md->getStartBodyLine()==-1 && root->bodyLine!=-1)
3718 md->setBodySegment(root->bodyLine,root->endBodyLine);
3719 md->setBodyDef(rfd);
3722 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3724 md->setArgsString(root->args);
3726 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3728 md->addSectionsToDefinition(root->anchors);
3730 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3731 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3732 md->enableReferencedByRelation(md->hasReferencedByRelation() || root->referencedByRelation);
3733 md->enableReferencesRelation(md->hasReferencesRelation() || root->referencesRelation);
3735 // merge ingroup specifiers
3736 if (md->getGroupDef()==0 && root->groups->getFirst()!=0)
3738 addMemberToGroups(root,md);
3740 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3742 //printf("existing member is grouped, new member not\n");
3743 root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3745 else if (md->getGroupDef()!=0 && root->groups->getFirst()!=0)
3747 //printf("both members are grouped\n");
3750 // if md is a declaration and root is the corresponding
3751 // definition, then turn md into a definition.
3752 if (md->isPrototype() && !root->proto)
3754 md->setPrototype(FALSE);
3760 if (!found) /* global function is unique with respect to the file */
3762 Debug::print(Debug::Functions,0," --> new function %s found!\n",qPrint(rname));
3763 //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3764 // root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3766 // new global function
3767 ArgumentList *tArgList = root->tArgLists ? root->tArgLists->getLast() : 0;
3768 QCString name=removeRedundantWhiteSpace(rname);
3770 root->fileName,root->startLine,root->startColumn,
3771 root->type,name,root->args,root->exception,
3772 root->protection,root->virt,root->stat,Member,
3773 MemberType_Function,tArgList,root->argList,root->metaData);
3775 md->setTagInfo(rootNav->tagInfo());
3776 md->setLanguage(root->lang);
3777 md->setId(root->id);
3778 //md->setDefFile(root->fileName);
3779 //md->setDefLine(root->startLine);
3780 md->setDocumentation(root->doc,root->docFile,root->docLine);
3781 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3782 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3783 md->setPrototype(root->proto);
3784 md->setDocsForDefinition(!root->proto);
3785 md->setTypeConstraints(root->typeConstr);
3786 //md->setBody(root->body);
3787 md->setBodySegment(root->bodyLine,root->endBodyLine);
3788 FileDef *fd=rootNav->fileDef();
3790 md->addSectionsToDefinition(root->anchors);
3791 md->setMemberSpecifiers(root->spec);
3792 md->setMemberGroupId(root->mGrpId);
3794 // see if the function is inside a namespace that was not part of
3795 // the name already (in that case nd should be non-zero already)
3796 if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3798 //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3799 QCString nscope=rootNav->parent()->name();
3800 if (!nscope.isEmpty())
3802 nd = getResolvedNamespace(nscope);
3806 if (!scope.isEmpty())
3808 QCString sep = getLanguageSpecificSeparator(root->lang);
3811 scope = substitute(scope,"::",sep);
3817 if (!root->type.isEmpty())
3821 def=root->type+" "+scope+name;
3825 def=root->type+" "+scope+name+root->args;
3832 def=scope+name.copy();
3836 def=scope+name+root->args;
3839 Debug::print(Debug::Functions,0,
3840 " Global Function:\n"
3841 " `%s' `%s'::`%s' `%s' proto=%d\n"
3844 qPrint(rootNav->parent()->name()),
3850 md->setDefinition(def);
3851 md->enableCallGraph(root->callGraph);
3852 md->enableCallerGraph(root->callerGraph);
3853 md->enableReferencedByRelation(root->referencedByRelation);
3854 md->enableReferencesRelation(root->referencesRelation);
3855 //if (root->mGrpId!=-1)
3857 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
3860 md->setRefItems(root->sli);
3861 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3863 // add member to namespace
3864 md->setNamespace(nd);
3865 nd->insertMember(md);
3869 // add member to the file (we do this even if we have already
3870 // inserted it into the namespace)
3872 fd->insertMember(md);
3875 // add member to the list of file members
3876 //printf("Adding member=%s\n",md->name().data());
3878 if ((mn=Doxygen::functionNameSDict->find(name)))
3884 mn = new MemberName(name);
3886 Doxygen::functionNameSDict->append(name,mn);
3888 addMemberToGroups(root,md);
3889 if (root->relatesType == Simple) // if this is a relatesalso command,
3890 // allow find Member to pick it up
3892 rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished
3899 FileDef *fd=rootNav->fileDef();
3902 // add member to the file (we do this even if we have already
3903 // inserted it into the namespace)
3904 fd->insertMember(md);
3908 //printf("unrelated function %d `%s' `%s' `%s'\n",
3909 // root->parent->section,root->type.data(),rname.data(),root->args.data());
3913 Debug::print(Debug::Functions,0," --> %s not processed!\n",qPrint(rname));
3916 else if (rname.isEmpty())
3918 warn(root->fileName,root->startLine,
3919 "Illegal member name found."
3923 rootNav->releaseEntry();
3925 RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3928 //----------------------------------------------------------------------
3930 static void findFriends()
3932 //printf("findFriends()\n");
3933 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3935 for (;(fn=fnli.current());++fnli) // for each global function name
3937 //printf("Function name=`%s'\n",fn->memberName());
3939 if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3940 { // there are members with the same name
3941 //printf("Function name is also a member name\n");
3942 MemberNameIterator fni(*fn);
3944 for (;(fmd=fni.current());++fni) // for each function with that name
3946 MemberNameIterator mni(*mn);
3948 for (;(mmd=mni.current());++mni) // for each member with that name
3950 //printf("Checking for matching arguments
3951 // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3952 // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3953 ArgumentList *mmdAl = mmd->argumentList();
3954 ArgumentList *fmdAl = fmd->argumentList();
3955 if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3956 matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl,
3957 fmd->getOuterScope(), fmd->getFileDef(), fmdAl,
3961 ) // if the member is related and the arguments match then the
3962 // function is actually a friend.
3964 mergeArguments(mmdAl,fmdAl);
3965 if (!fmd->documentation().isEmpty())
3967 mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3969 else if (!mmd->documentation().isEmpty())
3971 fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3973 if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3975 mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3977 else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3979 fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3981 if (!fmd->inbodyDocumentation().isEmpty())
3983 mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3985 else if (!mmd->inbodyDocumentation().isEmpty())
3987 fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3989 //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3990 if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3992 mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3993 mmd->setBodyDef(fmd->getBodyDef());
3994 //mmd->setBodyMember(fmd);
3996 else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3998 fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3999 fmd->setBodyDef(mmd->getBodyDef());
4000 //fmd->setBodyMember(mmd);
4002 mmd->setDocsForDefinition(fmd->isDocsForDefinition());
4004 mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
4005 mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
4006 mmd->enableReferencedByRelation(mmd->hasReferencedByRelation() || fmd->hasReferencedByRelation());
4007 mmd->enableReferencesRelation(mmd->hasReferencesRelation() || fmd->hasReferencesRelation());
4009 fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
4010 fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
4011 fmd->enableReferencedByRelation(mmd->hasReferencedByRelation() || fmd->hasReferencedByRelation());
4012 fmd->enableReferencesRelation(mmd->hasReferencesRelation() || fmd->hasReferencesRelation());
4020 //----------------------------------------------------------------------
4022 static void transferFunctionDocumentation()
4024 //printf("---- transferFunctionDocumentation()\n");
4026 // find matching function declaration and definitions.
4027 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4029 for (;(mn=mnli.current());++mnli)
4031 //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
4032 MemberDef *mdef=0,*mdec=0;
4033 MemberNameIterator mni1(*mn);
4034 /* find a matching function declaration and definition for this function */
4035 for (;(mdec=mni1.current());++mni1)
4037 if (mdec->isPrototype() ||
4038 (mdec->isVariable() && mdec->isExternal())
4041 MemberNameIterator mni2(*mn);
4042 for (;(mdef=mni2.current());++mni2)
4044 combineDeclarationAndDefinition(mdec,mdef);
4051 //----------------------------------------------------------------------
4053 static void transferFunctionReferences()
4055 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4057 for (;(mn=mnli.current());++mnli)
4059 MemberDef *md,*mdef=0,*mdec=0;
4060 MemberNameIterator mni(*mn);
4061 /* find a matching function declaration and definition for this function */
4062 for (;(md=mni.current());++mni)
4064 if (md->isPrototype())
4066 else if (md->isVariable() && md->isExternal())
4069 if (md->isFunction() && !md->isStatic() && !md->isPrototype())
4071 else if (md->isVariable() && !md->isExternal() && !md->isStatic())
4076 ArgumentList *mdefAl = mdef->argumentList();
4077 ArgumentList *mdecAl = mdec->argumentList();
4079 matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl,
4080 mdec->getOuterScope(),mdec->getFileDef(),mdecAl,
4085 MemberSDict *defDict = mdef->getReferencesMembers();
4086 MemberSDict *decDict = mdec->getReferencesMembers();
4089 MemberSDict::IteratorDict msdi(*defDict);
4091 for (msdi.toFirst();(rmd=msdi.current());++msdi)
4093 if (decDict==0 || decDict->find(rmd->name())==0)
4095 mdec->addSourceReferences(rmd);
4101 MemberSDict::IteratorDict msdi(*decDict);
4103 for (msdi.toFirst();(rmd=msdi.current());++msdi)
4105 if (defDict==0 || defDict->find(rmd->name())==0)
4107 mdef->addSourceReferences(rmd);
4112 defDict = mdef->getReferencedByMembers();
4113 decDict = mdec->getReferencedByMembers();
4116 MemberSDict::IteratorDict msdi(*defDict);
4118 for (msdi.toFirst();(rmd=msdi.current());++msdi)
4120 if (decDict==0 || decDict->find(rmd->name())==0)
4122 mdec->addSourceReferencedBy(rmd);
4128 MemberSDict::IteratorDict msdi(*decDict);
4130 for (msdi.toFirst();(rmd=msdi.current());++msdi)
4132 if (defDict==0 || defDict->find(rmd->name())==0)
4134 mdef->addSourceReferencedBy(rmd);
4143 //----------------------------------------------------------------------
4145 static void transferRelatedFunctionDocumentation()
4147 // find match between function declaration and definition for
4148 // related functions
4149 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
4151 for (mnli.toFirst();(mn=mnli.current());++mnli)
4154 MemberNameIterator mni(*mn);
4155 /* find a matching function declaration and definition for this function */
4156 for (mni.toFirst();(md=mni.current());++mni) // for each global function
4158 //printf(" Function `%s'\n",md->name().data());
4160 if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
4162 //printf(" Member name found\n");
4164 MemberNameIterator rmni(*rmn);
4165 for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
4167 ArgumentList *mdAl = md->argumentList();
4168 ArgumentList *rmdAl = rmd->argumentList();
4169 //printf(" Member found: related=`%d'\n",rmd->isRelated());
4170 if ((rmd->isRelated() || rmd->isForeign()) && // related function
4171 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
4172 rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
4177 //printf(" Found related member `%s'\n",md->name().data());
4178 if (rmd->relatedAlso())
4179 md->setRelatedAlso(rmd->relatedAlso());
4180 else if (rmd->isForeign())
4191 //----------------------------------------------------------------------
4193 /*! make a dictionary of all template arguments of class cd
4194 * that are part of the base class name.
4195 * Example: A template class A with template arguments <R,S,T>
4196 * that inherits from B<T,T,S> will have T and S in the dictionary.
4198 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
4200 QDict<int> *templateNames = new QDict<int>(17);
4201 templateNames->setAutoDelete(TRUE);
4202 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
4203 if (templateArguments)
4205 ArgumentListIterator ali(*templateArguments);
4208 for (ali.toFirst();(arg=ali.current());++ali,count++)
4211 while ((i=re.match(name,p,&l))!=-1)
4213 QCString n = name.mid(i,l);
4216 if (templateNames->find(n)==0)
4218 templateNames->insert(n,new int(count));
4225 return templateNames;
4228 /*! Searches a class from within \a context and \a cd and returns its
4229 * definition if found (otherwise 0 is returned).
4231 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
4238 FileDef *fd=cd->getFileDef();
4239 if (context && cd!=context)
4241 result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
4245 result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
4247 if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
4249 result = getClass(name);
4252 (cd->getLanguage()==SrcLangExt_CSharp || cd->getLanguage()==SrcLangExt_Java) &&
4255 result = Doxygen::genericsDict->find(name);
4257 //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
4259 // context ? context->name().data() : "<none>",
4260 // cd ? cd->name().data() : "<none>",
4261 // result ? result->name().data() : "<none>",
4262 // Doxygen::classSDict->find(name)
4268 static void findUsedClassesForClass(EntryNav *rootNav,
4269 Definition *context,
4271 ClassDef *instanceCd,
4273 ArgumentList *actualArgs=0,
4274 QDict<int> *templateNames=0
4277 masterCd->visited=TRUE;
4278 ArgumentList *formalArgs = masterCd->templateArguments();
4279 if (masterCd->memberNameInfoSDict())
4281 MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
4282 MemberNameInfo *mni;
4283 for (;(mni=mnili.current());++mnili)
4285 MemberNameInfoIterator mnii(*mni);
4287 for (mnii.toFirst();(mi=mnii.current());++mnii)
4289 MemberDef *md=mi->memberDef;
4290 if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
4292 //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
4293 QCString type = normalizeNonTemplateArgumentsInString(md->typeString(),masterCd,formalArgs);
4294 QCString typedefValue = resolveTypeDef(masterCd,type);
4295 if (!typedefValue.isEmpty())
4297 type = typedefValue;
4300 QCString usedClassName;
4303 // the type can contain template variables, replace them if present
4306 type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
4309 //printf(" template substitution gives=%s\n",type.data());
4310 while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
4312 // find the type (if any) that matches usedClassName
4313 ClassDef *typeCd = getResolvedClass(masterCd,
4314 masterCd->getFileDef(),
4319 //printf("====> usedClassName=%s -> typeCd=%s\n",
4320 // usedClassName.data(),typeCd?typeCd->name().data():"<none>");
4323 usedClassName = typeCd->name();
4326 int sp=usedClassName.find('<');
4328 int si=usedClassName.findRev("::",sp);
4331 // replace any namespace aliases
4332 replaceNamespaceAliases(usedClassName,si);
4334 // add any template arguments to the class
4335 QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
4336 //printf(" usedName=%s\n",usedName.data());
4338 bool delTempNames=FALSE;
4339 if (templateNames==0)
4341 templateNames = getTemplateArgumentsInName(formalArgs,usedName);
4344 BaseInfo bi(usedName,Public,Normal);
4345 findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
4347 if (masterCd->templateArguments())
4349 ArgumentListIterator ali(*masterCd->templateArguments());
4352 for (ali.toFirst();(arg=ali.current());++ali,++count)
4354 if (arg->name==usedName) // type is a template argument
4357 Debug::print(Debug::Classes,0," New used class `%s'\n", qPrint(usedName));
4359 ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
4362 usedCd = new ClassDef(
4363 masterCd->getDefFileName(),masterCd->getDefLine(),
4364 masterCd->getDefColumn(),
4367 //printf("making %s a template argument!!!\n",usedCd->name().data());
4368 usedCd->makeTemplateArgument();
4369 usedCd->setUsedOnly(TRUE);
4370 usedCd->setLanguage(masterCd->getLanguage());
4371 Doxygen::hiddenClasses->append(usedName,usedCd);
4373 if (isArtificial) usedCd->setArtificial(TRUE);
4374 Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", qPrint(usedCd->name()));
4375 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4376 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4383 ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
4384 //printf("Looking for used class %s: result=%s master=%s\n",
4385 // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
4390 Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", qPrint(usedCd->name()));
4391 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
4392 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4397 delete templateNames;
4401 if (!found && !type.isEmpty()) // used class is not documented in any scope
4403 ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4404 if (usedCd==0 && !Config_getBool(HIDE_UNDOC_RELATIONS))
4406 if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4408 type+=md->argsString();
4410 Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", qPrint(type));
4411 usedCd = new ClassDef(
4412 masterCd->getDefFileName(),masterCd->getDefLine(),
4413 masterCd->getDefColumn(),
4414 type,ClassDef::Class);
4415 usedCd->setUsedOnly(TRUE);
4416 usedCd->setLanguage(masterCd->getLanguage());
4417 Doxygen::hiddenClasses->append(type,usedCd);
4421 if (isArtificial) usedCd->setArtificial(TRUE);
4422 Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", qPrint(usedCd->name()));
4423 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4424 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4433 //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4437 static void findBaseClassesForClass(
4439 Definition *context,
4441 ClassDef *instanceCd,
4442 FindBaseClassRelation_Mode mode,
4444 ArgumentList *actualArgs=0,
4445 QDict<int> *templateNames=0
4448 Entry *root = rootNav->entry();
4449 //if (masterCd->visited) return;
4450 masterCd->visited=TRUE;
4451 // The base class could ofcouse also be a non-nested class
4452 ArgumentList *formalArgs = masterCd->templateArguments();
4453 QListIterator<BaseInfo> bii(*root->extends);
4455 for (bii.toFirst();(bi=bii.current());++bii)
4457 //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4458 // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4459 bool delTempNames=FALSE;
4460 if (templateNames==0)
4462 templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4465 BaseInfo tbi(bi->name,bi->prot,bi->virt);
4466 if (actualArgs) // substitute the formal template arguments of the base class
4468 tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4470 //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4472 if (mode==DocumentedOnly)
4474 // find a documented base class in the correct scope
4475 if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4477 // 1.8.2: decided to show inheritance relations even if not documented,
4478 // we do make them artificial, so they do not appear in the index
4479 //if (!Config_getBool(HIDE_UNDOC_RELATIONS))
4480 bool b = Config_getBool(HIDE_UNDOC_RELATIONS) ? TRUE : isArtificial;
4482 // no documented base class -> try to find an undocumented one
4483 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4487 else if (mode==TemplateInstances)
4489 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4493 delete templateNames;
4499 //----------------------------------------------------------------------
4501 static bool findTemplateInstanceRelation(Entry *root,
4502 Definition *context,
4503 ClassDef *templateClass,const QCString &templSpec,
4504 QDict<int> *templateNames,
4507 Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n",
4508 qPrint(templateClass->name()),qPrint(templSpec));
4509 //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4510 // templateClass->name().data(),templSpec.data());
4511 //if (templateNames)
4513 // QDictIterator<int> qdi(*templateNames);
4514 // int *tempArgIndex;
4515 // for (;(tempArgIndex=qdi.current());++qdi)
4517 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4522 bool existingClass = (templSpec ==
4523 tempArgListToString(templateClass->templateArguments(),root->lang)
4525 if (existingClass) return TRUE;
4527 bool freshInstance=FALSE;
4528 ClassDef *instanceClass = templateClass->insertTemplateInstance(
4529 root->fileName,root->startLine,root->startColumn,templSpec,freshInstance);
4530 if (isArtificial) instanceClass->setArtificial(TRUE);
4531 instanceClass->setLanguage(root->lang);
4535 Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",qPrint(instanceClass->name()));
4536 Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4537 instanceClass->setTemplateBaseClassNames(templateNames);
4539 // search for new template instances caused by base classes of
4541 EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4542 if (templateRootNav)
4544 bool unloadNeeded=FALSE;
4545 Entry *templateRoot = templateRootNav->entry();
4546 if (templateRoot==0) // not yet loaded
4548 templateRootNav->loadEntry(g_storage);
4549 templateRoot = templateRootNav->entry();
4550 ASSERT(templateRoot!=0); // now it should really be loaded
4554 Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",
4555 qPrint(templateRoot->name),qPrint(templSpec));
4556 ArgumentList *templArgs = new ArgumentList;
4557 stringToArgumentList(templSpec,templArgs);
4558 findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4559 TemplateInstances,isArtificial,templArgs,templateNames);
4561 findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4562 isArtificial,templArgs,templateNames);
4565 if (unloadNeeded) // still cleanup to do
4567 templateRootNav->releaseEntry();
4572 Debug::print(Debug::Classes,0," no template root entry found!\n");
4573 // TODO: what happened if we get here?
4576 //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data());
4577 //ArgumentList *tl = templateClass->templateArguments();
4581 Debug::print(Debug::Classes,0," instance already exists!\n");
4586 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4589 int index=n.find('<');
4594 bool result = rightScopeMatch(scope,n);
4598 /*! Searches for the end of a template in prototype \a s starting from
4599 * character position \a startPos. If the end was found the position
4600 * of the closing \> is returned, otherwise -1 is returned.
4602 * Handles exotic cases such as
4611 static int findEndOfTemplate(const QCString &s,int startPos)
4613 // locate end of template
4617 int len = s.length();
4618 bool insideString=FALSE;
4619 bool insideChar=FALSE;
4621 while (e<len && brCount!=0)
4627 if (!insideString && !insideChar)
4629 if (e<len-1 && s.at(e+1)=='<')
4631 else if (roundCount==0)
4636 if (!insideString && !insideChar)
4638 if (e<len-1 && s.at(e+1)=='>')
4640 else if (roundCount==0)
4645 if (!insideString && !insideChar)
4649 if (!insideString && !insideChar)
4655 if (insideString && pc!='\\')
4664 if (insideChar && pc!='\\')
4674 return brCount==0 ? e : -1;
4677 static bool findClassRelation(
4679 Definition *context,
4682 QDict<int> *templateNames,
4683 FindBaseClassRelation_Mode mode,
4687 //printf("findClassRelation(class=%s base=%s templateNames=",
4688 // cd->name().data(),bi->name.data());
4689 //if (templateNames)
4691 // QDictIterator<int> qdi(*templateNames);
4692 // int *tempArgIndex;
4693 // for (;(tempArgIndex=qdi.current());++qdi)
4695 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4700 Entry *root = rootNav->entry();
4702 QCString biName=bi->name;
4703 bool explicitGlobalScope=FALSE;
4704 //printf("findClassRelation: biName=`%s'\n",biName.data());
4705 if (biName.left(2)=="::") // explicit global scope
4707 biName=biName.right(biName.length()-2);
4708 explicitGlobalScope=TRUE;
4711 EntryNav *parentNode=rootNav->parent();
4712 bool lastParent=FALSE;
4713 do // for each parent scope, starting with the largest scope
4714 // (in case of nested classes)
4716 QCString scopeName= parentNode ? parentNode->name().data() : "";
4717 int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4718 do // try all parent scope prefixes, starting with the largest scope
4720 //printf("scopePrefix=`%s' biName=`%s'\n",
4721 // scopeName.left(scopeOffset).data(),biName.data());
4723 QCString baseClassName=biName;
4726 baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4728 //QCString stripped;
4729 //baseClassName=stripTemplateSpecifiersFromScope
4730 // (removeRedundantWhiteSpace(baseClassName),TRUE,
4732 MemberDef *baseClassTypeDef=0;
4734 ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4742 //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4743 // baseClassName.data(),baseClass,cd,explicitGlobalScope);
4744 //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4745 // cd ? cd->name().data():"<none>",
4746 // baseClassName.data(),
4747 // baseClass?baseClass->name().data():"<none>",
4750 //if (baseClassName.left(root->name.length())!=root->name ||
4751 // baseClassName.at(root->name.length())!='<'
4752 // ) // Check for base class with the same name.
4753 // // If found then look in the outer scope for a match
4754 // // and prevent recursion.
4755 if (!isRecursiveBaseClass(rootNav->name(),baseClassName)
4756 || explicitGlobalScope
4757 // sadly isRecursiveBaseClass always true for UNO IDL ifc/svc members
4758 // (i.e. this is needed for addInterfaceOrServiceToServiceOrSingleton)
4759 || (rootNav->lang()==SrcLangExt_IDL &&
4760 (rootNav->section()==Entry::EXPORTED_INTERFACE_SEC ||
4761 rootNav->section()==Entry::INCLUDED_SERVICE_SEC)))
4764 Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4765 qPrint(baseClassName),
4766 qPrint(rootNav->name()),
4767 (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4768 (bi->virt==Normal)?"normal":"virtual",
4772 int i=baseClassName.find('<');
4773 int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4775 if (baseClass==0 && (root->lang==SrcLangExt_CSharp || root->lang==SrcLangExt_Java))
4777 // for Java/C# strip the template part before looking for matching
4778 baseClass = Doxygen::genericsDict->find(baseClassName.left(i));
4779 //printf("looking for '%s' result=%p\n",baseClassName.data(),baseClass);
4781 if (baseClass==0 && i!=-1)
4782 // base class has template specifiers
4784 // TODO: here we should try to find the correct template specialization
4785 // but for now, we only look for the unspecializated base class.
4786 int e=findEndOfTemplate(baseClassName,i+1);
4787 //printf("baseClass==0 i=%d e=%d\n",i,e);
4788 if (e!=-1) // end of template was found at e
4790 templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4791 baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4792 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4800 //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4801 // baseClass,baseClassName.data(),templSpec.data());
4804 else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4805 // know it is a template, so see if
4806 // we can also link to the explicit
4807 // instance (for instance if a class
4808 // derived from a template argument)
4810 //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4811 ClassDef *templClass=getClass(baseClass->name()+templSpec);
4814 // use the template instance instead of the template base.
4815 baseClass = templClass;
4816 templSpec.resize(0);
4820 //printf("cd=%p baseClass=%p\n",cd,baseClass);
4821 bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4822 //printf("1. found=%d\n",found);
4823 if (!found && si!=-1)
4825 QCString tmpTemplSpec;
4826 // replace any namespace aliases
4827 replaceNamespaceAliases(baseClassName,si);
4828 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4836 found=baseClass!=0 && baseClass!=cd;
4837 if (found) templSpec = tmpTemplSpec;
4839 //printf("2. found=%d\n",found);
4841 //printf("root->name=%s biName=%s baseClassName=%s\n",
4842 // root->name.data(),biName.data(),baseClassName.data());
4843 //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4845 // baseClassName+="-g";
4850 baseClass=findClassWithinClassContext(context,cd,baseClassName);
4851 //printf("findClassWithinClassContext(%s,%s)=%p\n",
4852 // cd->name().data(),baseClassName.data(),baseClass);
4853 found = baseClass!=0 && baseClass!=cd;
4858 // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4859 // the class name also in the alias mapping.
4860 QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4861 if (aliasName) // see if it is indeed a class.
4863 baseClass=getClass(*aliasName);
4864 found = baseClass!=0 && baseClass!=cd;
4867 bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4868 // make templSpec canonical
4869 // warning: the following line doesn't work for Mixin classes (see bug 560623)
4870 // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4872 //printf("3. found=%d\n",found);
4875 Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",qPrint(biName),qPrint(templSpec));
4876 // add base class to this class
4878 // if templSpec is not empty then we should "instantiate"
4879 // the template baseClass. A new ClassDef should be created
4880 // to represent the instance. To be able to add the (instantiated)
4881 // members and documentation of a template class
4882 // (inserted in that template class at a later stage),
4883 // the template should know about its instances.
4884 // the instantiation process, should be done in a recursive way,
4885 // since instantiating a template may introduce new inheritance
4887 if (!templSpec.isEmpty() && mode==TemplateInstances)
4889 // if baseClass is actually a typedef then we should not
4890 // instantiate it, since typedefs are in a different namespace
4891 // see bug531637 for an example where this would otherwise hang
4893 if (baseClassTypeDef==0)
4895 //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4896 findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4899 else if (mode==DocumentedOnly || mode==Undocumented)
4901 //printf(" => insert base class\n");
4903 if (baseClassTypeDef || cd->isCSharp())
4906 //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4908 static bool sipSupport = Config_getBool(SIP_SUPPORT);
4909 if (sipSupport) bi->prot=Public;
4910 if (!cd->isSubClass(baseClass)) // check for recursion, see bug690787
4912 cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4913 // add this class as super class to the base class
4914 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4918 warn(root->fileName,root->startLine,
4919 "Detected potential recursive class relation "
4920 "between class %s and base class %s!",
4921 cd->name().data(),baseClass->name().data()
4927 else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4929 Debug::print(Debug::Classes,0,
4930 " New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4931 qPrint(biName),qPrint(baseClassName),qPrint(templSpec),isArtificial
4934 if (isATemplateArgument)
4936 baseClass=Doxygen::hiddenClasses->find(baseClassName);
4939 baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4942 Doxygen::hiddenClasses->append(baseClassName,baseClass);
4943 if (isArtificial) baseClass->setArtificial(TRUE);
4944 baseClass->setLanguage(root->lang);
4949 baseClass=Doxygen::classSDict->find(baseClassName);
4950 //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4951 // baseClassName.data(),baseClass,biName.data(),templSpec.data());
4954 baseClass=new ClassDef(root->fileName,root->startLine,root->startColumn,
4957 Doxygen::classSDict->append(baseClassName,baseClass);
4958 if (isArtificial) baseClass->setArtificial(TRUE);
4959 baseClass->setLanguage(root->lang);
4960 int si = baseClassName.findRev("::");
4961 if (si!=-1) // class is nested
4963 Definition *sd = findScopeFromQualifiedName(Doxygen::globalScope,baseClassName.left(si),0,rootNav->tagInfo());
4964 if (sd==0 || sd==Doxygen::globalScope) // outer scope not found
4966 baseClass->setArtificial(TRUE); // see bug678139
4971 if (biName.right(2)=="-p")
4973 biName="<"+biName.left(biName.length()-2)+">";
4975 // add base class to this class
4976 cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4977 // add this class as super class to the base class
4978 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4979 // the undocumented base was found in this file
4980 baseClass->insertUsedFile(rootNav->fileDef());
4981 baseClass->setOuterScope(Doxygen::globalScope);
4982 if (baseClassName.right(2)=="-p")
4984 baseClass->setCompoundType(ClassDef::Protocol);
4990 Debug::print(Debug::Classes,0," Base class `%s' not found\n",qPrint(biName));
4995 if (mode!=TemplateInstances)
4997 warn(root->fileName,root->startLine,
4998 "Detected potential recursive class relation "
4999 "between class %s and base class %s!\n",
5000 root->name.data(),baseClassName.data()
5003 // for mode==TemplateInstance this case is quite common and
5004 // indicates a relation between a template class and a template
5005 // instance with the same name.
5011 else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
5015 //printf("new scopeOffset=`%d'",scopeOffset);
5016 } while (scopeOffset>=0);
5024 parentNode=parentNode->parent();
5026 } while (lastParent);
5031 //----------------------------------------------------------------------
5032 // Computes the base and super classes for each class in the tree
5034 static bool isClassSection(EntryNav *rootNav)
5036 if ( !rootNav->name().isEmpty() )
5038 if (rootNav->section() & Entry::COMPOUND_MASK)
5039 // is it a compound (class, struct, union, interface ...)
5043 else if (rootNav->section() & Entry::COMPOUNDDOC_MASK)
5044 // is it a documentation block with inheritance info.
5046 rootNav->loadEntry(g_storage);
5047 Entry *root = rootNav->entry();
5048 bool extends = root->extends->count()>0;
5049 rootNav->releaseEntry();
5050 if (extends) return TRUE;
5057 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
5059 static void findClassEntries(EntryNav *rootNav)
5061 if (isClassSection(rootNav))
5063 g_classEntries.insert(rootNav->name(),rootNav);
5065 RECURSE_ENTRYTREE(findClassEntries,rootNav);
5068 static QCString extractClassName(EntryNav *rootNav)
5070 // strip any anonymous scopes first
5071 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
5072 bName=stripTemplateSpecifiersFromScope(bName);
5074 if ((rootNav->lang()==SrcLangExt_CSharp || rootNav->lang()==SrcLangExt_Java) &&
5075 (i=bName.find('<'))!=-1)
5077 // a Java/C# generic class looks like a C++ specialization, so we need to strip the
5078 // template part before looking for matches
5079 bName=bName.left(i);
5084 /*! Using the dictionary build by findClassEntries(), this
5085 * function will look for additional template specialization that
5086 * exists as inheritance relations only. These instances will be
5087 * added to the template they are derived from.
5089 static void findInheritedTemplateInstances()
5091 ClassSDict::Iterator cli(*Doxygen::classSDict);
5092 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5093 QDictIterator<EntryNav> edi(g_classEntries);
5095 for (;(rootNav=edi.current());++edi)
5098 QCString bName = extractClassName(rootNav);
5099 Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",qPrint(bName));
5100 if ((cd=getClass(bName)))
5102 rootNav->loadEntry(g_storage);
5103 //printf("Class %s %d\n",cd->name().data(),root->extends->count());
5104 findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
5105 rootNav->releaseEntry();
5110 static void findUsedTemplateInstances()
5112 ClassSDict::Iterator cli(*Doxygen::classSDict);
5113 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5114 QDictIterator<EntryNav> edi(g_classEntries);
5116 for (;(rootNav=edi.current());++edi)
5119 QCString bName = extractClassName(rootNav);
5120 Debug::print(Debug::Classes,0," Usage: Class %s : \n",qPrint(bName));
5121 if ((cd=getClass(bName)))
5123 rootNav->loadEntry(g_storage);
5124 findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
5125 cd->addTypeConstraints();
5126 rootNav->releaseEntry();
5131 static void computeClassRelations()
5133 ClassSDict::Iterator cli(*Doxygen::classSDict);
5134 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
5135 QDictIterator<EntryNav> edi(g_classEntries);
5137 for (;(rootNav=edi.current());++edi)
5141 rootNav->loadEntry(g_storage);
5142 Entry *root = rootNav->entry();
5143 QCString bName = extractClassName(rootNav);
5144 Debug::print(Debug::Classes,0," Relations: Class %s : \n",qPrint(bName));
5145 if ((cd=getClass(bName)))
5147 findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
5149 int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
5150 if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
5151 bName.right(2)!="::")
5153 if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
5154 (guessSection(root->fileName)==Entry::HEADER_SEC ||
5155 Config_getBool(EXTRACT_LOCAL_CLASSES)) && // not defined in source file
5156 protectionLevelVisible(root->protection) && // hidden by protection
5157 !Config_getBool(HIDE_UNDOC_CLASSES) // undocumented class are visible
5160 root->fileName,root->startLine,
5161 "Compound %s is not documented.",
5166 rootNav->releaseEntry();
5170 static void computeTemplateClassRelations()
5172 QDictIterator<EntryNav> edi(g_classEntries);
5174 for (;(rootNav=edi.current());++edi)
5176 rootNav->loadEntry(g_storage);
5177 Entry *root = rootNav->entry();
5179 QCString bName=stripAnonymousNamespaceScope(root->name);
5180 bName=stripTemplateSpecifiersFromScope(bName);
5181 ClassDef *cd=getClass(bName);
5182 // strip any anonymous scopes first
5183 QDict<ClassDef> *templInstances = 0;
5184 if (cd && (templInstances=cd->getTemplateInstances()))
5186 Debug::print(Debug::Classes,0," Template class %s : \n",qPrint(cd->name()));
5187 QDictIterator<ClassDef> tdi(*templInstances);
5189 for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
5191 Debug::print(Debug::Classes,0," Template instance %s : \n",qPrint(tcd->name()));
5192 QCString templSpec = tdi.currentKey();
5193 ArgumentList *templArgs = new ArgumentList;
5194 stringToArgumentList(templSpec,templArgs);
5195 QList<BaseInfo> *baseList=root->extends;
5196 QListIterator<BaseInfo> it(*baseList);
5198 for (;(bi=it.current());++it) // for each base class of the template
5200 // check if the base class is a template argument
5201 BaseInfo tbi(bi->name,bi->prot,bi->virt);
5202 ArgumentList *tl = cd->templateArguments();
5205 QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
5206 QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
5207 // for each template name that we inherit from we need to
5208 // substitute the formal with the actual arguments
5209 QDict<int> *actualTemplateNames = new QDict<int>(17);
5210 actualTemplateNames->setAutoDelete(TRUE);
5211 QDictIterator<int> qdi(*templateNames);
5212 for (qdi.toFirst();qdi.current();++qdi)
5214 int templIndex = *qdi.current();
5215 Argument *actArg = 0;
5216 if (templIndex<(int)templArgs->count())
5218 actArg=templArgs->at(templIndex);
5221 baseClassNames!=0 &&
5222 baseClassNames->find(actArg->type)!=0 &&
5223 actualTemplateNames->find(actArg->type)==0
5226 actualTemplateNames->insert(actArg->type,new int(templIndex));
5229 delete templateNames;
5231 tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
5232 // find a documented base class in the correct scope
5233 if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
5235 // no documented base class -> try to find an undocumented one
5236 findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,TRUE);
5238 delete actualTemplateNames;
5242 } // class has no base classes
5245 rootNav->releaseEntry();
5249 //-----------------------------------------------------------------------
5250 // compute the references (anchors in HTML) for each function in the file
5252 static void computeMemberReferences()
5254 ClassSDict::Iterator cli(*Doxygen::classSDict);
5256 for (cli.toFirst();(cd=cli.current());++cli)
5258 cd->computeAnchors();
5260 FileNameListIterator fnli(*Doxygen::inputNameList);
5262 for (fnli.toFirst();(fn=fnli.current());++fnli)
5264 FileNameIterator fni(*fn);
5266 for (;(fd=fni.current());++fni)
5268 fd->computeAnchors();
5271 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5273 for (nli.toFirst();(nd=nli.current());++nli)
5275 nd->computeAnchors();
5277 GroupSDict::Iterator gli(*Doxygen::groupSDict);
5279 for (gli.toFirst();(gd=gli.current());++gli)
5281 gd->computeAnchors();
5285 //----------------------------------------------------------------------
5287 static void addListReferences()
5289 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
5291 for (mnli.toFirst();(mn=mnli.current());++mnli)
5293 MemberNameIterator mni(*mn);
5295 for (mni.toFirst();(md=mni.current());++mni)
5300 MemberNameSDict::Iterator fmnli(*Doxygen::functionNameSDict);
5301 for (fmnli.toFirst();(mn=fmnli.current());++fmnli)
5303 MemberNameIterator mni(*mn);
5305 for (mni.toFirst();(md=mni.current());++mni)
5311 ClassSDict::Iterator cli(*Doxygen::classSDict);
5313 for (cli.toFirst();(cd=cli.current());++cli)
5315 cd->addListReferences();
5318 FileNameListIterator fnli(*Doxygen::inputNameList);
5320 for (fnli.toFirst();(fn=fnli.current());++fnli)
5322 FileNameIterator fni(*fn);
5324 for (;(fd=fni.current());++fni)
5326 fd->addListReferences();
5330 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
5332 for (nli.toFirst();(nd=nli.current());++nli)
5334 nd->addListReferences();
5337 GroupSDict::Iterator gli(*Doxygen::groupSDict);
5339 for (gli.toFirst();(gd=gli.current());++gli)
5341 gd->addListReferences();
5344 PageSDict::Iterator pdi(*Doxygen::pageSDict);
5346 for (pdi.toFirst();(pd=pdi.current());++pdi)
5348 QCString name = pd->getOutputFileBase();
5349 if (pd->getGroupDef())
5351 name = pd->getGroupDef()->getOutputFileBase();
5354 QList<ListItemInfo> *xrefItems = pd->xrefListItems();
5355 addRefItem(xrefItems,
5357 theTranslator->trPage(TRUE,TRUE),
5358 name,pd->title(),0,0);
5362 DirSDict::Iterator ddi(*Doxygen::directories);
5364 for (ddi.toFirst();(dd=ddi.current());++ddi)
5366 QCString name = dd->getOutputFileBase();
5367 //if (dd->getGroupDef())
5369 // name = dd->getGroupDef()->getOutputFileBase();
5371 QList<ListItemInfo> *xrefItems = dd->xrefListItems();
5372 addRefItem(xrefItems,
5374 theTranslator->trDir(TRUE,TRUE),
5375 name,dd->displayName(),0,0);
5379 //----------------------------------------------------------------------
5381 static void generateXRefPages()
5383 QDictIterator<RefList> di(*Doxygen::xrefLists);
5385 for (di.toFirst();(rl=di.current());++di)
5391 //----------------------------------------------------------------------
5392 // Copy the documentation in entry `root' to member definition `md' and
5393 // set the function declaration of the member to `funcDecl'. If the boolean
5394 // over_load is set the standard overload text is added.
5396 static void addMemberDocs(EntryNav *rootNav,
5397 MemberDef *md, const char *funcDecl,
5403 Entry *root = rootNav->entry();
5404 //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
5405 // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
5406 QCString fDecl=funcDecl;
5407 // strip extern specifier
5408 fDecl.stripPrefix("extern ");
5409 md->setDefinition(fDecl);
5410 md->enableCallGraph(root->callGraph);
5411 md->enableCallerGraph(root->callerGraph);
5412 md->enableReferencedByRelation(root->referencedByRelation);
5413 md->enableReferencesRelation(root->referencesRelation);
5414 ClassDef *cd=md->getClassDef();
5415 NamespaceDef *nd=md->getNamespaceDef();
5418 fullName = cd->name();
5420 fullName = nd->name();
5422 if (!fullName.isEmpty()) fullName+="::";
5423 fullName+=md->name();
5424 FileDef *rfd=rootNav->fileDef();
5426 // TODO determine scope based on root not md
5427 Definition *rscope = md->getOuterScope();
5429 ArgumentList *mdAl = md->argumentList();
5432 //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
5433 mergeArguments(mdAl,al,!root->doc.isEmpty());
5438 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl,
5439 rscope,rfd,root->argList,
5444 //printf("merging arguments (2)\n");
5445 mergeArguments(mdAl,root->argList,!root->doc.isEmpty());
5448 if (over_load) // the \overload keyword was used
5450 QCString doc=getOverloadDocs();
5451 if (!root->doc.isEmpty())
5456 md->setDocumentation(doc,root->docFile,root->docLine);
5457 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5458 md->setDocsForDefinition(!root->proto);
5462 //printf("overwrite!\n");
5463 md->setDocumentation(root->doc,root->docFile,root->docLine);
5464 md->setDocsForDefinition(!root->proto);
5466 //printf("overwrite!\n");
5467 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5470 (md->inbodyDocumentation().isEmpty() ||
5471 !rootNav->parent()->name().isEmpty()
5472 ) && !root->inbodyDocs.isEmpty()
5475 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5479 //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5480 // md->initializer().data(),md->initializer().isEmpty(),
5481 // root->initializer.data(),root->initializer.isEmpty()
5483 if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5485 //printf("setInitializer\n");
5486 md->setInitializer(root->initializer);
5489 md->setMaxInitLines(root->initLines);
5493 if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5496 //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5497 md->setBodySegment(root->bodyLine,root->endBodyLine);
5498 md->setBodyDef(rfd);
5501 md->setRefItems(root->sli);
5504 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5505 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5506 md->enableReferencedByRelation(md->hasReferencedByRelation() || root->referencedByRelation);
5507 md->enableReferencesRelation(md->hasReferencesRelation() || root->referencesRelation);
5509 md->mergeMemberSpecifiers(root->spec);
5510 md->addSectionsToDefinition(root->anchors);
5511 addMemberToGroups(root,md);
5512 if (cd) cd->insertUsedFile(rfd);
5513 //printf("root->mGrpId=%d\n",root->mGrpId);
5514 if (root->mGrpId!=-1)
5516 if (md->getMemberGroupId()!=-1)
5518 if (md->getMemberGroupId()!=root->mGrpId)
5521 root->fileName,root->startLine,
5522 "member %s belongs to two different groups. The second "
5523 "one found here will be ignored.",
5528 else // set group id
5530 //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5531 md->setMemberGroupId(root->mGrpId);
5536 //----------------------------------------------------------------------
5537 // find a class definition given the scope name and (optionally) a
5538 // template list specifier
5540 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5541 const char *scopeName)
5543 ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5548 //----------------------------------------------------------------------
5549 // Adds the documentation contained in `root' to a global function
5550 // with name `name' and argument list `args' (for overloading) and
5551 // function declaration `decl' to the corresponding member definition.
5553 static bool findGlobalMember(EntryNav *rootNav,
5554 const QCString &namespaceName,
5557 const char *tempArg,
5561 Entry *root = rootNav->entry();
5562 Debug::print(Debug::FindMembers,0,
5563 "2. findGlobalMember(namespace=%s,type=%s,name=%s,tempArg=%s,decl=%s)\n",
5564 qPrint(namespaceName),qPrint(type),qPrint(name),qPrint(tempArg),qPrint(decl));
5566 if (n.isEmpty()) return FALSE;
5567 if (n.find("::")!=-1) return FALSE; // skip undefined class members
5568 MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5571 mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5573 if (mn) // function name defined
5575 Debug::print(Debug::FindMembers,0,"3. Found symbol scope\n");
5577 MemberNameIterator mni(*mn);
5580 for (mni.toFirst();(md=mni.current()) && !found;++mni)
5582 NamespaceDef *nd=md->getNamespaceDef();
5584 //printf("Namespace namespaceName=%s nd=%s\n",
5585 // namespaceName.data(),nd ? nd->name().data() : "<none>");
5587 FileDef *fd=rootNav->fileDef();
5588 //printf("File %s\n",fd ? fd->name().data() : "<none>");
5589 NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5590 //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0;
5591 //printf("NamespaceList %p\n",nl);
5593 // search in the list of namespaces that are imported via a
5594 // using declaration
5595 bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5597 if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
5598 (nd && nd->name()==namespaceName) || // or in the same namespace
5599 viaUsingDirective // member in `using' namespace
5602 Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5603 qPrint(md->name()),qPrint(namespaceName));
5605 NamespaceDef *rnd = 0;
5606 if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5608 ArgumentList *mdAl = md->argumentList();
5610 (mdAl==0 && root->argList->count()==0) ||
5611 md->isVariable() || md->isTypedef() || /* in case of function pointers */
5612 matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl,
5613 rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5616 // for template members we need to check if the number of
5617 // template arguments is the same, otherwise we are dealing with
5618 // different functions.
5619 if (matching && root->tArgLists)
5621 ArgumentList *mdTempl = md->templateArguments();
5624 if (root->tArgLists->getLast()->count()!=mdTempl->count())
5631 //printf("%s<->%s\n",
5632 // argListToString(md->argumentList()).data(),
5633 // argListToString(root->argList).data());
5635 // for static members we also check if the comment block was found in
5636 // the same file. This is needed because static members with the same
5637 // name can be in different files. Thus it would be wrong to just
5638 // put the comment block at the first syntactically matching member.
5639 if (matching && md->isStatic() &&
5640 md->getDefFileName()!=root->fileName &&
5646 // for template member we also need to check the return type
5647 if (md->templateArguments()!=0 && root->tArgLists!=0)
5649 //printf("Comparing return types '%s'<->'%s'\n",
5650 // md->typeString(),type);
5651 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
5652 qstrcmp(md->typeString(),type)!=0)
5654 //printf(" ---> no matching\n");
5659 if (matching) // add docs to the member
5661 Debug::print(Debug::FindMembers,0,"5. Match found\n");
5662 addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5667 if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5669 QCString fullFuncDecl=decl;
5670 if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5672 QCString("no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5675 warnMsg+="\nPossible candidates:\n";
5676 for (mni.toFirst();(md=mni.current());++mni)
5679 warnMsg+=substitute(md->declaration(),"%","%%");
5680 warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5681 " of file"+md->getDefFileName()+"\n";
5684 warn(root->fileName,root->startLine,warnMsg);
5687 else // got docs for an undefined member!
5689 if (root->type!="friend class" &&
5690 root->type!="friend struct" &&
5691 root->type!="friend union" &&
5692 root->type!="friend" &&
5693 (!Config_getBool(TYPEDEF_HIDES_STRUCT) ||
5694 root->type.find("typedef ")==-1)
5697 warn(root->fileName,root->startLine,
5698 "documented symbol `%s' was not declared or defined.",decl
5705 static bool isSpecialization(
5706 const QList<ArgumentList> &srcTempArgLists,
5707 const QList<ArgumentList> &dstTempArgLists
5710 QListIterator<ArgumentList> srclali(srcTempArgLists);
5711 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5712 for (;srclali.current();++srclali,++dstlali)
5714 ArgumentList *sal = srclali.current();
5715 ArgumentList *dal = dstlali.current();
5716 if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5721 static bool scopeIsTemplate(Definition *d)
5724 if (d && d->definitionType()==Definition::TypeClass)
5726 result = ((ClassDef*)d)->templateArguments() || scopeIsTemplate(d->getOuterScope());
5731 static QCString substituteTemplatesInString(
5732 const QList<ArgumentList> &srcTempArgLists,
5733 const QList<ArgumentList> &dstTempArgLists,
5734 ArgumentList *funcTempArgList, // can be used to match template specializations
5739 QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5740 //printf("type=%s\n",sa->type.data());
5742 while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5745 dst+=src.mid(p,i-p);
5746 QCString name=src.mid(i,l);
5748 QListIterator<ArgumentList> srclali(srcTempArgLists);
5749 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5750 for (;srclali.current() && !found;++srclali,++dstlali)
5752 ArgumentListIterator tsali(*srclali.current());
5753 ArgumentListIterator tdali(*dstlali.current());
5754 ArgumentListIterator *fali=0;
5755 Argument *tsa =0,*tda=0, *fa=0;
5756 if (funcTempArgList)
5758 fali = new ArgumentListIterator(*funcTempArgList);
5759 fa = fali->current();
5762 for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5764 tda = tdali.current();
5765 //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5766 // tsa->type.data(),tsa->name.data(),
5767 // tda->type.data(),tda->name.data());
5768 if (name==tsa->name)
5770 if (tda && tda->name.isEmpty())
5773 if (tda->type.left(6)=="class ") vc=6;
5774 else if (tda->type.left(9)=="typename ") vc=9;
5775 if (vc>0) // convert type=="class T" to type=="class" name=="T"
5777 tda->name = tda->type.mid(vc);
5778 tda->type = tda->type.left(vc-1);
5781 if (tda && !tda->name.isEmpty())
5783 name=tda->name; // substitute
5795 { ++(*fali); fa=fali->current(); }
5799 //printf(" srcList='%s' dstList='%s faList='%s'\n",
5800 // argListToString(srclali.current()).data(),
5801 // argListToString(dstlali.current()).data(),
5802 // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5807 dst+=src.right(src.length()-p);
5808 //printf(" substituteTemplatesInString(%s)=%s\n",
5809 // src.data(),dst.data());
5813 static void substituteTemplatesInArgList(
5814 const QList<ArgumentList> &srcTempArgLists,
5815 const QList<ArgumentList> &dstTempArgLists,
5818 ArgumentList *funcTempArgs = 0
5821 ArgumentListIterator sali(*src);
5822 ArgumentListIterator dali(*dst);
5824 Argument *da=dali.current();
5826 for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5828 QCString dstType = substituteTemplatesInString(
5829 srcTempArgLists,dstTempArgLists,funcTempArgs,
5831 QCString dstArray = substituteTemplatesInString(
5832 srcTempArgLists,dstTempArgLists,funcTempArgs,
5836 da=new Argument(*sa);
5850 dst->constSpecifier = src->constSpecifier;
5851 dst->volatileSpecifier = src->volatileSpecifier;
5852 dst->pureSpecifier = src->pureSpecifier;
5853 dst->trailingReturnType = substituteTemplatesInString(
5854 srcTempArgLists,dstTempArgLists,
5855 funcTempArgs,src->trailingReturnType);
5856 //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5857 // argListToString(src).data(),argListToString(dst).data()
5863 /*! This function tries to find a member (in a documented class/file/namespace)
5864 * that corresponds to the function/variable declaration given in \a funcDecl.
5866 * The boolean \a overloaded is used to specify whether or not a standard
5867 * overload documentation line should be generated.
5869 * The boolean \a isFunc is a hint that indicates that this is a function
5870 * instead of a variable or typedef.
5872 static void findMember(EntryNav *rootNav,
5878 Entry *root = rootNav->entry();
5880 Debug::print(Debug::FindMembers,0,
5881 "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5882 "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5883 "spec=%lld lang=%x\n",
5884 root,qPrint(funcDecl),qPrint(root->relates),overloaded,isFunc,root->mGrpId,
5885 root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5886 root->spec,root->lang
5891 QCString namespaceName;
5895 QCString funcTempList;
5896 QCString exceptions;
5898 bool isRelated=FALSE;
5899 bool isMemberOf=FALSE;
5900 bool isFriend=FALSE;
5905 if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5910 if (funcDecl.stripPrefix("inline "))
5912 root->spec|=Entry::Inline;
5915 if (funcDecl.stripPrefix("explicit "))
5917 root->spec|=Entry::Explicit;
5920 if (funcDecl.stripPrefix("mutable "))
5922 root->spec|=Entry::Mutable;
5925 if (funcDecl.stripPrefix("virtual "))
5931 // delete any ; from the function declaration
5933 while ((sep=funcDecl.find(';'))!=-1)
5935 funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5938 // make sure the first character is a space to simplify searching.
5939 if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5941 // remove some superfluous spaces
5942 funcDecl= substitute(
5944 substitute(funcDecl,"~ ","~"),
5948 ).stripWhiteSpace();
5950 //printf("funcDecl=`%s'\n",funcDecl.data());
5951 if (isFriend && funcDecl.left(6)=="class ")
5953 //printf("friend class\n");
5954 funcDecl=funcDecl.right(funcDecl.length()-6);
5955 funcName = funcDecl.copy();
5957 else if (isFriend && funcDecl.left(7)=="struct ")
5959 funcDecl=funcDecl.right(funcDecl.length()-7);
5960 funcName = funcDecl.copy();
5964 // extract information from the declarations
5965 parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5966 funcArgs,funcTempList,exceptions
5969 //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5970 // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5972 // the class name can also be a namespace name, we decide this later.
5973 // if a related class name is specified and the class name could
5974 // not be derived from the function declaration, then use the
5976 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5977 // scopeName.data(),className.data(),namespaceName.data());
5978 if (!root->relates.isEmpty())
5979 { // related member, prefix user specified scope
5981 isMemberOf=(root->relatesType == MemberOf);
5982 if (getClass(root->relates)==0 && !scopeName.isEmpty())
5984 scopeName= mergeScopes(scopeName,root->relates);
5988 scopeName = root->relates;
5992 if (root->relates.isEmpty() && rootNav->parent() &&
5993 ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5994 (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5996 !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName
5997 // with the scope in which it was found
5999 QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
6000 if (!scopeName.isEmpty() &&
6001 (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
6003 scopeName = joinedName;
6007 scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
6010 else // see if we can prefix a namespace or class that is used from the file
6012 FileDef *fd=rootNav->fileDef();
6015 NamespaceSDict *fnl = fd->getUsedNamespaces();
6018 QCString joinedName;
6020 NamespaceSDict::Iterator nsdi(*fnl);
6021 for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
6023 joinedName = fnd->name()+"::"+scopeName;
6024 if (Doxygen::namespaceSDict->find(joinedName))
6026 scopeName=joinedName;
6033 scopeName=stripTemplateSpecifiersFromScope(
6034 removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
6036 // funcSpec contains the last template specifiers of the given scope.
6037 // If this method does not have any template arguments or they are
6038 // empty while funcSpec is not empty we assume this is a
6039 // specialization of a method. If not, we clear the funcSpec and treat
6040 // this as a normal method of a template class.
6041 if (!(root->tArgLists &&
6042 root->tArgLists->count()>0 &&
6043 root->tArgLists->getFirst()->count()==0
6050 // split scope into a namespace and a class part
6051 extractNamespaceName(scopeName,className,namespaceName,TRUE);
6052 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
6053 // scopeName.data(),className.data(),namespaceName.data());
6055 //namespaceName=removeAnonymousScopes(namespaceName);
6056 if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
6058 //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
6059 // merge class and namespace scopes again
6060 scopeName.resize(0);
6061 if (!namespaceName.isEmpty())
6063 if (className.isEmpty())
6065 scopeName=namespaceName;
6067 else if (!root->relates.isEmpty() || // relates command with explicit scope
6068 !getClass(className)) // class name only exists in a namespace
6070 scopeName=namespaceName+"::"+className;
6074 scopeName=className;
6077 else if (!className.isEmpty())
6079 scopeName=className;
6081 //printf("new scope=`%s'\n",scopeName.data());
6083 QCString tempScopeName=scopeName;
6084 ClassDef *cd=getClass(scopeName);
6087 if (funcSpec.isEmpty())
6090 tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists,&argListIndex);
6094 tempScopeName=scopeName+funcSpec;
6097 //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
6098 // scopeName.data(),cd,root->tArgLists,tempScopeName.data());
6100 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6101 // rebuild the function declaration (needed to get the scope right).
6102 if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool(HIDE_SCOPE_NAMES))
6104 if (!funcType.isEmpty())
6106 if (isFunc) // a function -> we use argList for the arguments
6108 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
6112 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
6117 if (isFunc) // a function => we use argList for the arguments
6119 funcDecl=tempScopeName+"::"+funcName+funcTempList;
6121 else // variable => add `argument' list
6123 funcDecl=tempScopeName+"::"+funcName+funcArgs;
6127 else // build declaration without scope
6129 if (!funcType.isEmpty()) // but with a type
6131 if (isFunc) // function => omit argument list
6133 funcDecl=funcType+" "+funcName+funcTempList;
6135 else // variable => add `argument' list
6137 funcDecl=funcType+" "+funcName+funcArgs;
6144 funcDecl=funcName+funcTempList;
6148 funcDecl=funcName+funcArgs;
6153 if (funcType=="template class" && !funcTempList.isEmpty())
6154 return; // ignore explicit template instantiations
6156 Debug::print(Debug::FindMembers,0,
6157 "findMember() Parse results:\n"
6158 " namespaceName=`%s'\n"
6164 " funcTempList=`%s'\n"
6167 " exceptions=`%s'\n"
6172 qPrint(namespaceName),qPrint(className),
6173 qPrint(funcType),qPrint(funcSpec),qPrint(funcName),qPrint(funcArgs),qPrint(funcTempList),
6174 qPrint(funcDecl),qPrint(root->relates),qPrint(exceptions),isRelated,isMemberOf,isFriend,
6179 if (!funcName.isEmpty()) // function name is valid
6181 Debug::print(Debug::FindMembers,0,
6182 "1. funcName=`%s'\n",funcName.data());
6183 if (funcName.left(9)=="operator ") // strip class scope from cast operator
6185 funcName = substitute(funcName,className+"::","");
6187 if (!funcTempList.isEmpty()) // try with member specialization
6189 mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
6191 if (mn==0) // try without specialization
6193 mn=Doxygen::memberNameSDict->find(funcName);
6195 if (!isRelated && mn) // function name already found
6197 Debug::print(Debug::FindMembers,0,
6198 "2. member name exists (%d members with this name)\n",mn->count());
6199 if (!className.isEmpty()) // class name is valid
6201 if (funcSpec.isEmpty()) // not a member specialization
6205 MemberNameIterator mni(*mn);
6207 bool memFound=FALSE;
6208 for (mni.toFirst();!memFound && (md=mni.current());++mni)
6210 ClassDef *cd=md->getClassDef();
6211 Debug::print(Debug::FindMembers,0,
6212 "3. member definition found, "
6213 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
6214 qPrint(scopeName),cd ? qPrint(cd->name()) : "<none>",
6215 qPrint(md->argsString()),
6216 qPrint(root->fileName));
6217 //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
6218 FileDef *fd=rootNav->fileDef();
6220 if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
6222 //printf("scopeName %s->%s\n",scopeName.data(),
6223 // stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
6225 ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
6226 if (tcd==0 && cd && stripAnonymousNamespaceScope(cd->name())==scopeName)
6228 // don't be fooled by anonymous scopes
6231 //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
6232 // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
6234 if (cd && tcd==cd) // member's classes match
6236 Debug::print(Debug::FindMembers,0,
6237 "4. class definition %s found\n",cd->name().data());
6239 // get the template parameter lists found at the member declaration
6240 QList<ArgumentList> declTemplArgs;
6241 cd->getTemplateParameterLists(declTemplArgs);
6242 ArgumentList *templAl = md->templateArguments();
6245 declTemplArgs.append(templAl);
6248 // get the template parameter lists found at the member definition
6249 QList<ArgumentList> *defTemplArgs = root->tArgLists;
6250 //printf("defTemplArgs=%p\n",defTemplArgs);
6252 // do we replace the decl argument lists with the def argument lists?
6253 bool substDone=FALSE;
6254 ArgumentList *argList=0;
6256 /* substitute the occurrences of class template names in the
6257 * argument list before matching
6259 ArgumentList *mdAl = md->argumentList();
6260 if (declTemplArgs.count()>0 && defTemplArgs &&
6261 declTemplArgs.count()==defTemplArgs->count() &&
6265 /* the function definition has template arguments
6266 * and the class definition also has template arguments, so
6267 * we must substitute the template names of the class by that
6268 * of the function definition before matching.
6270 argList = new ArgumentList;
6271 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
6276 else /* no template arguments, compare argument lists directly */
6281 Debug::print(Debug::FindMembers,0,
6282 "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
6283 qPrint(argListToString(argList,TRUE)),qPrint(argListToString(root->argList,TRUE)),
6284 qPrint(className),qPrint(namespaceName)
6288 md->isVariable() || md->isTypedef() || // needed for function pointers
6289 (mdAl==0 && root->argList->count()==0) ||
6291 md->getClassDef(),md->getFileDef(),argList,
6292 cd,fd,root->argList,
6295 if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
6297 matching = FALSE; // don't match methods and attributes with the same name
6300 // for template member we also need to check the return type
6301 if (md->templateArguments()!=0 && root->tArgLists!=0)
6303 QCString memType = md->typeString();
6304 memType.stripPrefix("static "); // see bug700696
6305 funcType=substitute(stripTemplateSpecifiersFromScope(funcType,TRUE),
6306 className+"::",""); // see bug700693 & bug732594
6307 memType=substitute(stripTemplateSpecifiersFromScope(memType,TRUE),
6308 className+"::",""); // see bug758900
6309 Debug::print(Debug::FindMembers,0,
6310 "5b. Comparing return types '%s'<->'%s' #args %d<->%d\n",
6311 qPrint(md->typeString()),qPrint(funcType),
6312 md->templateArguments()->count(),root->tArgLists->getLast()->count());
6313 if (md->templateArguments()->count()!=root->tArgLists->getLast()->count() ||
6314 qstrcmp(memType,funcType))
6316 //printf(" ---> no matching\n");
6320 bool rootIsUserDoc = (root->section&Entry::MEMBERDOC_SEC)!=0;
6321 bool classIsTemplate = scopeIsTemplate(md->getClassDef());
6322 bool mdIsTemplate = md->templateArguments()!=0;
6323 bool classOrMdIsTemplate = mdIsTemplate || classIsTemplate;
6324 bool rootIsTemplate = root->tArgLists!=0;
6325 //printf("classIsTemplate=%d mdIsTemplate=%d rootIsTemplate=%d\n",classIsTemplate,mdIsTemplate,rootIsTemplate);
6326 if (!rootIsUserDoc && // don't check out-of-line @fn references, see bug722457
6327 (mdIsTemplate || rootIsTemplate) && // either md or root is a template
6328 ((classOrMdIsTemplate && !rootIsTemplate) || (!classOrMdIsTemplate && rootIsTemplate))
6331 // Method with template return type does not match method without return type
6332 // even if the parameters are the same. See also bug709052
6333 Debug::print(Debug::FindMembers,0,
6334 "5b. Comparing return types: template v.s. non-template\n");
6339 Debug::print(Debug::FindMembers,0,
6340 "6. match results of matchArguments2 = %d\n",matching);
6342 if (substDone) // found a new argument list
6344 if (matching) // replace member's argument list
6346 md->setDefinitionTemplateParameterLists(root->tArgLists);
6347 md->setArgumentList(argList); // new owner of the list => no delete
6351 if (!funcTempList.isEmpty() &&
6352 isSpecialization(declTemplArgs,*defTemplArgs))
6354 // check if we are dealing with a partial template
6355 // specialization. In this case we add it to the class
6356 // even though the member arguments do not match.
6358 // TODO: copy other aspects?
6359 root->protection=md->protection(); // copy protection level
6360 addMethodToClass(rootNav,cd,md->name(),isFriend);
6368 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
6373 else if (cd && cd!=tcd) // we did find a class with the same name as cd
6374 // but in a different namespace
6379 if (count==0 && rootNav->parent() &&
6380 rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6382 goto localObjCMethod;
6384 if (count==0 && !(isFriend && funcType=="class"))
6387 ClassDef *ecd = 0, *ucd = 0;
6388 MemberDef *emd = 0, *umd = 0;
6391 //printf("Assume template class\n");
6392 for (mni.toFirst();(md=mni.current());++mni)
6394 ClassDef *ccd=md->getClassDef();
6396 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
6397 if (ccd!=0 && rightScopeMatch(ccd->name(),className))
6399 ArgumentList *templAl = md->templateArguments();
6400 if (root->tArgLists && templAl!=0 &&
6401 root->tArgLists->getLast()->count()<=templAl->count())
6403 addMethodToClass(rootNav,ccd,md->name(),isFriend);
6406 if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
6407 { // exact argument list match -> remember
6410 Debug::print(Debug::FindMembers,0,
6411 "7. new candidate className=%s scope=%s args=%s exact match\n",
6412 qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6414 else // arguments do not match, but member name and scope do -> remember
6418 Debug::print(Debug::FindMembers,0,
6419 "7. new candidate className=%s scope=%s args=%s no match\n",
6420 qPrint(className),qPrint(ccd->name()),qPrint(md->argsString()));
6426 static bool strictProtoMatching = Config_getBool(STRICT_PROTO_MATCHING);
6427 if (!strictProtoMatching)
6429 if (candidates==1 && ucd && umd)
6431 // we didn't find an actual match on argument lists, but there is only 1 member with this
6432 // name in the same scope, so that has to be the one.
6433 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
6436 else if (candidates>1 && ecd && emd)
6438 // we didn't find a unique match using type resolution,
6439 // but one of the matches has the exact same signature so
6440 // we take that one.
6441 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
6446 QCString warnMsg = "no ";
6447 if (noMatchCount>1) warnMsg+="uniquely ";
6448 warnMsg+="matching class member found for \n";
6450 if (root->tArgLists)
6452 QListIterator<ArgumentList> alli(*root->tArgLists);
6454 for (;(al=alli.current());++alli)
6456 warnMsg+=" template ";
6457 warnMsg+=tempArgListToString(al,root->lang);
6461 QCString fullFuncDecl=funcDecl.copy();
6462 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6465 warnMsg+=fullFuncDecl;
6470 warnMsg+="Possible candidates:\n";
6471 for (mni.toFirst();(md=mni.current());++mni)
6473 ClassDef *cd=md->getClassDef();
6474 if (cd!=0 && rightScopeMatch(cd->name(),className))
6476 ArgumentList *templAl = md->templateArguments();
6479 warnMsg+=" 'template ";
6480 warnMsg+=tempArgListToString(templAl,root->lang);
6484 if (md->typeString())
6486 warnMsg+=md->typeString();
6489 QCString qScope = cd->qualifiedNameWithTemplateParameters();
6490 if (!qScope.isEmpty())
6491 warnMsg+=qScope+"::"+md->name();
6492 if (md->argsString())
6493 warnMsg+=md->argsString();
6496 warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
6497 " of file "+md->getDefFileName();
6504 warn_simple(root->fileName,root->startLine,warnMsg);
6507 else if (cd) // member specialization
6509 MemberNameIterator mni(*mn);
6510 MemberDef *declMd=0;
6512 for (mni.toFirst();(md=mni.current());++mni)
6514 if (md->getClassDef()==cd)
6516 // TODO: we should probably also check for matching arguments
6521 MemberType mtype=MemberType_Function;
6522 ArgumentList *tArgList = new ArgumentList;
6523 // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6525 root->fileName,root->startLine,root->startColumn,
6526 funcType,funcName,funcArgs,exceptions,
6527 declMd ? declMd->protection() : root->protection,
6528 root->virt,root->stat,Member,
6529 mtype,tArgList,root->argList,root->metaData);
6530 //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6531 md->setTagInfo(rootNav->tagInfo());
6532 md->setLanguage(root->lang);
6533 md->setId(root->id);
6534 md->setMemberClass(cd);
6535 md->setTemplateSpecialization(TRUE);
6536 md->setTypeConstraints(root->typeConstr);
6537 md->setDefinition(funcDecl);
6538 md->enableCallGraph(root->callGraph);
6539 md->enableCallerGraph(root->callerGraph);
6540 md->enableReferencedByRelation(root->referencedByRelation);
6541 md->enableReferencesRelation(root->referencesRelation);
6542 md->setDocumentation(root->doc,root->docFile,root->docLine);
6543 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6544 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6545 md->setDocsForDefinition(!root->proto);
6546 md->setPrototype(root->proto);
6547 md->addSectionsToDefinition(root->anchors);
6548 md->setBodySegment(root->bodyLine,root->endBodyLine);
6549 FileDef *fd=rootNav->fileDef();
6551 md->setMemberSpecifiers(root->spec);
6552 md->setMemberGroupId(root->mGrpId);
6554 cd->insertMember(md);
6555 md->setRefItems(root->sli);
6560 //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6561 // scopeName.data(),funcName.data(),funcArgs.data());
6564 else if (overloaded) // check if the function belongs to only one class
6566 // for unique overloaded member we allow the class to be
6567 // omitted, this is to be Qt compatible. Using this should
6568 // however be avoided, because it is error prone
6569 MemberNameIterator mni(*mn);
6570 MemberDef *md=mni.toFirst();
6572 ClassDef *cd=md->getClassDef();
6574 QCString className=cd->name().copy();
6577 for (;(md=mni.current());++mni)
6579 ClassDef *cd=md->getClassDef();
6580 if (className!=cd->name()) unique=FALSE;
6585 if (root->mtype==Signal) mtype=MemberType_Signal;
6586 else if (root->mtype==Slot) mtype=MemberType_Slot;
6587 else if (root->mtype==DCOP) mtype=MemberType_DCOP;
6588 else mtype=MemberType_Function;
6590 // new overloaded member function
6591 ArgumentList *tArgList =
6592 getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6593 //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6594 MemberDef *md=new MemberDef(
6595 root->fileName,root->startLine,root->startColumn,
6596 funcType,funcName,funcArgs,exceptions,
6597 root->protection,root->virt,root->stat,Related,
6598 mtype,tArgList,root->argList,root->metaData);
6599 md->setTagInfo(rootNav->tagInfo());
6600 md->setLanguage(root->lang);
6601 md->setId(root->id);
6602 md->setTypeConstraints(root->typeConstr);
6603 md->setMemberClass(cd);
6604 md->setDefinition(funcDecl);
6605 md->enableCallGraph(root->callGraph);
6606 md->enableCallerGraph(root->callerGraph);
6607 md->enableReferencedByRelation(root->referencedByRelation);
6608 md->enableReferencesRelation(root->referencesRelation);
6609 QCString doc=getOverloadDocs();
6612 md->setDocumentation(doc,root->docFile,root->docLine);
6613 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6614 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6615 md->setDocsForDefinition(!root->proto);
6616 md->setPrototype(root->proto);
6617 md->addSectionsToDefinition(root->anchors);
6618 md->setBodySegment(root->bodyLine,root->endBodyLine);
6619 FileDef *fd=rootNav->fileDef();
6621 md->setMemberSpecifiers(root->spec);
6622 md->setMemberGroupId(root->mGrpId);
6624 cd->insertMember(md);
6625 cd->insertUsedFile(fd);
6626 md->setRefItems(root->sli);
6629 else // unrelated function with the same name as a member
6631 if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6633 QCString fullFuncDecl=funcDecl.copy();
6634 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6635 warn(root->fileName,root->startLine,
6636 "Cannot determine class for function\n%s",
6642 else if (isRelated && !root->relates.isEmpty())
6644 Debug::print(Debug::FindMembers,0,"2. related function\n"
6645 " scopeName=%s className=%s\n",qPrint(scopeName),qPrint(className));
6646 if (className.isEmpty()) className=root->relates;
6648 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6649 if ((cd=getClass(scopeName)))
6651 bool newMember=TRUE; // assume we have a new member
6652 bool newMemberName=FALSE;
6653 MemberDef *mdDefine=0;
6654 bool isDefine=FALSE;
6656 MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6659 MemberNameIterator mni(*mn);
6660 mdDefine = mni.current();
6661 while (mdDefine && !isDefine)
6663 isDefine = isDefine || mdDefine->isDefine();
6664 if (!isDefine) { ++mni; mdDefine=mni.current(); }
6669 FileDef *fd=rootNav->fileDef();
6671 if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6673 mn=new MemberName(funcName);
6674 newMemberName=TRUE; // we create a new member name
6678 MemberNameIterator mni(*mn);
6680 while ((rmd=mni.current()) && newMember) // see if we got another member with matching arguments
6682 ArgumentList *rmdAl = rmd->argumentList();
6685 className!=rmd->getOuterScope()->name() ||
6686 !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6687 cd,fd,root->argList,
6689 if (newMember) ++mni;
6691 if (!newMember && rmd) // member already exists as rmd -> add docs
6693 //printf("addMemberDocs for related member %s\n",root->name.data());
6694 //rmd->setMemberDefTemplateArguments(root->mtArgList);
6695 addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6699 if (newMember) // need to create a new member
6703 mtype=MemberType_Define;
6704 else if (root->mtype==Signal)
6705 mtype=MemberType_Signal;
6706 else if (root->mtype==Slot)
6707 mtype=MemberType_Slot;
6708 else if (root->mtype==DCOP)
6709 mtype=MemberType_DCOP;
6711 mtype=MemberType_Function;
6713 if (isDefine && mdDefine)
6715 mdDefine->setHidden(TRUE);
6717 funcArgs=mdDefine->argsString();
6718 funcDecl=funcType + " " + funcName;
6721 //printf("New related name `%s' `%d'\n",funcName.data(),
6722 // root->argList ? (int)root->argList->count() : -1);
6724 // first note that we pass:
6725 // (root->tArgLists ? root->tArgLists->last() : 0)
6726 // for the template arguments fo the new "member."
6727 // this accurately reflects the template arguments of
6728 // the related function, which don't have to do with
6729 // those of the related class.
6730 MemberDef *md=new MemberDef(
6731 root->fileName,root->startLine,root->startColumn,
6732 funcType,funcName,funcArgs,exceptions,
6733 root->protection,root->virt,
6734 root->stat && !isMemberOf,
6735 isMemberOf ? Foreign : Related,
6737 (root->tArgLists ? root->tArgLists->getLast() : 0),
6738 funcArgs.isEmpty() ? 0 : root->argList,root->metaData);
6740 if (isDefine && mdDefine)
6742 md->setInitializer(mdDefine->initializer());
6746 // we still have the problem that
6747 // MemberDef::writeDocumentation() in memberdef.cpp
6748 // writes the template argument list for the class,
6749 // as if this member is a member of the class.
6750 // fortunately, MemberDef::writeDocumentation() has
6751 // a special mechanism that allows us to totally
6752 // override the set of template argument lists that
6753 // are printed. We use that and set it to the
6754 // template argument lists of the related function.
6756 md->setDefinitionTemplateParameterLists(root->tArgLists);
6758 md->setTagInfo(rootNav->tagInfo());
6762 //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6763 // funcName.data(),funcDecl.data(),root->bodyLine);
6765 // try to find the matching line number of the body from the
6766 // global function list
6768 if (root->bodyLine==-1)
6770 MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6773 MemberNameIterator rmni(*rmn);
6775 while ((rmd=rmni.current()) && !found) // see if we got another member with matching arguments
6777 ArgumentList *rmdAl = rmd->argumentList();
6778 // check for matching argument lists
6780 matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl,
6781 cd,fd,root->argList,
6789 if (rmd) // member found -> copy line number info
6791 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6792 md->setBodyDef(rmd->getBodyDef());
6793 //md->setBodyMember(rmd);
6797 if (!found) // line number could not be found or is available in this
6800 md->setBodySegment(root->bodyLine,root->endBodyLine);
6804 //if (root->mGrpId!=-1)
6806 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
6808 md->setMemberClass(cd);
6809 md->setMemberSpecifiers(root->spec);
6810 md->setDefinition(funcDecl);
6811 md->enableCallGraph(root->callGraph);
6812 md->enableCallerGraph(root->callerGraph);
6813 md->enableReferencedByRelation(root->referencedByRelation);
6814 md->enableReferencesRelation(root->referencesRelation);
6815 md->setDocumentation(root->doc,root->docFile,root->docLine);
6816 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6817 md->setDocsForDefinition(!root->proto);
6818 md->setPrototype(root->proto);
6819 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6820 md->addSectionsToDefinition(root->anchors);
6821 md->setMemberGroupId(root->mGrpId);
6822 md->setLanguage(root->lang);
6823 md->setId(root->id);
6824 //md->setMemberDefTemplateArguments(root->mtArgList);
6826 cd->insertMember(md);
6827 cd->insertUsedFile(fd);
6828 md->setRefItems(root->sli);
6829 if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6832 addMemberToGroups(root,md);
6834 //printf("Adding member=%s\n",md->name().data());
6837 //Doxygen::memberNameList.append(mn);
6838 //Doxygen::memberNameDict.insert(funcName,mn);
6839 Doxygen::memberNameSDict->append(funcName,mn);
6842 if (root->relatesType == Duplicate)
6844 if (!findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl))
6846 QCString fullFuncDecl=funcDecl.copy();
6847 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6848 warn(root->fileName,root->startLine,
6849 "Cannot determine file/namespace for relatedalso function\n%s",
6857 warn_undoc(root->fileName,root->startLine,
6858 "class `%s' for related function `%s' is not "
6860 className.data(),funcName.data()
6864 else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6868 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6869 if (Config_getBool(EXTRACT_LOCAL_METHODS) && (cd=getClass(scopeName)))
6871 Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6872 " scopeName=%s className=%s\n",qPrint(root->name),qPrint(scopeName),qPrint(className));
6873 //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6874 MemberDef *md=new MemberDef(
6875 root->fileName,root->startLine,root->startColumn,
6876 funcType,funcName,funcArgs,exceptions,
6877 root->protection,root->virt,root->stat,Member,
6878 MemberType_Function,0,root->argList,root->metaData);
6879 md->setTagInfo(rootNav->tagInfo());
6880 md->setLanguage(root->lang);
6881 md->setId(root->id);
6882 md->makeImplementationDetail();
6883 md->setMemberClass(cd);
6884 md->setDefinition(funcDecl);
6885 md->enableCallGraph(root->callGraph);
6886 md->enableCallerGraph(root->callerGraph);
6887 md->enableReferencedByRelation(root->referencedByRelation);
6888 md->enableReferencesRelation(root->referencesRelation);
6889 md->setDocumentation(root->doc,root->docFile,root->docLine);
6890 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6891 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6892 md->setDocsForDefinition(!root->proto);
6893 md->setPrototype(root->proto);
6894 md->addSectionsToDefinition(root->anchors);
6895 md->setBodySegment(root->bodyLine,root->endBodyLine);
6896 FileDef *fd=rootNav->fileDef();
6898 md->setMemberSpecifiers(root->spec);
6899 md->setMemberGroupId(root->mGrpId);
6900 cd->insertMember(md);
6901 cd->insertUsedFile(fd);
6902 md->setRefItems(root->sli);
6903 if ((mn=Doxygen::memberNameSDict->find(root->name)))
6909 mn = new MemberName(root->name);
6911 Doxygen::memberNameSDict->append(root->name,mn);
6916 // local objective C method found for class without interface
6919 else // unrelated not overloaded member found
6921 bool globMem = findGlobalMember(rootNav,namespaceName,funcType,funcName,funcTempList,funcArgs,funcDecl);
6922 if (className.isEmpty() && !globMem)
6924 warn(root->fileName,root->startLine,
6925 "class for member `%s' cannot "
6926 "be found.", funcName.data()
6929 else if (!className.isEmpty() && !globMem)
6931 warn(root->fileName,root->startLine,
6932 "member `%s' of class `%s' cannot be found",
6933 funcName.data(),className.data());
6939 // this should not be called
6940 warn(root->fileName,root->startLine,
6941 "member with no name found.");
6946 //----------------------------------------------------------------------
6947 // find the members corresponding to the different documentation blocks
6948 // that are extracted from the sources.
6950 static void filterMemberDocumentation(EntryNav *rootNav)
6952 Entry *root = rootNav->entry();
6954 Debug::print(Debug::FindMembers,0,
6955 "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%lld root->mGrpId=%d\n",
6956 qPrint(root->type),qPrint(root->inside),qPrint(root->name),qPrint(root->args),root->section,root->spec,root->mGrpId
6958 //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6961 if (root->relatesType == Duplicate && !root->relates.isEmpty())
6963 QCString tmp = root->relates;
6964 root->relates.resize(0);
6965 filterMemberDocumentation(rootNav);
6966 root->relates = tmp;
6969 if ( // detect func variable/typedef to func ptr
6970 (i=findFunctionPtr(root->type,root->lang,&l))!=-1
6973 //printf("Fixing function pointer!\n");
6974 // fix type and argument
6975 root->args.prepend(root->type.right(root->type.length()-i-l));
6976 root->type=root->type.left(i+l);
6977 //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6980 else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1))
6981 // detect function types marked as functions
6986 //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6987 if (root->section==Entry::MEMBERDOC_SEC)
6989 //printf("Documentation for inline member `%s' found args=`%s'\n",
6990 // root->name.data(),root->args.data());
6991 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6992 if (root->type.isEmpty())
6994 findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6998 findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
7001 else if (root->section==Entry::OVERLOADDOC_SEC)
7003 //printf("Overloaded member %s found\n",root->name.data());
7004 findMember(rootNav,root->name,TRUE,isFunc);
7007 ((root->section==Entry::FUNCTION_SEC // function
7009 (root->section==Entry::VARIABLE_SEC && // variable
7010 !root->type.isEmpty() && // with a type
7011 g_compoundKeywordDict.find(root->type)==0 // that is not a keyword
7012 // (to skip forward declaration of class etc.)
7017 //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
7018 // root->name.data(),root->args.data(),root->exception.data());
7019 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
7020 //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
7021 if (root->type=="friend class" || root->type=="friend struct" ||
7022 root->type=="friend union")
7030 else if (!root->type.isEmpty())
7050 else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
7052 findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
7054 else if (root->section==Entry::VARIABLEDOC_SEC)
7056 //printf("Documentation for variable %s found\n",root->name.data());
7057 //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data());
7058 findMember(rootNav,root->name,FALSE,FALSE);
7060 else if (root->section==Entry::EXPORTED_INTERFACE_SEC ||
7061 root->section==Entry::INCLUDED_SERVICE_SEC)
7063 findMember(rootNav,root->type + " " + root->name,FALSE,FALSE);
7068 //printf("skip section\n");
7072 static void findMemberDocumentation(EntryNav *rootNav)
7074 if (rootNav->section()==Entry::MEMBERDOC_SEC ||
7075 rootNav->section()==Entry::OVERLOADDOC_SEC ||
7076 rootNav->section()==Entry::FUNCTION_SEC ||
7077 rootNav->section()==Entry::VARIABLE_SEC ||
7078 rootNav->section()==Entry::VARIABLEDOC_SEC ||
7079 rootNav->section()==Entry::DEFINE_SEC ||
7080 rootNav->section()==Entry::INCLUDED_SERVICE_SEC ||
7081 rootNav->section()==Entry::EXPORTED_INTERFACE_SEC
7084 rootNav->loadEntry(g_storage);
7086 filterMemberDocumentation(rootNav);
7088 rootNav->releaseEntry();
7090 if (rootNav->children())
7092 EntryNavListIterator eli(*rootNav->children());
7094 for (;(e=eli.current());++eli)
7096 if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
7101 //----------------------------------------------------------------------
7103 static void findObjCMethodDefinitions(EntryNav *rootNav)
7105 if (rootNav->children())
7107 EntryNavListIterator eli(*rootNav->children());
7108 EntryNav *objCImplNav;
7109 for (;(objCImplNav=eli.current());++eli)
7111 if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
7113 EntryNavListIterator seli(*objCImplNav->children());
7114 EntryNav *objCMethodNav;
7115 for (;(objCMethodNav=seli.current());++seli)
7117 if (objCMethodNav->section()==Entry::FUNCTION_SEC)
7119 objCMethodNav->loadEntry(g_storage);
7120 Entry *objCMethod = objCMethodNav->entry();
7122 //Printf(" Found ObjC method definition %s\n",objCMethod->name.data());
7123 findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
7124 objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
7125 objCMethod->section=Entry::EMPTY_SEC;
7127 objCMethodNav->releaseEntry();
7135 //----------------------------------------------------------------------
7136 // find and add the enumeration to their classes, namespaces or files
7138 static void findEnums(EntryNav *rootNav)
7140 if (rootNav->section()==Entry::ENUM_SEC)
7142 rootNav->loadEntry(g_storage);
7143 Entry *root = rootNav->entry();
7149 MemberNameSDict *mnsd=0;
7151 bool isRelated=FALSE;
7152 bool isMemberOf=FALSE;
7153 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7159 if ((i=root->name.findRev("::"))!=-1) // scope is specified
7161 scope=root->name.left(i); // extract scope
7162 name=root->name.right(root->name.length()-i-2); // extract name
7163 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7165 else // no scope, check the scope in which the docs where found
7167 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7168 && !rootNav->parent()->name().isEmpty()
7169 ) // found enum docs inside a compound
7171 scope=rootNav->parent()->name();
7172 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7177 if (!root->relates.isEmpty())
7178 { // related member, prefix user specified scope
7180 isMemberOf=(root->relatesType == MemberOf);
7181 if (getClass(root->relates)==0 && !scope.isEmpty())
7182 scope=mergeScopes(scope,root->relates);
7184 scope=root->relates.copy();
7185 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7188 if (cd && !name.isEmpty()) // found a enum inside a compound
7190 //printf("Enum `%s'::`%s'\n",cd->name().data(),name.data());
7192 mnsd=Doxygen::memberNameSDict;
7195 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7197 mnsd=Doxygen::functionNameSDict;
7200 else // found a global enum
7202 fd=rootNav->fileDef();
7203 mnsd=Doxygen::functionNameSDict;
7207 if (!name.isEmpty())
7211 root->fileName,root->startLine,root->startColumn,
7213 root->protection,Normal,FALSE,
7214 isMemberOf ? Foreign : isRelated ? Related : Member,
7215 MemberType_Enumeration,
7216 0,0,root->metaData);
7217 md->setTagInfo(rootNav->tagInfo());
7218 md->setLanguage(root->lang);
7219 md->setId(root->id);
7220 if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
7221 md->setBodySegment(root->bodyLine,root->endBodyLine);
7222 md->setBodyDef(rootNav->fileDef());
7223 md->setMemberSpecifiers(root->spec);
7224 md->setEnumBaseType(root->args);
7225 //printf("Enum %s definition at line %d of %s: protection=%d scope=%s\n",
7226 // root->name.data(),root->bodyLine,root->fileName.data(),root->protection,cd?cd->name().data():"<none>");
7227 md->addSectionsToDefinition(root->anchors);
7228 md->setMemberGroupId(root->mGrpId);
7229 md->enableCallGraph(root->callGraph);
7230 md->enableCallerGraph(root->callerGraph);
7231 md->enableReferencedByRelation(root->referencedByRelation);
7232 md->enableReferencesRelation(root->referencesRelation);
7233 //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
7234 md->setRefItems(root->sli);
7235 //printf("found enum %s nd=%p\n",md->name().data(),nd);
7238 QCString baseType = root->args;
7239 if (!baseType.isEmpty())
7241 baseType.prepend(" : ");
7244 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7246 if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7248 md->setDefinition(name+baseType);
7252 md->setDefinition(nd->name()+"::"+name+baseType);
7254 //printf("definition=%s\n",md->definition());
7256 md->setNamespace(nd);
7257 nd->insertMember(md);
7260 // even if we have already added the enum to a namespace, we still
7261 // also want to add it to other appropriate places such as file
7265 if (!defSet) md->setDefinition(name+baseType);
7266 if (fd==0 && rootNav->parent())
7268 fd=rootNav->parent()->fileDef();
7273 fd->insertMember(md);
7278 if (isRelated || Config_getBool(HIDE_SCOPE_NAMES))
7280 md->setDefinition(name+baseType);
7284 md->setDefinition(cd->name()+"::"+name+baseType);
7286 cd->insertMember(md);
7287 cd->insertUsedFile(fd);
7289 md->setDocumentation(root->doc,root->docFile,root->docLine);
7290 md->setDocsForDefinition(!root->proto);
7291 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7292 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7294 //printf("Adding member=%s\n",md->name().data());
7296 if ((mn=(*mnsd)[name]))
7298 // this is used if the same enum is in multiple namespaces/classes
7301 else // new enum name
7303 mn = new MemberName(name);
7305 mnsd->append(name,mn);
7306 //printf("add %s to new memberName. Now %d members\n",
7307 // name.data(),mn->count());
7309 addMemberToGroups(root,md);
7311 rootNav->releaseEntry();
7315 RECURSE_ENTRYTREE(findEnums,rootNav);
7319 //----------------------------------------------------------------------
7321 static void addEnumValuesToEnums(EntryNav *rootNav)
7323 if (rootNav->section()==Entry::ENUM_SEC)
7324 // non anonymous enumeration
7326 rootNav->loadEntry(g_storage);
7327 Entry *root = rootNav->entry();
7332 MemberNameSDict *mnsd=0;
7334 bool isRelated=FALSE;
7335 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
7341 if ((i=root->name.findRev("::"))!=-1) // scope is specified
7343 scope=root->name.left(i); // extract scope
7344 name=root->name.right(root->name.length()-i-2); // extract name
7345 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7347 else // no scope, check the scope in which the docs where found
7349 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7350 && !rootNav->parent()->name().isEmpty()
7351 ) // found enum docs inside a compound
7353 scope=rootNav->parent()->name();
7354 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7359 if (!root->relates.isEmpty())
7360 { // related member, prefix user specified scope
7362 if (getClass(root->relates)==0 && !scope.isEmpty())
7363 scope=mergeScopes(scope,root->relates);
7365 scope=root->relates.copy();
7366 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
7369 if (cd && !name.isEmpty()) // found a enum inside a compound
7371 //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
7373 mnsd=Doxygen::memberNameSDict;
7376 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
7378 //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
7379 mnsd=Doxygen::functionNameSDict;
7382 else // found a global enum
7384 fd=rootNav->fileDef();
7385 //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
7386 mnsd=Doxygen::functionNameSDict;
7390 if (!name.isEmpty())
7392 //printf("** name=%s\n",name.data());
7393 MemberName *mn = mnsd->find(name); // for all members with this name
7396 MemberNameIterator mni(*mn);
7398 for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list
7400 if (md->isEnumerate() && rootNav->children())
7402 //printf(" enum with %d children\n",rootNav->children()->count());
7403 EntryNavListIterator eli(*rootNav->children()); // for each enum value
7405 for (;(e=eli.current());++eli)
7409 (sle=rootNav->lang())==SrcLangExt_CSharp ||
7410 sle==SrcLangExt_Java ||
7411 sle==SrcLangExt_XML ||
7412 (root->spec&Entry::Strong)
7415 // Unlike classic C/C++ enums, for C++11, C# & Java enum
7416 // values are only visible inside the enum scope, so we must create
7417 // them here and only add them to the enum
7418 e->loadEntry(g_storage);
7419 Entry *root = e->entry();
7420 //printf("md->qualifiedName()=%s rootNav->name()=%s tagInfo=%p name=%s\n",
7421 // md->qualifiedName().data(),rootNav->name().data(),rootNav->tagInfo(),root->name.data());
7422 QCString qualifiedName = substitute(rootNav->name(),"::",".");
7423 if (!scope.isEmpty() && rootNav->tagInfo())
7425 qualifiedName=substitute(scope,"::",".")+"."+qualifiedName;
7427 if (substitute(md->qualifiedName(),"::",".")== // TODO: add function to get canonical representation
7428 qualifiedName // enum value scope matches that of the enum
7431 QCString fileName = root->fileName;
7432 if (fileName.isEmpty() && rootNav->tagInfo())
7434 fileName = rootNav->tagInfo()->tagName;
7436 MemberDef *fmd=new MemberDef(
7437 fileName,root->startLine,root->startColumn,
7438 root->type,root->name,root->args,0,
7439 root->protection, Normal,root->stat,Member,
7440 MemberType_EnumValue,0,0,root->metaData);
7441 if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
7442 else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
7443 else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
7444 fmd->setOuterScope(md->getOuterScope());
7445 fmd->setTagInfo(e->tagInfo());
7446 fmd->setLanguage(root->lang);
7447 fmd->setId(root->id);
7448 fmd->setDocumentation(root->doc,root->docFile,root->docLine);
7449 fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7450 fmd->addSectionsToDefinition(root->anchors);
7451 fmd->setInitializer(root->initializer);
7452 fmd->setMaxInitLines(root->initLines);
7453 fmd->setMemberGroupId(root->mGrpId);
7454 fmd->setExplicitExternal(root->explicitExternal);
7455 fmd->setRefItems(root->sli);
7457 md->insertEnumField(fmd);
7458 fmd->setEnumScope(md,TRUE);
7459 MemberName *mn=mnsd->find(root->name);
7466 mn = new MemberName(root->name);
7468 mnsd->append(root->name,mn);
7475 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
7477 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
7478 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
7479 // get list of members with the same name as the field
7481 MemberNameIterator fmni(*fmn);
7483 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
7485 if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
7487 //printf("found enum value with same name %s in scope %s\n",
7488 // fmd->name().data(),fmd->getOuterScope()->name().data());
7489 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7491 NamespaceDef *fnd=fmd->getNamespaceDef();
7492 if (fnd==nd) // enum value is inside a namespace
7494 md->insertEnumField(fmd);
7495 fmd->setEnumScope(md);
7500 FileDef *ffd=fmd->getFileDef();
7501 if (ffd==fd) // enum value has file scope
7503 md->insertEnumField(fmd);
7504 fmd->setEnumScope(md);
7507 else if (isRelated && cd) // reparent enum value to
7508 // match the enum's scope
7510 md->insertEnumField(fmd); // add field def to list
7511 fmd->setEnumScope(md); // cross ref with enum name
7512 fmd->setEnumClassScope(cd); // cross ref with enum name
7513 fmd->setOuterScope(cd);
7515 cd->insertMember(fmd);
7519 ClassDef *fcd=fmd->getClassDef();
7520 if (fcd==cd) // enum value is inside a class
7522 //printf("Inserting enum field %s in enum scope %s\n",
7523 // fmd->name().data(),md->name().data());
7524 md->insertEnumField(fmd); // add field def to list
7525 fmd->setEnumScope(md); // cross ref with enum name
7538 rootNav->releaseEntry();
7542 RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7547 //----------------------------------------------------------------------
7548 // find the documentation blocks for the enumerations
7550 static void findEnumDocumentation(EntryNav *rootNav)
7552 if (rootNav->section()==Entry::ENUMDOC_SEC
7553 && !rootNav->name().isEmpty()
7554 && rootNav->name().at(0)!='@' // skip anonymous enums
7557 rootNav->loadEntry(g_storage);
7558 Entry *root = rootNav->entry();
7560 //printf("Found docs for enum with name `%s' in context %s\n",
7561 // root->name.data(),root->parent->name.data());
7565 if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7567 name=root->name.right(root->name.length()-i-2); // extract name
7568 scope=root->name.left(i); // extract scope
7569 //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7571 else // just the name
7575 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7576 && !rootNav->parent()->name().isEmpty()
7577 ) // found enum docs inside a compound
7579 if (!scope.isEmpty()) scope.prepend("::");
7580 scope.prepend(rootNav->parent()->name());
7582 ClassDef *cd=getClass(scope);
7584 if (!name.isEmpty())
7589 //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7590 QCString className=cd->name().copy();
7591 MemberName *mn=Doxygen::memberNameSDict->find(name);
7594 MemberNameIterator mni(*mn);
7596 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7598 ClassDef *cd=md->getClassDef();
7599 if (cd && cd->name()==className && md->isEnumerate())
7601 // documentation outside a compound overrides the documentation inside it
7603 if (!md->documentation() || rootNav->parent()->name().isEmpty())
7606 md->setDocumentation(root->doc,root->docFile,root->docLine);
7607 md->setDocsForDefinition(!root->proto);
7610 // brief descriptions inside a compound override the documentation
7613 if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7616 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7619 if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7621 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7624 if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7626 md->setMemberGroupId(root->mGrpId);
7629 md->addSectionsToDefinition(root->anchors);
7630 md->setRefItems(root->sli);
7632 GroupDef *gd=md->getGroupDef();
7633 if (gd==0 &&root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7635 addMemberToGroups(root,md);
7644 //printf("MemberName %s not found!\n",name.data());
7647 else // enum outside class
7649 //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7650 MemberName *mn=Doxygen::functionNameSDict->find(name);
7653 MemberNameIterator mni(*mn);
7655 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7657 if (md->isEnumerate())
7659 md->setDocumentation(root->doc,root->docFile,root->docLine);
7660 md->setDocsForDefinition(!root->proto);
7661 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7662 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7663 md->addSectionsToDefinition(root->anchors);
7664 md->setMemberGroupId(root->mGrpId);
7666 GroupDef *gd=md->getGroupDef();
7667 if (gd==0 && root->groups->getFirst()!=0) // member not grouped but out-of-line documentation is
7669 addMemberToGroups(root,md);
7679 warn(root->fileName,root->startLine,
7680 "Documentation for undefined enum `%s' found.",
7686 rootNav->releaseEntry();
7688 RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7691 // search for each enum (member or function) in mnl if it has documented
7693 static void findDEV(const MemberNameSDict &mnsd)
7696 MemberNameSDict::Iterator mnli(mnsd);
7697 // for each member name
7698 for (mnli.toFirst();(mn=mnli.current());++mnli)
7701 MemberNameIterator mni(*mn);
7702 // for each member definition
7703 for (mni.toFirst();(md=mni.current());++mni)
7705 if (md->isEnumerate()) // member is an enum
7707 MemberList *fmdl = md->enumFieldList();
7708 int documentedEnumValues=0;
7709 if (fmdl) // enum has values
7711 MemberListIterator fmni(*fmdl);
7713 // for each enum value
7714 for (fmni.toFirst();(fmd=fmni.current());++fmni)
7716 if (fmd->isLinkableInProject()) documentedEnumValues++;
7719 // at least one enum value is documented
7720 if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7726 // search for each enum (member or function) if it has documented enum
7728 static void findDocumentedEnumValues()
7730 findDEV(*Doxygen::memberNameSDict);
7731 findDEV(*Doxygen::functionNameSDict);
7734 //----------------------------------------------------------------------
7736 static void addMembersToIndex()
7739 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7740 // for each member name
7741 for (mnli.toFirst();(mn=mnli.current());++mnli)
7744 MemberNameIterator mni(*mn);
7745 // for each member definition
7746 for (mni.toFirst();(md=mni.current());++mni)
7748 addClassMemberNameToIndex(md);
7751 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7752 // for each member name
7753 for (fnli.toFirst();(mn=fnli.current());++fnli)
7756 MemberNameIterator mni(*mn);
7757 // for each member definition
7758 for (mni.toFirst();(md=mni.current());++mni)
7760 if (md->getNamespaceDef())
7762 addNamespaceMemberNameToIndex(md);
7766 addFileMemberNameToIndex(md);
7772 //----------------------------------------------------------------------
7773 // computes the relation between all members. For each member `m'
7774 // the members that override the implementation of `m' are searched and
7775 // the member that `m' overrides is searched.
7777 static void computeMemberRelations()
7779 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7781 for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7783 MemberNameIterator mdi(*mn);
7784 MemberNameIterator bmdi(*mn);
7787 for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7789 for ( bmdi.toFirst() ; (bmd=bmdi.current()); ++bmdi ) // for each other member with the same name
7791 ClassDef *mcd = md->getClassDef();
7792 if (mcd && mcd->baseClasses())
7794 ClassDef *bmcd = bmd->getClassDef();
7795 //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7796 // mcd->name().data(),md->name().data(),md,
7797 // bmcd->name().data(),bmd->name().data(),bmd
7799 if (md!=bmd && bmcd && mcd && bmcd!=mcd &&
7800 (bmd->virtualness()!=Normal || bmd->getLanguage()==SrcLangExt_Python ||
7801 bmcd->compoundType()==ClassDef::Interface ||
7802 bmcd->compoundType()==ClassDef::Protocol
7805 mcd->isLinkable() &&
7806 bmcd->isLinkable() &&
7807 mcd->isBaseClass(bmcd,TRUE))
7809 //printf(" derived scope\n");
7810 ArgumentList *bmdAl = bmd->argumentList();
7811 ArgumentList *mdAl = md->argumentList();
7812 //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7813 // argListToString(bmdAl.pointer()).data(),
7814 // argListToString(mdAl.pointer()).data()
7817 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl,
7818 md->getOuterScope(), md->getFileDef(), mdAl,
7824 if ((rmd=md->reimplements())==0 ||
7825 minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7828 //printf("setting (new) reimplements member\n");
7829 md->setReimplements(bmd);
7831 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7832 bmd->insertReimplementedBy(md);
7842 //----------------------------------------------------------------------------
7843 //static void computeClassImplUsageRelations()
7846 // ClassSDict::Iterator cli(*Doxygen::classSDict);
7847 // for (;(cd=cli.current());++cli)
7849 // cd->determineImplUsageRelation();
7853 //----------------------------------------------------------------------------
7855 static void createTemplateInstanceMembers()
7857 ClassSDict::Iterator cli(*Doxygen::classSDict);
7860 for (cli.toFirst();(cd=cli.current());++cli)
7862 // that is a template
7863 QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7866 QDictIterator<ClassDef> qdi(*templInstances);
7868 // for each instance of the template
7869 for (qdi.toFirst();(tcd=qdi.current());++qdi)
7871 tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7877 //----------------------------------------------------------------------------
7879 static void mergeCategories()
7882 ClassSDict::Iterator cli(*Doxygen::classSDict);
7883 // merge members of categories into the class they extend
7884 for (cli.toFirst();(cd=cli.current());++cli)
7886 int i=cd->name().find('(');
7887 if (i!=-1) // it is an Objective-C category
7889 QCString baseName=cd->name().left(i);
7890 ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7893 //printf("*** merging members of category %s into %s\n",
7894 // cd->name().data(),baseClass->name().data());
7895 baseClass->mergeCategory(cd);
7901 // builds the list of all members for each class
7903 static void buildCompleteMemberLists()
7906 ClassSDict::Iterator cli(*Doxygen::classSDict);
7907 // merge the member list of base classes into the inherited classes.
7908 for (cli.toFirst();(cd=cli.current());++cli)
7910 if (// !cd->isReference() && // not an external class
7911 cd->subClasses()==0 && // is a root of the hierarchy
7912 cd->baseClasses()) // and has at least one base class
7914 //printf("*** merging members for %s\n",cd->name().data());
7918 // now sort the member list of all classes.
7919 for (cli.toFirst();(cd=cli.current());++cli)
7921 if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7925 //----------------------------------------------------------------------------
7927 static void generateFileSources()
7929 if (Doxygen::inputNameList->count()>0)
7932 static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
7933 if (clangAssistedParsing)
7935 QDict<void> g_processedFiles(10007);
7937 // create a dictionary with files to process
7938 QDict<void> g_filesToProcess(10007);
7939 FileNameListIterator fnli(*Doxygen::inputNameList);
7941 for (fnli.toFirst();(fn=fnli.current());++fnli)
7943 FileNameIterator fni(*fn);
7945 for (;(fd=fni.current());++fni)
7947 g_filesToProcess.insert(fd->absFilePath(),(void*)0x8);
7950 // process source files (and their include dependencies)
7951 for (fnli.toFirst();(fn=fnli.current());++fnli)
7953 FileNameIterator fni(*fn);
7955 for (;(fd=fni.current());++fni)
7957 if (fd->isSource() && !fd->isReference())
7959 QStrList filesInSameTu;
7960 fd->getAllIncludeFilesRecursively(filesInSameTu);
7962 if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7964 msg("Generating code for file %s...\n",fd->docName().data());
7965 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
7968 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7969 // we needed to parse the sources even if we do not show them
7971 msg("Parsing code for file %s...\n",fd->docName().data());
7972 fd->parseSource(FALSE,filesInSameTu);
7975 char *incFile = filesInSameTu.first();
7976 while (incFile && g_filesToProcess.find(incFile))
7978 if (fd->absFilePath()!=incFile && !g_processedFiles.find(incFile))
7982 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
7983 if (ifd && !ifd->isReference())
7985 if (ifd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
7987 msg(" Generating code for file %s...\n",ifd->docName().data());
7988 ifd->writeSource(*g_outputList,TRUE,moreFiles);
7991 else if (!ifd->isReference() && Doxygen::parseSourcesNeeded)
7992 // we needed to parse the sources even if we do not show them
7994 msg(" Parsing code for file %s...\n",ifd->docName().data());
7995 ifd->parseSource(TRUE,moreFiles);
7997 g_processedFiles.insert(incFile,(void*)0x8);
8000 incFile = filesInSameTu.next();
8002 fd->finishParsing();
8003 g_processedFiles.insert(fd->absFilePath(),(void*)0x8);
8007 // process remaining files
8008 for (fnli.toFirst();(fn=fnli.current());++fnli)
8010 FileNameIterator fni(*fn);
8012 for (;(fd=fni.current());++fni)
8014 if (!g_processedFiles.find(fd->absFilePath())) // not yet processed
8016 QStrList filesInSameTu;
8018 if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
8020 msg("Generating code for file %s...\n",fd->docName().data());
8021 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
8024 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
8025 // we needed to parse the sources even if we do not show them
8027 msg("Parsing code for file %s...\n",fd->docName().data());
8028 fd->parseSource(FALSE,filesInSameTu);
8030 fd->finishParsing();
8038 FileNameListIterator fnli(*Doxygen::inputNameList);
8040 for (;(fn=fnli.current());++fnli)
8042 FileNameIterator fni(*fn);
8044 for (;(fd=fni.current());++fni)
8046 QStrList filesInSameTu;
8048 if (fd->generateSourceFile() && !g_useOutputTemplate) // sources need to be shown in the output
8050 msg("Generating code for file %s...\n",fd->docName().data());
8051 fd->writeSource(*g_outputList,FALSE,filesInSameTu);
8054 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
8055 // we needed to parse the sources even if we do not show them
8057 msg("Parsing code for file %s...\n",fd->docName().data());
8058 fd->parseSource(FALSE,filesInSameTu);
8060 fd->finishParsing();
8067 //----------------------------------------------------------------------------
8069 static void generateFileDocs()
8071 if (documentedHtmlFiles==0) return;
8073 if (Doxygen::inputNameList->count()>0)
8075 FileNameListIterator fnli(*Doxygen::inputNameList);
8077 for (fnli.toFirst();(fn=fnli.current());++fnli)
8079 FileNameIterator fni(*fn);
8081 for (fni.toFirst();(fd=fni.current());++fni)
8083 bool doc = fd->isLinkableInProject();
8086 msg("Generating docs for file %s...\n",fd->docName().data());
8087 fd->writeDocumentation(*g_outputList);
8094 //----------------------------------------------------------------------------
8096 static void addSourceReferences()
8098 // add source references for class definitions
8099 ClassSDict::Iterator cli(*Doxygen::classSDict);
8101 for (cli.toFirst();(cd=cli.current());++cli)
8103 FileDef *fd=cd->getBodyDef();
8104 if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
8106 fd->addSourceRef(cd->getStartBodyLine(),cd,0);
8109 // add source references for namespace definitions
8110 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8112 for (nli.toFirst();(nd=nli.current());++nli)
8114 FileDef *fd=nd->getBodyDef();
8115 if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
8117 fd->addSourceRef(nd->getStartBodyLine(),nd,0);
8121 // add source references for member names
8122 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8124 for (mnli.toFirst();(mn=mnli.current());++mnli)
8126 MemberNameIterator mni(*mn);
8128 for (mni.toFirst();(md=mni.current());++mni)
8130 //printf("class member %s: def=%s body=%d link?=%d\n",
8131 // md->name().data(),
8132 // md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
8133 // md->getStartBodyLine(),md->isLinkableInProject());
8134 FileDef *fd=md->getBodyDef();
8136 md->getStartBodyLine()!=-1 &&
8137 md->isLinkableInProject() &&
8138 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
8141 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8142 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8143 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8147 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8148 for (fnli.toFirst();(mn=fnli.current());++fnli)
8150 MemberNameIterator mni(*mn);
8152 for (mni.toFirst();(md=mni.current());++mni)
8154 FileDef *fd=md->getBodyDef();
8155 //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
8156 // md->name().data(),
8157 // md->getStartBodyLine(),md->getEndBodyLine(),fd,
8158 // md->isLinkableInProject(),
8159 // Doxygen::parseSourcesNeeded);
8161 md->getStartBodyLine()!=-1 &&
8162 md->isLinkableInProject() &&
8163 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
8166 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
8167 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
8168 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
8174 //----------------------------------------------------------------------------
8176 static void sortMemberLists()
8178 // sort class member lists
8179 ClassSDict::Iterator cli(*Doxygen::classSDict);
8181 for (cli.toFirst();(cd=cli.current());++cli)
8183 cd->sortMemberLists();
8186 // sort namespace member lists
8187 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8189 for (nli.toFirst();(nd=nli.current());++nli)
8191 nd->sortMemberLists();
8194 // sort file member lists
8195 FileNameListIterator fnli(*Doxygen::inputNameList);
8197 for (;(fn=fnli.current());++fnli)
8199 FileNameIterator fni(*fn);
8201 for (;(fd=fni.current());++fni)
8203 fd->sortMemberLists();
8207 // sort group member lists
8208 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8210 for (gli.toFirst();(gd=gli.current());++gli)
8212 gd->sortMemberLists();
8216 //----------------------------------------------------------------------------
8217 // generate the documentation of all classes
8219 static void generateClassList(ClassSDict &classSDict)
8221 ClassSDict::Iterator cli(classSDict);
8222 for ( ; cli.current() ; ++cli )
8224 ClassDef *cd=cli.current();
8226 //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
8228 (cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
8229 cd->getOuterScope()==Doxygen::globalScope // only look at global classes
8230 ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8233 // skip external references, anonymous compounds and
8234 // template instances
8235 if ( cd->isLinkableInProject() && cd->templateMaster()==0)
8237 msg("Generating docs for compound %s...\n",cd->name().data());
8239 cd->writeDocumentation(*g_outputList);
8240 cd->writeMemberList(*g_outputList);
8242 // even for undocumented classes, the inner classes can be documented.
8243 cd->writeDocumentationForInnerClasses(*g_outputList);
8248 static void generateClassDocs()
8250 generateClassList(*Doxygen::classSDict);
8251 generateClassList(*Doxygen::hiddenClasses);
8254 //----------------------------------------------------------------------------
8256 static void inheritDocumentation()
8258 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8261 for (;(mn=mnli.current());++mnli)
8263 MemberNameIterator mni(*mn);
8265 for (;(md=mni.current());++mni)
8267 //printf("%04d Member `%s'\n",count++,md->name().data());
8268 if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
8269 { // no documentation yet
8270 MemberDef *bmd = md->reimplements();
8271 while (bmd && bmd->documentation().isEmpty() &&
8272 bmd->briefDescription().isEmpty()
8274 { // search up the inheritance tree for a documentation member
8275 //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
8276 bmd = bmd->reimplements();
8278 if (bmd) // copy the documentation from the reimplemented member
8280 md->setInheritsDocsFrom(bmd);
8281 md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
8282 md->setDocsForDefinition(bmd->isDocsForDefinition());
8283 md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
8284 md->copyArgumentNames(bmd);
8285 md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
8292 //----------------------------------------------------------------------------
8294 static void combineUsingRelations()
8297 FileNameListIterator fnli(*Doxygen::inputNameList);
8299 for (fnli.toFirst();(fn=fnli.current());++fnli)
8301 FileNameIterator fni(*fn);
8303 for (fni.toFirst();(fd=fni.current());++fni)
8308 for (fnli.toFirst();(fn=fnli.current());++fnli)
8310 FileNameIterator fni(*fn);
8312 for (fni.toFirst();(fd=fni.current());++fni)
8314 fd->combineUsingRelations();
8318 // for each namespace
8319 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8321 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8325 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
8327 nd->combineUsingRelations();
8331 //----------------------------------------------------------------------------
8333 static void addMembersToMemberGroup()
8336 ClassSDict::Iterator cli(*Doxygen::classSDict);
8338 for ( ; (cd=cli.current()) ; ++cli )
8340 cd->addMembersToMemberGroup();
8343 FileNameListIterator fnli(*Doxygen::inputNameList);
8345 for (fnli.toFirst();(fn=fnli.current());++fnli)
8347 FileNameIterator fni(*fn);
8349 for (fni.toFirst();(fd=fni.current());++fni)
8351 fd->addMembersToMemberGroup();
8354 // for each namespace
8355 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8357 for ( ; (nd=nli.current()) ; ++nli )
8359 nd->addMembersToMemberGroup();
8362 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8364 for (gli.toFirst();(gd=gli.current());++gli)
8366 gd->addMembersToMemberGroup();
8370 //----------------------------------------------------------------------------
8372 static void distributeMemberGroupDocumentation()
8375 ClassSDict::Iterator cli(*Doxygen::classSDict);
8377 for ( ; (cd=cli.current()) ; ++cli )
8379 cd->distributeMemberGroupDocumentation();
8382 FileNameListIterator fnli(*Doxygen::inputNameList);
8384 for (fnli.toFirst();(fn=fnli.current());++fnli)
8386 FileNameIterator fni(*fn);
8388 for (fni.toFirst();(fd=fni.current());++fni)
8390 fd->distributeMemberGroupDocumentation();
8393 // for each namespace
8394 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8396 for ( ; (nd=nli.current()) ; ++nli )
8398 nd->distributeMemberGroupDocumentation();
8401 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8403 for (gli.toFirst();(gd=gli.current());++gli)
8405 gd->distributeMemberGroupDocumentation();
8409 //----------------------------------------------------------------------------
8411 static void findSectionsInDocumentation()
8414 ClassSDict::Iterator cli(*Doxygen::classSDict);
8416 for ( ; (cd=cli.current()) ; ++cli )
8418 cd->findSectionsInDocumentation();
8421 FileNameListIterator fnli(*Doxygen::inputNameList);
8423 for (fnli.toFirst();(fn=fnli.current());++fnli)
8425 FileNameIterator fni(*fn);
8427 for (fni.toFirst();(fd=fni.current());++fni)
8429 fd->findSectionsInDocumentation();
8432 // for each namespace
8433 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8435 for ( ; (nd=nli.current()) ; ++nli )
8437 nd->findSectionsInDocumentation();
8440 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8442 for (gli.toFirst();(gd=gli.current());++gli)
8444 gd->findSectionsInDocumentation();
8447 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8449 for (pdi.toFirst();(pd=pdi.current());++pdi)
8451 pd->findSectionsInDocumentation();
8453 if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
8456 static void flushCachedTemplateRelations()
8458 // remove all references to classes from the cache
8459 // as there can be new template instances in the inheritance path
8460 // to this class. Optimization: only remove those classes that
8461 // have inheritance instances as direct or indirect sub classes.
8462 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8464 for (ci.toFirst();(li=ci.current());++ci)
8468 Doxygen::lookupCache->remove(ci.currentKey());
8471 // remove all cached typedef resolutions whose target is a
8472 // template class as this may now be a template instance
8473 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8475 for (;(fn=fnli.current());++fnli) // for each global function name
8477 MemberNameIterator fni(*fn);
8479 for (;(fmd=fni.current());++fni) // for each function with that name
8481 if (fmd->isTypedefValCached())
8483 ClassDef *cd = fmd->getCachedTypedefVal();
8484 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8488 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8489 for (;(fn=mnli.current());++mnli) // for each class method name
8491 MemberNameIterator mni(*fn);
8493 for (;(fmd=mni.current());++mni) // for each function with that name
8495 if (fmd->isTypedefValCached())
8497 ClassDef *cd = fmd->getCachedTypedefVal();
8498 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
8504 //----------------------------------------------------------------------------
8506 static void flushUnresolvedRelations()
8508 // Remove all unresolved references to classes from the cache.
8509 // This is needed before resolving the inheritance relations, since
8510 // it would otherwise not find the inheritance relation
8511 // for C in the example below, as B::I was already found to be unresolvable
8512 // (which is correct if you ignore the inheritance relation between A and B).
8514 // class A { class I {} };
8515 // class B : public A {};
8516 // class C : public B::I {};
8518 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
8520 for (ci.toFirst();(li=ci.current());++ci)
8522 if (li->classDef==0 && li->typeDef==0)
8524 Doxygen::lookupCache->remove(ci.currentKey());
8528 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
8530 for (;(fn=fnli.current());++fnli) // for each global function name
8532 MemberNameIterator fni(*fn);
8534 for (;(fmd=fni.current());++fni) // for each function with that name
8536 fmd->invalidateCachedArgumentTypes();
8539 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
8540 for (;(fn=mnli.current());++mnli) // for each class method name
8542 MemberNameIterator mni(*fn);
8544 for (;(fmd=mni.current());++mni) // for each function with that name
8546 fmd->invalidateCachedArgumentTypes();
8552 //----------------------------------------------------------------------------
8554 static void findDefineDocumentation(EntryNav *rootNav)
8556 if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
8557 rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
8560 rootNav->loadEntry(g_storage);
8561 Entry *root = rootNav->entry();
8563 //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
8564 // root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
8566 if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
8568 MemberDef *md=new MemberDef(rootNav->tagInfo()->tagName,1,1,
8569 "#define",root->name,root->args,0,
8570 Public,Normal,FALSE,Member,MemberType_Define,0,0,"");
8571 md->setTagInfo(rootNav->tagInfo());
8572 md->setLanguage(root->lang);
8573 //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
8574 md->setFileDef(rootNav->parent()->fileDef());
8575 //printf("Adding member=%s\n",md->name().data());
8577 if ((mn=Doxygen::functionNameSDict->find(root->name)))
8583 mn = new MemberName(root->name);
8585 Doxygen::functionNameSDict->append(root->name,mn);
8588 MemberName *mn=Doxygen::functionNameSDict->find(root->name);
8591 MemberNameIterator mni(*mn);
8594 for (;(md=mni.current());++mni)
8596 if (md->memberType()==MemberType_Define) count++;
8600 for (mni.toFirst();(md=mni.current());++mni)
8602 if (md->memberType()==MemberType_Define)
8604 md->setDocumentation(root->doc,root->docFile,root->docLine);
8605 md->setDocsForDefinition(!root->proto);
8606 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8607 if (md->inbodyDocumentation().isEmpty())
8609 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8611 md->setBodySegment(root->bodyLine,root->endBodyLine);
8612 md->setBodyDef(rootNav->fileDef());
8613 md->addSectionsToDefinition(root->anchors);
8614 md->setMaxInitLines(root->initLines);
8615 md->setRefItems(root->sli);
8616 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8617 addMemberToGroups(root,md);
8622 (!root->doc.isEmpty() ||
8623 !root->brief.isEmpty() ||
8627 // multiple defines don't know where to add docs
8628 // but maybe they are in different files together with their documentation
8630 for (mni.toFirst();(md=mni.current());++mni)
8632 if (md->memberType()==MemberType_Define)
8634 FileDef *fd=md->getFileDef();
8635 if (fd && fd->absFilePath()==root->fileName)
8636 // doc and define in the same file assume they belong together.
8639 if (md->documentation().isEmpty())
8642 md->setDocumentation(root->doc,root->docFile,root->docLine);
8643 md->setDocsForDefinition(!root->proto);
8646 if (md->briefDescription().isEmpty())
8649 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8651 if (md->inbodyDocumentation().isEmpty())
8653 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8655 md->setBodySegment(root->bodyLine,root->endBodyLine);
8656 md->setBodyDef(rootNav->fileDef());
8657 md->addSectionsToDefinition(root->anchors);
8658 md->setRefItems(root->sli);
8659 md->setLanguage(root->lang);
8660 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8661 addMemberToGroups(root,md);
8665 //warn("define %s found in the following files:\n",root->name.data());
8666 //warn("Cannot determine where to add the documentation found "
8667 // "at line %d of file %s. \n",
8668 // root->startLine,root->fileName.data());
8671 else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8673 static bool preEnabled = Config_getBool(ENABLE_PREPROCESSING);
8676 warn(root->fileName,root->startLine,
8677 "documentation for unknown define %s found.\n",
8683 warn(root->fileName,root->startLine,
8684 "found documented #define but ignoring it because "
8685 "ENABLE_PREPROCESSING is NO.\n",
8691 rootNav->releaseEntry();
8693 RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8696 //----------------------------------------------------------------------------
8698 static void findDirDocumentation(EntryNav *rootNav)
8700 if (rootNav->section() == Entry::DIRDOC_SEC)
8702 rootNav->loadEntry(g_storage);
8703 Entry *root = rootNav->entry();
8705 QCString normalizedName = root->name;
8706 normalizedName = substitute(normalizedName,"\\","/");
8707 //printf("root->docFile=%s normalizedName=%s\n",
8708 // root->docFile.data(),normalizedName.data());
8709 if (root->docFile==normalizedName) // current dir?
8711 int lastSlashPos=normalizedName.findRev('/');
8712 if (lastSlashPos!=-1) // strip file name
8714 normalizedName=normalizedName.left(lastSlashPos);
8717 if (normalizedName.at(normalizedName.length()-1)!='/')
8719 normalizedName+='/';
8721 DirDef *dir,*matchingDir=0;
8722 SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8723 for (sdi.toFirst();(dir=sdi.current());++sdi)
8725 //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8726 if (dir->name().right(normalizedName.length())==normalizedName)
8730 warn(root->fileName,root->startLine,
8731 "\\dir command matches multiple directories.\n"
8732 " Applying the command for directory %s\n"
8733 " Ignoring the command for directory %s\n",
8734 matchingDir->name().data(),dir->name().data()
8745 //printf("Match for with dir %s\n",matchingDir->name().data());
8746 matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8747 matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8748 matchingDir->setRefItems(root->sli);
8749 addDirToGroups(root,matchingDir);
8753 warn(root->fileName,root->startLine,"No matching "
8754 "directory found for command \\dir %s\n",normalizedName.data());
8756 rootNav->releaseEntry();
8758 RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8762 //----------------------------------------------------------------------------
8763 // create a (sorted) list of separate documentation pages
8765 static void buildPageList(EntryNav *rootNav)
8767 if (rootNav->section() == Entry::PAGEDOC_SEC)
8769 rootNav->loadEntry(g_storage);
8770 Entry *root = rootNav->entry();
8772 if (!root->name.isEmpty())
8774 addRelatedPage(rootNav);
8777 rootNav->releaseEntry();
8779 else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8781 rootNav->loadEntry(g_storage);
8782 Entry *root = rootNav->entry();
8784 QCString title=root->args.stripWhiteSpace();
8785 if (title.isEmpty()) title=theTranslator->trMainPage();
8786 //QCString name = Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8787 QCString name = "index";
8788 addRefItem(root->sli,
8796 rootNav->releaseEntry();
8798 RECURSE_ENTRYTREE(buildPageList,rootNav);
8801 // search for the main page defined in this project
8802 static void findMainPage(EntryNav *rootNav)
8804 if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8806 rootNav->loadEntry(g_storage);
8808 if (Doxygen::mainPage==0 && rootNav->tagInfo()==0)
8810 Entry *root = rootNav->entry();
8811 //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8812 QCString title=root->args.stripWhiteSpace();
8813 //QCString indexName=Config_getBool(GENERATE_TREEVIEW)?"main":"index";
8814 QCString indexName="index";
8815 Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8816 indexName, root->brief+root->doc+root->inbodyDocs,title);
8817 //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8818 Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8819 Doxygen::mainPage->setFileName(indexName);
8820 Doxygen::mainPage->setLocalToc(root->localToc);
8821 addPageToContext(Doxygen::mainPage,rootNav);
8823 SectionInfo *si = Doxygen::sectionDict->find(Doxygen::mainPage->name());
8826 if (si->lineNr != -1)
8828 warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s, line %d)",Doxygen::mainPage->name().data(),si->fileName.data(),si->lineNr);
8832 warn(root->fileName,root->startLine,"multiple use of section label '%s' for main page, (first occurrence: %s)",Doxygen::mainPage->name().data(),si->fileName.data());
8837 // a page name is a label as well! but should no be double either
8839 indexName, root->startLine,
8840 Doxygen::mainPage->name(),
8841 Doxygen::mainPage->title(),
8844 Doxygen::sectionDict->append(indexName,si);
8845 Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8848 else if (rootNav->tagInfo()==0)
8850 Entry *root = rootNav->entry();
8851 warn(root->fileName,root->startLine,
8852 "found more than one \\mainpage comment block! (first occurrence: %s, line %d), Skipping current block!",
8853 Doxygen::mainPage->docFile().data(),Doxygen::mainPage->docLine());
8856 rootNav->releaseEntry();
8858 RECURSE_ENTRYTREE(findMainPage,rootNav);
8861 // search for the main page imported via tag files and add only the section labels
8862 static void findMainPageTagFiles(EntryNav *rootNav)
8864 if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8866 rootNav->loadEntry(g_storage);
8868 if (Doxygen::mainPage && rootNav->tagInfo())
8870 Entry *root = rootNav->entry();
8871 Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8874 RECURSE_ENTRYTREE(findMainPageTagFiles,rootNav);
8877 static void computePageRelations(EntryNav *rootNav)
8879 if ((rootNav->section()==Entry::PAGEDOC_SEC ||
8880 rootNav->section()==Entry::MAINPAGEDOC_SEC
8882 && !rootNav->name().isEmpty()
8885 rootNav->loadEntry(g_storage);
8886 Entry *root = rootNav->entry();
8888 PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8889 Doxygen::pageSDict->find(root->name) :
8893 QListIterator<BaseInfo> bii(*root->extends);
8895 for (bii.toFirst();(bi=bii.current());++bii)
8897 PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8900 pd->addInnerCompound(subPd);
8901 //printf("*** Added subpage relation: %s->%s\n",
8902 // pd->name().data(),subPd->name().data());
8907 rootNav->releaseEntry();
8909 RECURSE_ENTRYTREE(computePageRelations,rootNav);
8912 static void checkPageRelations()
8914 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8916 for (pdi.toFirst();(pd=pdi.current());++pdi)
8918 Definition *ppd = pd->getOuterScope();
8923 err("page defined at line %d of file %s with label %s is a subpage "
8924 "of itself! Please remove this cyclic dependency.\n",
8925 pd->docLine(),pd->docFile().data(),pd->name().data());
8928 ppd=ppd->getOuterScope();
8933 //----------------------------------------------------------------------------
8935 static void resolveUserReferences()
8937 SDict<SectionInfo>::Iterator sdi(*Doxygen::sectionDict);
8939 for (;(si=sdi.current());++sdi)
8941 //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8942 // si->label.data(),si->definition?si->definition->name().data():"<none>",
8943 // si->fileName.data());
8946 // hack: the items of a todo/test/bug/deprecated list are all fragments from
8947 // different files, so the resulting section's all have the wrong file
8948 // name (not from the todo/test/bug/deprecated list, but from the file in
8949 // which they are defined). We correct this here by looking at the
8950 // generated section labels!
8951 QDictIterator<RefList> rli(*Doxygen::xrefLists);
8953 for (rli.toFirst();(rl=rli.current());++rli)
8955 QCString label="_"+rl->listName(); // "_todo", "_test", ...
8956 if (si->label.left(label.length())==label)
8958 si->fileName=rl->listName();
8964 //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8967 // if this section is in a page and the page is in a group, then we
8968 // have to adjust the link file name to point to the group.
8969 if (!si->fileName.isEmpty() &&
8970 (pd=Doxygen::pageSDict->find(si->fileName)) &&
8973 si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8978 // TODO: there should be one function in Definition that returns
8979 // the file to link to, so we can avoid the following tests.
8981 if (si->definition->definitionType()==Definition::TypeMember)
8983 gd = ((MemberDef *)si->definition)->getGroupDef();
8988 si->fileName=gd->getOutputFileBase().copy();
8992 //si->fileName=si->definition->getOutputFileBase().copy();
8993 //printf("Setting si->fileName to %s\n",si->fileName.data());
8997 //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
9003 //----------------------------------------------------------------------------
9004 // generate all separate documentation pages
9007 static void generatePageDocs()
9009 //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
9010 if (documentedPages==0) return;
9011 PageSDict::Iterator pdi(*Doxygen::pageSDict);
9013 for (pdi.toFirst();(pd=pdi.current());++pdi)
9015 if (!pd->getGroupDef() && !pd->isReference())
9017 msg("Generating docs for page %s...\n",pd->name().data());
9018 Doxygen::insideMainPage=TRUE;
9019 pd->writeDocumentation(*g_outputList);
9020 Doxygen::insideMainPage=FALSE;
9025 //----------------------------------------------------------------------------
9026 // create a (sorted) list & dictionary of example pages
9028 static void buildExampleList(EntryNav *rootNav)
9030 if ((rootNav->section()==Entry::EXAMPLE_SEC || rootNav->section()==Entry::EXAMPLE_LINENO_SEC) && !rootNav->name().isEmpty())
9032 rootNav->loadEntry(g_storage);
9033 Entry *root = rootNav->entry();
9035 if (Doxygen::exampleSDict->find(root->name))
9037 warn(root->fileName,root->startLine,
9038 "Example %s was already documented. Ignoring "
9039 "documentation found here.",
9045 PageDef *pd=new PageDef(root->fileName,root->startLine,
9046 root->name,root->brief+root->doc+root->inbodyDocs,root->args);
9047 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
9048 pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
9049 pd->addSectionsToDefinition(root->anchors);
9050 pd->setLanguage(root->lang);
9051 pd->setShowLineNo(rootNav->section()==Entry::EXAMPLE_LINENO_SEC);
9053 Doxygen::exampleSDict->inSort(root->name,pd);
9054 //we don't add example to groups
9055 //addExampleToGroups(root,pd);
9058 rootNav->releaseEntry();
9060 RECURSE_ENTRYTREE(buildExampleList,rootNav);
9063 //----------------------------------------------------------------------------
9064 // prints the Entry tree (for debugging)
9066 void printNavTree(EntryNav *rootNav,int indent)
9069 indentStr.fill(' ',indent);
9070 msg("%s%s (sec=0x%x)\n",
9071 indentStr.isEmpty()?"":indentStr.data(),
9072 rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
9073 rootNav->section());
9074 if (rootNav->children())
9076 EntryNavListIterator eli(*rootNav->children());
9077 for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
9082 //----------------------------------------------------------------------------
9083 // generate the example documentation
9085 static void generateExampleDocs()
9087 g_outputList->disable(OutputGenerator::Man);
9088 PageSDict::Iterator pdi(*Doxygen::exampleSDict);
9090 for (pdi.toFirst();(pd=pdi.current());++pdi)
9092 msg("Generating docs for example %s...\n",pd->name().data());
9093 resetCCodeParserState();
9094 QCString n=pd->getOutputFileBase();
9095 startFile(*g_outputList,n,n,pd->name());
9096 startTitle(*g_outputList,n);
9097 g_outputList->docify(pd->name());
9098 endTitle(*g_outputList,n,0);
9099 g_outputList->startContents();
9100 QCString lineNoOptStr;
9101 if (pd->showLineNo())
9103 lineNoOptStr="{lineno}";
9105 g_outputList->generateDoc(pd->docFile(), // file
9106 pd->docLine(), // startLine
9109 pd->documentation()+"\n\n\\include"+lineNoOptStr+" "+pd->name(), // docs
9110 TRUE, // index words
9114 endFile(*g_outputList); // contains g_outputList->endContents()
9116 g_outputList->enable(OutputGenerator::Man);
9119 //----------------------------------------------------------------------------
9120 // generate module pages
9122 static void generateGroupDocs()
9124 GroupSDict::Iterator gli(*Doxygen::groupSDict);
9126 for (gli.toFirst();(gd=gli.current());++gli)
9128 if (!gd->isReference())
9130 gd->writeDocumentation(*g_outputList);
9135 //----------------------------------------------------------------------------
9137 //static void generatePackageDocs()
9139 // writePackageIndex(*g_outputList);
9141 // if (Doxygen::packageDict.count()>0)
9143 // PackageSDict::Iterator pdi(Doxygen::packageDict);
9145 // for (pdi.toFirst();(pd=pdi.current());++pdi)
9147 // pd->writeDocumentation(*g_outputList);
9152 //----------------------------------------------------------------------------
9153 // generate module pages
9155 static void generateNamespaceClassDocs(ClassSDict *d)
9157 // for each class in the namespace...
9158 ClassSDict::Iterator cli(*d);
9160 for ( ; (cd=cli.current()) ; ++cli )
9162 if ( ( cd->isLinkableInProject() &&
9163 cd->templateMaster()==0
9164 ) // skip external references, anonymous compounds and
9165 // template instances and nested classes
9166 && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
9169 msg("Generating docs for compound %s...\n",cd->name().data());
9171 cd->writeDocumentation(*g_outputList);
9172 cd->writeMemberList(*g_outputList);
9174 cd->writeDocumentationForInnerClasses(*g_outputList);
9178 static void generateNamespaceDocs()
9180 static bool sliceOpt = Config_getBool(OPTIMIZE_OUTPUT_SLICE);
9182 //writeNamespaceIndex(*g_outputList);
9184 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
9186 // for each namespace...
9187 for (;(nd=nli.current());++nli)
9190 if (nd->isLinkableInProject())
9192 msg("Generating docs for namespace %s\n",nd->name().data());
9193 nd->writeDocumentation(*g_outputList);
9196 generateNamespaceClassDocs(nd->getClassSDict());
9199 generateNamespaceClassDocs(nd->getInterfaceSDict());
9200 generateNamespaceClassDocs(nd->getStructSDict());
9201 generateNamespaceClassDocs(nd->getExceptionSDict());
9207 static QCString fixSlashes(QCString &s)
9211 for (i=0;i<s.length();i++)
9228 //----------------------------------------------------------------------------
9230 /*! Generate a template version of the configuration file.
9231 * If the \a shortList parameter is TRUE a configuration file without
9232 * comments will be generated.
9234 static void generateConfigFile(const char *configFile,bool shortList,
9235 bool updateOnly=FALSE)
9238 bool fileOpened=openOutputFile(configFile,f);
9239 bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
9243 Config::writeTemplate(t,shortList,updateOnly);
9248 msg("\n\nConfiguration file `%s' created.\n\n",configFile);
9249 msg("Now edit the configuration file and enter\n\n");
9250 if (qstrcmp(configFile,"Doxyfile") || qstrcmp(configFile,"doxyfile"))
9251 msg(" doxygen %s\n\n",configFile);
9253 msg(" doxygen\n\n");
9254 msg("to generate the documentation for your project\n\n");
9258 msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
9264 err("Cannot open file %s for writing\n",configFile);
9268 static void compareDoxyfile()
9272 configFile[0] = '-';
9273 configFile[1] = '\0';
9274 bool fileOpened=openOutputFile(configFile,f);
9278 Config::compareDoxyfile(t);
9282 err("Cannot open file %s for writing\n",configFile);
9286 //----------------------------------------------------------------------------
9287 // read and parse a tag file
9289 //static bool readLineFromFile(QFile &f,QCString &s)
9293 // while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
9294 // return f.atEnd();
9297 //----------------------------------------------------------------------------
9299 static void readTagFile(Entry *root,const char *tl)
9301 QCString tagLine = tl;
9304 int eqPos = tagLine.find('=');
9305 if (eqPos!=-1) // tag command contains a destination
9307 fileName = tagLine.left(eqPos).stripWhiteSpace();
9308 destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
9309 QFileInfo fi(fileName);
9310 Doxygen::tagDestinationDict.insert(fi.absFilePath().utf8(),new QCString(destName));
9311 //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
9318 QFileInfo fi(fileName);
9319 if (!fi.exists() || !fi.isFile())
9321 err("Tag file `%s' does not exist or is not a file. Skipping it...\n",
9326 if (!destName.isEmpty())
9327 msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
9329 msg("Reading tag file `%s'...\n",fileName.data());
9331 parseTagFile(root,fi.absFilePath().utf8());
9334 //----------------------------------------------------------------------------
9335 static void copyLatexStyleSheet()
9337 QStrList latexExtraStyleSheet = Config_getList(LATEX_EXTRA_STYLESHEET);
9338 for (uint i=0; i<latexExtraStyleSheet.count(); ++i)
9340 QCString fileName(latexExtraStyleSheet.at(i));
9341 if (!fileName.isEmpty())
9343 QFileInfo fi(fileName);
9346 err("Style sheet '%s' specified by LATEX_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9350 QCString destFileName = Config_getString(LATEX_OUTPUT)+"/"+fi.fileName().data();
9351 if (!checkExtension(fi.fileName().data(), latexStyleExtension))
9353 destFileName += latexStyleExtension;
9355 copyFile(fileName, destFileName);
9361 //----------------------------------------------------------------------------
9362 static void copyStyleSheet()
9364 QCString &htmlStyleSheet = Config_getString(HTML_STYLESHEET);
9365 if (!htmlStyleSheet.isEmpty())
9367 QFileInfo fi(htmlStyleSheet);
9370 err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
9371 htmlStyleSheet.resize(0); // revert to the default
9375 QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9376 copyFile(htmlStyleSheet,destFileName);
9379 QStrList htmlExtraStyleSheet = Config_getList(HTML_EXTRA_STYLESHEET);
9380 for (uint i=0; i<htmlExtraStyleSheet.count(); ++i)
9382 QCString fileName(htmlExtraStyleSheet.at(i));
9383 if (!fileName.isEmpty())
9385 QFileInfo fi(fileName);
9388 err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",fileName.data());
9390 else if (fi.fileName()=="doxygen.css" || fi.fileName()=="tabs.css" || fi.fileName()=="navtree.css")
9392 err("Style sheet %s specified by HTML_EXTRA_STYLESHEET is already a built-in stylesheet. Please use a different name\n",fi.fileName().data());
9396 QCString destFileName = Config_getString(HTML_OUTPUT)+"/"+fi.fileName().data();
9397 copyFile(fileName, destFileName);
9403 static void copyLogo(const QCString &outputOption)
9405 QCString &projectLogo = Config_getString(PROJECT_LOGO);
9406 if (!projectLogo.isEmpty())
9408 QFileInfo fi(projectLogo);
9411 err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
9412 projectLogo.resize(0); // revert to the default
9416 QCString destFileName = outputOption+"/"+fi.fileName().data();
9417 copyFile(projectLogo,destFileName);
9418 Doxygen::indexList->addImageFile(fi.fileName().data());
9423 static void copyExtraFiles(QStrList files,const QString &filesOption,const QCString &outputOption)
9426 for (i=0; i<files.count(); ++i)
9428 QCString fileName(files.at(i));
9430 if (!fileName.isEmpty())
9432 QFileInfo fi(fileName);
9435 err("Extra file '%s' specified in %s does not exist!\n", fileName.data(),filesOption.data());
9439 QCString destFileName = outputOption+"/"+fi.fileName().data();
9440 Doxygen::indexList->addImageFile(fi.fileName().utf8());
9441 copyFile(fileName, destFileName);
9447 //----------------------------------------------------------------------------
9449 static ParserInterface *getParserForFile(const char *fn)
9451 QCString fileName=fn;
9453 int sep = fileName.findRev('/');
9454 int ei = fileName.findRev('.');
9455 if (ei!=-1 && (sep==-1 || ei>sep)) // matches dir/file.ext but not dir.1/file
9457 extension=fileName.right(fileName.length()-ei);
9461 extension = ".no_extension";
9464 return Doxygen::parserManager->getParser(extension);
9467 static void parseFile(ParserInterface *parser,
9468 Entry *root,EntryNav *rootNav,FileDef *fd,const char *fn,
9469 bool sameTu,QStrList &filesInSameTu)
9472 static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9474 static bool clangAssistedParsing = FALSE;
9476 QCString fileName=fn;
9478 int ei = fileName.findRev('.');
9481 extension=fileName.right(fileName.length()-ei);
9485 extension = ".no_extension";
9488 QFileInfo fi(fileName);
9489 BufStr preBuf(fi.size()+4096);
9491 if (Config_getBool(ENABLE_PREPROCESSING) &&
9492 parser->needsPreprocessing(extension))
9494 BufStr inBuf(fi.size()+4096);
9495 msg("Preprocessing %s...\n",fn);
9496 readInputFile(fileName,inBuf);
9497 preprocessFile(fileName,inBuf,preBuf);
9499 else // no preprocessing
9501 msg("Reading %s...\n",fn);
9502 readInputFile(fileName,preBuf);
9504 if (preBuf.data() && preBuf.curPos()>0 && *(preBuf.data()+preBuf.curPos()-1)!='\n')
9506 preBuf.addChar('\n'); // add extra newline to help parser
9509 BufStr convBuf(preBuf.curPos()+1024);
9511 // convert multi-line C++ comments to C style comments
9512 convertCppComments(&preBuf,&convBuf,fileName);
9514 convBuf.addChar('\0');
9516 if (clangAssistedParsing && !sameTu)
9518 fd->getAllIncludeFilesRecursively(filesInSameTu);
9521 // use language parse to parse the file
9522 parser->parseInput(fileName,convBuf.data(),root,sameTu,filesInSameTu);
9524 // store the Entry tree in a file and create an index to
9525 // navigate/load entries
9526 //printf("root->createNavigationIndex for %s\n",fd->name().data());
9527 root->createNavigationIndex(rootNav,g_storage,fd);
9530 //! parse the list of input files
9531 static void parseFiles(Entry *root,EntryNav *rootNav)
9534 static bool clangAssistedParsing = Config_getBool(CLANG_ASSISTED_PARSING);
9535 if (clangAssistedParsing)
9537 QDict<void> g_processedFiles(10007);
9539 // create a dictionary with files to process
9540 QDict<void> g_filesToProcess(10007);
9541 StringListIterator it(g_inputFiles);
9543 for (;(s=it.current());++it)
9545 g_filesToProcess.insert(*s,(void*)0x8);
9548 // process source files (and their include dependencies)
9549 for (it.toFirst();(s=it.current());++it)
9552 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9554 if (fd->isSource() && !fd->isReference()) // this is a source file
9556 QStrList filesInSameTu;
9557 ParserInterface * parser = getParserForFile(s->data());
9558 parser->startTranslationUnit(s->data());
9559 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9560 //printf(" got %d extra files in tu\n",filesInSameTu.count());
9562 // Now process any include files in the same translation unit
9563 // first. When libclang is used this is much more efficient.
9564 char *incFile = filesInSameTu.first();
9565 while (incFile && g_filesToProcess.find(incFile))
9567 if (qstrcmp(incFile,s->data()) && !g_processedFiles.find(incFile))
9569 FileDef *ifd=findFileDef(Doxygen::inputNameDict,incFile,ambig);
9570 if (ifd && !ifd->isReference())
9573 //printf(" Processing %s in same translation unit as %s\n",incFile,s->data());
9574 parseFile(parser,root,rootNav,ifd,incFile,TRUE,moreFiles);
9575 g_processedFiles.insert(incFile,(void*)0x8);
9578 incFile = filesInSameTu.next();
9580 parser->finishTranslationUnit();
9581 g_processedFiles.insert(*s,(void*)0x8);
9584 // process remaining files
9585 for (it.toFirst();(s=it.current());++it)
9587 if (!g_processedFiles.find(*s)) // not yet processed
9590 QStrList filesInSameTu;
9591 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9593 ParserInterface * parser = getParserForFile(s->data());
9594 parser->startTranslationUnit(s->data());
9595 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9596 parser->finishTranslationUnit();
9597 g_processedFiles.insert(*s,(void*)0x8);
9601 else // normal pocessing
9604 StringListIterator it(g_inputFiles);
9606 for (;(s=it.current());++it)
9609 QStrList filesInSameTu;
9610 FileDef *fd=findFileDef(Doxygen::inputNameDict,s->data(),ambig);
9612 ParserInterface * parser = getParserForFile(s->data());
9613 parser->startTranslationUnit(s->data());
9614 parseFile(parser,root,rootNav,fd,s->data(),FALSE,filesInSameTu);
9619 // resolves a path that may include symlinks, if a recursive symlink is
9620 // found an empty string is returned.
9621 static QCString resolveSymlink(QCString path)
9626 QDict<void> nonSymlinks;
9628 QCString result = path;
9629 QCString oldPrefix = "/";
9633 // UNC path, skip server and share name
9634 if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
9635 sepPos = result.find('/',2);
9637 sepPos = result.find('/',sepPos+1);
9639 sepPos = result.find('/',sepPos+1);
9641 QCString prefix = sepPos==-1 ? result : result.left(sepPos);
9642 if (nonSymlinks.find(prefix)==0)
9647 QString target = fi.readLink();
9648 bool isRelative = QFileInfo(target).isRelative();
9651 target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
9655 if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
9659 target+=result.mid(sepPos);
9661 result = QDir::cleanDirPath(target).data();
9663 if (known.find(result)) return QCString(); // recursive symlink!
9664 known.insert(result,(void*)0x8);
9669 else // link to absolute path
9677 nonSymlinks.insert(prefix,(void*)0x8);
9684 return QDir::cleanDirPath(result).data();
9687 static QDict<void> g_pathsVisited(1009);
9689 //----------------------------------------------------------------------------
9690 // Read all files matching at least one pattern in `patList' in the
9691 // directory represented by `fi'.
9692 // The directory is read iff the recusiveFlag is set.
9693 // The contents of all files is append to the input string
9695 int readDir(QFileInfo *fi,
9696 FileNameList *fnList,
9697 FileNameDict *fnDict,
9698 StringDict *exclDict,
9700 QStrList *exclPatList,
9701 StringList *resultList,
9702 StringDict *resultDict,
9703 bool errorIfNotExist,
9705 QDict<void> *killDict,
9709 QCString dirName = fi->absFilePath().utf8();
9710 if (paths && paths->find(dirName)==0)
9712 paths->insert(dirName,(void*)0x8);
9714 if (fi->isSymLink())
9716 dirName = resolveSymlink(dirName.data());
9717 if (dirName.isEmpty()) return 0; // recursive symlink
9718 if (g_pathsVisited.find(dirName)) return 0; // already visited path
9719 g_pathsVisited.insert(dirName,(void*)0x8);
9722 dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
9724 msg("Searching for files in directory %s\n", fi->absFilePath().data());
9725 //printf("killDict=%p count=%d\n",killDict,killDict->count());
9727 const QFileInfoList *list = dir.entryInfoList();
9730 QFileInfoListIterator it( *list );
9733 while ((cfi=it.current()))
9735 if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0)
9736 { // file should not be excluded
9737 //printf("killDict->find(%s)\n",cfi->absFilePath().data());
9738 if (!cfi->exists() || !cfi->isReadable())
9740 if (errorIfNotExist)
9742 warn_uncond("source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
9745 else if (cfi->isFile() &&
9746 (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9747 (patList==0 || patternMatch(*cfi,patList)) &&
9748 !patternMatch(*cfi,exclPatList) &&
9749 (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
9752 totalSize+=cfi->size()+cfi->absFilePath().length()+4;
9753 QCString name=cfi->fileName().utf8();
9754 //printf("New file %s\n",name.data());
9757 FileDef *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
9759 if (!name.isEmpty() && (fn=(*fnDict)[name]))
9765 fn = new FileName(cfi->absFilePath().utf8(),name);
9767 if (fnList) fnList->append(fn);
9768 fnDict->insert(name,fn);
9772 if (resultList || resultDict)
9774 rs=new QCString(cfi->absFilePath().utf8());
9776 if (resultList) resultList->append(rs);
9777 if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
9778 if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
9780 else if (recursive &&
9781 (!Config_getBool(EXCLUDE_SYMLINKS) || !cfi->isSymLink()) &&
9783 !patternMatch(*cfi,exclPatList) &&
9784 cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
9786 cfi->setFile(cfi->absFilePath());
9787 totalSize+=readDir(cfi,fnList,fnDict,exclDict,
9788 patList,exclPatList,resultList,resultDict,errorIfNotExist,
9789 recursive,killDict,paths);
9799 //----------------------------------------------------------------------------
9800 // read a file or all files in a directory and append their contents to the
9801 // input string. The names of the files are appended to the `fiList' list.
9803 int readFileOrDirectory(const char *s,
9804 FileNameList *fnList,
9805 FileNameDict *fnDict,
9806 StringDict *exclDict,
9808 QStrList *exclPatList,
9809 StringList *resultList,
9810 StringDict *resultDict,
9812 bool errorIfNotExist,
9813 QDict<void> *killDict,
9817 //printf("killDict=%p count=%d\n",killDict,killDict->count());
9818 // strip trailing slashes
9821 char lc = fs.at(fs.length()-1);
9822 if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9825 //printf("readFileOrDirectory(%s)\n",s);
9828 if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9830 if (!fi.exists() || !fi.isReadable())
9832 if (errorIfNotExist)
9834 warn_uncond("source %s is not a readable file or directory... skipping.\n",s);
9837 else if (!Config_getBool(EXCLUDE_SYMLINKS) || !fi.isSymLink())
9841 QCString dirPath = fi.dirPath(TRUE).utf8();
9842 QCString filePath = fi.absFilePath().utf8();
9843 if (paths && paths->find(dirPath))
9845 paths->insert(dirPath,(void*)0x8);
9847 //printf("killDict->find(%s)\n",fi.absFilePath().data());
9848 if (killDict==0 || killDict->find(filePath)==0)
9850 totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input);
9851 //fiList->inSort(new FileInfo(fi));
9852 QCString name=fi.fileName().utf8();
9853 //printf("New file %s\n",name.data());
9856 FileDef *fd=new FileDef(dirPath+"/",name);
9858 if (!name.isEmpty() && (fn=(*fnDict)[name]))
9864 fn = new FileName(filePath,name);
9866 if (fnList) fnList->append(fn);
9867 fnDict->insert(name,fn);
9871 if (resultList || resultDict)
9873 rs=new QCString(filePath);
9874 if (resultList) resultList->append(rs);
9875 if (resultDict) resultDict->insert(filePath,rs);
9878 if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9881 else if (fi.isDir()) // readable dir
9883 totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9884 exclPatList,resultList,resultDict,errorIfNotExist,
9885 recursive,killDict,paths);
9893 //----------------------------------------------------------------------------
9895 void readFormulaRepository(QCString dir, bool cmp)
9897 static int current_repository = 0;
9898 int new_repository = 0;
9899 QFile f(dir+"/formula.repository");
9900 if (f.open(IO_ReadOnly)) // open repository
9902 msg("Reading formula repository...\n");
9908 line=t.readLine().utf8();
9909 int se=line.find(':'); // find name and text separator.
9912 warn_uncond("formula.repository is corrupted!\n");
9917 QCString formName = line.left(se);
9918 QCString formText = line.right(line.length()-se-1);
9921 if ((f=Doxygen::formulaDict->find(formText))==0)
9923 err("discrepancy between formula repositories! Remove "
9924 "formula.repository and from_* files from output directories.");
9928 formLabel.sprintf("\\form#%d",f->getId());
9929 if (formLabel != formName)
9931 err("discrepancy between formula repositories! Remove "
9932 "formula.repository and from_* files from output directories.");
9939 f=new Formula(formText);
9940 Doxygen::formulaList->append(f);
9941 Doxygen::formulaDict->insert(formText,f);
9942 Doxygen::formulaNameDict->insert(formName,f);
9943 current_repository++;
9948 if (cmp && (current_repository != new_repository))
9950 err("size discrepancy between formula repositories! Remove "
9951 "formula.repository and from_* files from output directories.");
9956 //----------------------------------------------------------------------------
9958 static void expandAliases()
9960 QDictIterator<QCString> adi(Doxygen::aliasDict);
9962 for (adi.toFirst();(s=adi.current());++adi)
9964 *s = expandAlias(adi.currentKey(),*s);
9968 //----------------------------------------------------------------------------
9970 static void escapeAliases()
9972 QDictIterator<QCString> adi(Doxygen::aliasDict);
9974 for (adi.toFirst();(s=adi.current());++adi)
9976 QCString value=*s,newValue;
9978 // for each \n in the alias command value
9979 while ((in=value.find("\\n",p))!=-1)
9981 newValue+=value.mid(p,in-p);
9982 // expand \n's except if \n is part of a built-in command.
9983 if (value.mid(in,5)!="\\note" &&
9984 value.mid(in,5)!="\\name" &&
9985 value.mid(in,10)!="\\namespace" &&
9986 value.mid(in,14)!="\\nosubgrouping"
9989 newValue+="\\_linebr ";
9997 newValue+=value.mid(p,value.length()-p);
10001 while ((in=value.find("^^",p))!=-1)
10003 newValue+=value.mid(p,in-p);
10004 newValue+="@_linebr";
10007 newValue+=value.mid(p,value.length()-p);
10009 //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
10013 //----------------------------------------------------------------------------
10017 // add aliases to a dictionary
10018 Doxygen::aliasDict.setAutoDelete(TRUE);
10019 QStrList &aliasList = Config_getList(ALIASES);
10020 const char *s=aliasList.first();
10023 if (Doxygen::aliasDict[s]==0)
10026 int i=alias.find('=');
10029 QCString name=alias.left(i).stripWhiteSpace();
10030 QCString value=alias.right(alias.length()-i-1);
10031 //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
10032 if (!name.isEmpty())
10034 QCString *dn=Doxygen::aliasDict[name];
10035 if (dn==0) // insert new alias
10037 Doxygen::aliasDict.insert(name,new QCString(value));
10039 else // overwrite previous alias
10046 s=aliasList.next();
10052 //----------------------------------------------------------------------------
10054 static void dumpSymbol(FTextStream &t,Definition *d)
10057 if (d->definitionType()==Definition::TypeMember)
10059 MemberDef *md = (MemberDef *)d;
10060 anchor=":"+md->anchor();
10063 if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope)
10065 scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
10067 t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
10068 << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
10070 << d->name() << "','"
10071 << d->getDefFileName() << "','"
10076 static void dumpSymbolMap()
10078 QFile f("symbols.sql");
10079 if (f.open(IO_WriteOnly))
10082 QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
10083 DefinitionIntf *intf;
10084 for (;(intf=di.current());++di)
10086 if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
10088 DefinitionListIterator dli(*(DefinitionList*)intf);
10091 for (dli.toFirst();(d=dli.current());++dli)
10096 else // single symbol
10098 Definition *d = (Definition *)intf;
10099 if (d!=Doxygen::globalScope) dumpSymbol(t,d);
10105 // print developer options of doxygen
10106 static void devUsage()
10108 msg("Developer parameters:\n");
10109 msg(" -m dump symbol map\n");
10110 msg(" -b output to wizard\n");
10111 msg(" -T activates output generation via Django like template\n");
10112 msg(" -d <level> enable a debug level, such as (multiple invocations of -d are possible):\n");
10113 Debug::printFlags();
10117 //----------------------------------------------------------------------------
10118 // print the usage of doxygen
10120 static void usage(const char *name)
10122 msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2015\n\n",versionString);
10123 msg("You can use doxygen in a number of ways:\n\n");
10124 msg("1) Use doxygen to generate a template configuration file:\n");
10125 msg(" %s [-s] -g [configName]\n\n",name);
10126 msg(" If - is used for configName doxygen will write to standard output.\n\n");
10127 msg("2) Use doxygen to update an old configuration file:\n");
10128 msg(" %s [-s] -u [configName]\n\n",name);
10129 msg("3) Use doxygen to generate documentation using an existing ");
10130 msg("configuration file:\n");
10131 msg(" %s [configName]\n\n",name);
10132 msg(" If - is used for configName doxygen will read from standard input.\n\n");
10133 msg("4) Use doxygen to generate a template file controlling the layout of the\n");
10134 msg(" generated documentation:\n");
10135 msg(" %s -l [layoutFileName.xml]\n\n",name);
10136 msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
10137 msg(" RTF: %s -w rtf styleSheetFile\n",name);
10138 msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
10139 msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
10140 msg("6) Use doxygen to generate a rtf extensions file\n");
10141 msg(" RTF: %s -e rtf extensionsFile\n\n",name);
10142 msg("7) Use doxygen to compare the used configuration file with the template configuration file\n");
10143 msg(" %s -x [configFile]\n\n",name);
10144 msg("8) Use doxygen to show a list of build in emoji.\n");
10145 msg(" %s -f emoji outputFileName\n\n",name);
10146 msg(" If - is used for outputFileName doxygen will write to standard output.\n\n");
10147 msg("If -s is specified the comments of the configuration items in the config file will be omitted.\n");
10148 msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
10149 msg("-v print version string\n");
10152 //----------------------------------------------------------------------------
10153 // read the argument of option `c' from the comment argument list and
10154 // update the option index `optind'.
10156 static const char *getArg(int argc,char **argv,int &optind)
10159 if (qstrlen(&argv[optind][2])>0)
10160 s=&argv[optind][2];
10161 else if (optind+1<argc && argv[optind+1][0]!='-')
10166 //----------------------------------------------------------------------------
10171 const char *lang = portable_getenv("LC_ALL");
10172 if (lang) portable_setenv("LANG",lang);
10173 setlocale(LC_ALL,"");
10174 setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
10175 setlocale(LC_NUMERIC,"C");
10177 portable_correct_path();
10179 Doxygen::runningTime.start();
10180 initPreprocessor();
10182 Doxygen::parserManager = new ParserManager;
10183 Doxygen::parserManager->registerDefaultParser( new FileParser);
10184 Doxygen::parserManager->registerParser("c", new CLanguageScanner);
10185 Doxygen::parserManager->registerParser("python", new PythonLanguageScanner);
10186 Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
10187 Doxygen::parserManager->registerParser("fortranfree", new FortranLanguageScannerFree);
10188 Doxygen::parserManager->registerParser("fortranfixed", new FortranLanguageScannerFixed);
10189 Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner);
10190 Doxygen::parserManager->registerParser("xml", new XMLScanner);
10191 Doxygen::parserManager->registerParser("sql", new SQLScanner);
10192 Doxygen::parserManager->registerParser("tcl", new TclLanguageScanner);
10193 Doxygen::parserManager->registerParser("md", new MarkdownFileParser);
10195 // register any additional parsers here...
10197 initDefaultExtensionMapping();
10198 initClassMemberIndices();
10199 initNamespaceMemberIndices();
10200 initFileMemberIndices();
10202 Doxygen::symbolMap = new QDict<DefinitionIntf>(50177);
10203 #ifdef USE_LIBCLANG
10204 Doxygen::clangUsrMap = new QDict<Definition>(50177);
10206 Doxygen::inputNameList = new FileNameList;
10207 Doxygen::inputNameList->setAutoDelete(TRUE);
10208 Doxygen::memberNameSDict = new MemberNameSDict(10000);
10209 Doxygen::memberNameSDict->setAutoDelete(TRUE);
10210 Doxygen::functionNameSDict = new MemberNameSDict(10000);
10211 Doxygen::functionNameSDict->setAutoDelete(TRUE);
10212 Doxygen::groupSDict = new GroupSDict(17);
10213 Doxygen::groupSDict->setAutoDelete(TRUE);
10214 Doxygen::namespaceSDict = new NamespaceSDict(20);
10215 Doxygen::namespaceSDict->setAutoDelete(TRUE);
10216 Doxygen::classSDict = new ClassSDict(1009);
10217 Doxygen::classSDict->setAutoDelete(TRUE);
10218 Doxygen::hiddenClasses = new ClassSDict(257);
10219 Doxygen::hiddenClasses->setAutoDelete(TRUE);
10220 Doxygen::directories = new DirSDict(17);
10221 Doxygen::directories->setAutoDelete(TRUE);
10222 Doxygen::pageSDict = new PageSDict(1009); // all doc pages
10223 Doxygen::pageSDict->setAutoDelete(TRUE);
10224 Doxygen::exampleSDict = new PageSDict(1009); // all examples
10225 Doxygen::exampleSDict->setAutoDelete(TRUE);
10226 Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
10227 Doxygen::tagDestinationDict.setAutoDelete(TRUE);
10228 Doxygen::dirRelations.setAutoDelete(TRUE);
10229 Doxygen::citeDict = new CiteDict(257);
10230 Doxygen::genericsDict = new GenericsSDict;
10231 Doxygen::indexList = new IndexList;
10232 Doxygen::formulaList = new FormulaList;
10233 Doxygen::formulaList->setAutoDelete(TRUE);
10234 Doxygen::formulaDict = new FormulaDict(1009);
10235 Doxygen::formulaNameDict = new FormulaDict(1009);
10236 Doxygen::sectionDict = new SectionDict(257);
10237 Doxygen::sectionDict->setAutoDelete(TRUE);
10239 // initialisation of these globals depends on
10240 // configuration switches so we need to postpone these
10241 Doxygen::globalScope = 0;
10242 Doxygen::inputNameDict = 0;
10243 Doxygen::includeNameDict = 0;
10244 Doxygen::exampleNameDict = 0;
10245 Doxygen::imageNameDict = 0;
10246 Doxygen::dotFileNameDict = 0;
10247 Doxygen::mscFileNameDict = 0;
10248 Doxygen::diaFileNameDict = 0;
10250 /**************************************************************************
10251 * Initialize some global constants
10252 **************************************************************************/
10254 g_compoundKeywordDict.insert("template class",(void *)8);
10255 g_compoundKeywordDict.insert("template struct",(void *)8);
10256 g_compoundKeywordDict.insert("class",(void *)8);
10257 g_compoundKeywordDict.insert("struct",(void *)8);
10258 g_compoundKeywordDict.insert("union",(void *)8);
10259 g_compoundKeywordDict.insert("interface",(void *)8);
10260 g_compoundKeywordDict.insert("exception",(void *)8);
10263 void cleanUpDoxygen()
10265 delete Doxygen::sectionDict;
10266 delete Doxygen::formulaNameDict;
10267 delete Doxygen::formulaDict;
10268 delete Doxygen::formulaList;
10269 delete Doxygen::indexList;
10270 delete Doxygen::genericsDict;
10271 delete Doxygen::inputNameDict;
10272 delete Doxygen::includeNameDict;
10273 delete Doxygen::exampleNameDict;
10274 delete Doxygen::imageNameDict;
10275 delete Doxygen::dotFileNameDict;
10276 delete Doxygen::mscFileNameDict;
10277 delete Doxygen::diaFileNameDict;
10278 delete Doxygen::mainPage;
10279 delete Doxygen::pageSDict;
10280 delete Doxygen::exampleSDict;
10281 delete Doxygen::globalScope;
10282 delete Doxygen::xrefLists;
10283 delete Doxygen::parserManager;
10284 cleanUpPreprocessor();
10285 delete theTranslator;
10286 delete g_outputList;
10287 Mappers::freeMappers();
10290 if (Doxygen::symbolMap)
10292 // iterate through Doxygen::symbolMap and delete all
10293 // DefinitionList objects, since they have no owner
10294 QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
10295 DefinitionIntf *di;
10296 for (dli.toFirst();(di=dli.current());)
10298 if (di->definitionType()==DefinitionIntf::TypeSymbolList)
10300 DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
10301 delete (DefinitionList *)tmp;
10310 delete Doxygen::inputNameList;
10311 delete Doxygen::memberNameSDict;
10312 delete Doxygen::functionNameSDict;
10313 delete Doxygen::groupSDict;
10314 delete Doxygen::classSDict;
10315 delete Doxygen::hiddenClasses;
10316 delete Doxygen::namespaceSDict;
10317 delete Doxygen::directories;
10319 //delete Doxygen::symbolMap; <- we cannot do this unless all static lists
10320 // (such as Doxygen::namespaceSDict)
10321 // with objects based on Definition are made
10325 static int computeIdealCacheParam(uint v)
10327 //printf("computeIdealCacheParam(v=%u)\n",v);
10330 while (v!=0) v>>=1,r++;
10333 // convert to a valid cache size value
10334 return QMAX(0,QMIN(r-16,9));
10337 void readConfiguration(int argc, char **argv)
10339 /**************************************************************************
10340 * Handle arguments *
10341 **************************************************************************/
10344 const char *configName=0;
10345 const char *layoutName=0;
10346 const char *debugLabel;
10347 const char *formatName;
10348 const char *listName;
10349 bool genConfig=FALSE;
10350 bool shortList=FALSE;
10351 bool diffList=FALSE;
10352 bool updateConfig=FALSE;
10354 while (optind<argc && argv[optind][0]=='-' &&
10355 (isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
10356 argv[optind][1]=='-')
10359 switch(argv[optind][1])
10365 layoutName=getArg(argc,argv,optind);
10367 { layoutName="DoxygenLayout.xml"; }
10368 writeDefaultLayoutFile(layoutName);
10373 debugLabel=getArg(argc,argv,optind);
10376 err("option \"-d\" is missing debug specifier.\n");
10381 retVal = Debug::setFlag(debugLabel);
10384 err("option \"-d\" has unknown debug specifier: \"%s\".\n",debugLabel);
10399 formatName=getArg(argc,argv,optind);
10402 err("option \"-e\" is missing format specifier rtf.\n");
10406 if (qstricmp(formatName,"rtf")==0)
10408 if (optind+1>=argc)
10410 err("option \"-e rtf\" is missing an extensions file name\n");
10415 if (openOutputFile(argv[optind+1],f))
10417 RTFGenerator::writeExtensionsFile(f);
10422 err("option \"-e\" has invalid format specifier.\n");
10427 listName=getArg(argc,argv,optind);
10430 err("option \"-f\" is missing list specifier.\n");
10434 if (qstricmp(listName,"emoji")==0)
10436 if (optind+1>=argc)
10438 err("option \"-f emoji\" is missing an output file name\n");
10443 if (openOutputFile(argv[optind+1],f))
10445 EmojiEntityMapper::instance()->writeEmojiFile(f);
10450 err("option \"-f\" has invalid list specifier.\n");
10455 formatName=getArg(argc,argv,optind);
10458 err("option \"-w\" is missing format specifier rtf, html or latex\n");
10462 if (qstricmp(formatName,"rtf")==0)
10464 if (optind+1>=argc)
10466 err("option \"-w rtf\" is missing a style sheet file name\n");
10471 if (openOutputFile(argv[optind+1],f))
10473 RTFGenerator::writeStyleSheetFile(f);
10478 else if (qstricmp(formatName,"html")==0)
10481 if (optind+4<argc || QFileInfo("Doxyfile").exists())
10482 // explicit config file mentioned or default found on disk
10484 QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10485 if (!Config::parse(df)) // parse the config file
10487 err("error opening or reading configuration file %s!\n",argv[optind+4]);
10492 if (optind+3>=argc)
10494 err("option \"-w html\" does not have enough arguments\n");
10498 Config::postProcess(TRUE);
10499 Config::checkAndCorrect();
10501 QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10502 if (!setTranslator(outputLanguage))
10504 warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10508 if (openOutputFile(argv[optind+1],f))
10510 HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
10513 if (openOutputFile(argv[optind+2],f))
10515 HtmlGenerator::writeFooterFile(f);
10518 if (openOutputFile(argv[optind+3],f))
10520 HtmlGenerator::writeStyleSheetFile(f);
10525 else if (qstricmp(formatName,"latex")==0)
10528 if (optind+4<argc || QFileInfo("Doxyfile").exists())
10530 QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
10531 if (!Config::parse(df))
10533 err("error opening or reading configuration file %s!\n",argv[optind+4]);
10538 if (optind+3>=argc)
10540 err("option \"-w latex\" does not have enough arguments\n");
10544 Config::postProcess(TRUE);
10545 Config::checkAndCorrect();
10547 QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10548 if (!setTranslator(outputLanguage))
10550 warn_uncond("Output language %s not supported! Using English instead.\n", outputLanguage.data());
10554 if (openOutputFile(argv[optind+1],f))
10556 LatexGenerator::writeHeaderFile(f);
10559 if (openOutputFile(argv[optind+2],f))
10561 LatexGenerator::writeFooterFile(f);
10564 if (openOutputFile(argv[optind+3],f))
10566 LatexGenerator::writeStyleSheetFile(f);
10573 err("Illegal format specifier \"%s\": should be one of rtf, html or latex\n",formatName);
10579 g_dumpSymbolMap = TRUE;
10582 msg("%s\n",versionString);
10587 if (qstrcmp(&argv[optind][2],"help")==0)
10592 else if (qstrcmp(&argv[optind][2],"version")==0)
10594 msg("%s\n",versionString);
10600 err("Unknown option \"-%s\"\n",&argv[optind][1]);
10606 setvbuf(stdout,NULL,_IONBF,0);
10607 Doxygen::outputToWizard=TRUE;
10610 msg("Warning: this option activates output generation via Django like template files. "
10611 "This option is scheduled for doxygen 2.0, is currently incomplete and highly experimental! "
10612 "Only use if you are a doxygen developer\n");
10613 g_useOutputTemplate=TRUE;
10621 err("Unknown option \"-%c\"\n",argv[optind][1]);
10628 /**************************************************************************
10629 * Parse or generate the config file *
10630 **************************************************************************/
10634 QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
10637 if (configFileInfo1.exists())
10639 configName="Doxyfile";
10641 else if (configFileInfo2.exists())
10643 configName="doxyfile";
10645 else if (genConfig)
10647 configName="Doxyfile";
10651 err("Doxyfile not found and no input file specified!\n");
10658 QFileInfo fi(argv[optind]);
10659 if (fi.exists() || qstrcmp(argv[optind],"-")==0 || genConfig)
10661 configName=argv[optind];
10665 err("configuration file %s not found!\n",argv[optind]);
10671 if (genConfig && g_useOutputTemplate)
10673 generateTemplateFiles("templates");
10680 generateConfigFile(configName,shortList);
10685 if (!Config::parse(configName,updateConfig))
10687 err("could not open or read configuration file %s!\n",configName);
10701 generateConfigFile(configName,shortList,TRUE);
10706 /* Perlmod wants to know the path to the config file.*/
10707 QFileInfo configFileInfo(configName);
10708 setPerlModDoxyfile(configFileInfo.absFilePath().data());
10712 /** check and resolve config options */
10713 void checkConfiguration()
10716 Config::postProcess(FALSE);
10717 Config::checkAndCorrect();
10718 initWarningFormat();
10721 /** adjust globals that depend on configuration settings. */
10722 void adjustConfiguration()
10724 Doxygen::globalScope = new NamespaceDef("<globalScope>",1,1,"<globalScope>");
10725 Doxygen::inputNameDict = new FileNameDict(10007);
10726 Doxygen::includeNameDict = new FileNameDict(10007);
10727 Doxygen::exampleNameDict = new FileNameDict(1009);
10728 Doxygen::exampleNameDict->setAutoDelete(TRUE);
10729 Doxygen::imageNameDict = new FileNameDict(257);
10730 Doxygen::imageNameDict->setAutoDelete(TRUE);
10731 Doxygen::dotFileNameDict = new FileNameDict(257);
10732 Doxygen::dotFileNameDict->setAutoDelete(TRUE);
10733 Doxygen::mscFileNameDict = new FileNameDict(257);
10734 Doxygen::mscFileNameDict->setAutoDelete(TRUE);
10735 Doxygen::diaFileNameDict = new FileNameDict(257);
10736 Doxygen::diaFileNameDict->setAutoDelete(TRUE);
10738 QCString outputLanguage=Config_getEnum(OUTPUT_LANGUAGE);
10739 if (!setTranslator(outputLanguage))
10741 warn_uncond("Output language %s not supported! Using English instead.\n",
10742 outputLanguage.data());
10744 QStrList &includePath = Config_getList(INCLUDE_PATH);
10745 char *s=includePath.first();
10749 addSearchDir(fi.absFilePath().utf8());
10750 s=includePath.next();
10753 /* Set the global html file extension. */
10754 Doxygen::htmlFileExtension = Config_getString(HTML_FILE_EXTENSION);
10757 Doxygen::xrefLists->setAutoDelete(TRUE);
10759 Doxygen::parseSourcesNeeded = Config_getBool(CALL_GRAPH) ||
10760 Config_getBool(CALLER_GRAPH) ||
10761 Config_getBool(REFERENCES_RELATION) ||
10762 Config_getBool(REFERENCED_BY_RELATION);
10764 Doxygen::markdownSupport = Config_getBool(MARKDOWN_SUPPORT);
10766 /**************************************************************************
10767 * Add custom extension mappings
10768 **************************************************************************/
10770 QStrList &extMaps = Config_getList(EXTENSION_MAPPING);
10771 char *mapping = extMaps.first();
10774 QCString mapStr = mapping;
10776 if ((i=mapStr.find('='))!=-1)
10778 QCString ext=mapStr.left(i).stripWhiteSpace().lower();
10779 QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
10780 if (!updateLanguageMapping(ext,language))
10782 err("Failed to map file extension '%s' to unsupported language '%s'.\n"
10783 "Check the EXTENSION_MAPPING setting in the config file.\n",
10784 ext.data(),language.data());
10788 msg("Adding custom extension mapping: .%s will be treated as language %s\n",
10789 ext.data(),language.data());
10792 mapping = extMaps.next();
10796 // add predefined macro name to a dictionary
10797 QStrList &expandAsDefinedList =Config_getList(EXPAND_AS_DEFINED);
10798 s=expandAsDefinedList.first();
10801 if (Doxygen::expandAsDefinedDict[s]==0)
10803 Doxygen::expandAsDefinedDict.insert(s,(void *)666);
10805 s=expandAsDefinedList.next();
10808 // read aliases and store them in a dictionary
10811 // store number of spaces in a tab into Doxygen::spaces
10812 int &tabSize = Config_getInt(TAB_SIZE);
10813 Doxygen::spaces.resize(tabSize+1);
10814 int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
10815 Doxygen::spaces.at(tabSize)='\0';
10819 static void stopDoxygen(int)
10822 msg("Cleaning up...\n");
10823 if (!Doxygen::entryDBFileName.isEmpty())
10825 thisDir.remove(Doxygen::entryDBFileName);
10827 if (!Doxygen::objDBFileName.isEmpty())
10829 thisDir.remove(Doxygen::objDBFileName);
10831 if (!Doxygen::filterDBFileName.isEmpty())
10833 thisDir.remove(Doxygen::filterDBFileName);
10840 static void writeTagFile()
10842 QCString &generateTagFile = Config_getString(GENERATE_TAGFILE);
10843 if (generateTagFile.isEmpty()) return;
10845 QFile tag(generateTagFile);
10846 if (!tag.open(IO_WriteOnly))
10848 err("cannot open tag file %s for writing\n",
10849 generateTagFile.data()
10853 FTextStream tagFile(&tag);
10854 tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
10855 tagFile << "<tagfile>" << endl;
10858 FileNameListIterator fnli(*Doxygen::inputNameList);
10860 for (fnli.toFirst();(fn=fnli.current());++fnli)
10862 FileNameIterator fni(*fn);
10864 for (fni.toFirst();(fd=fni.current());++fni)
10866 if (fd->isLinkableInProject()) fd->writeTagFile(tagFile);
10870 ClassSDict::Iterator cli(*Doxygen::classSDict);
10872 for ( ; (cd=cli.current()) ; ++cli )
10874 if (cd->isLinkableInProject()) cd->writeTagFile(tagFile);
10876 // for each namespace
10877 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
10879 for ( ; (nd=nli.current()) ; ++nli )
10881 if (nd->isLinkableInProject()) nd->writeTagFile(tagFile);
10884 GroupSDict::Iterator gli(*Doxygen::groupSDict);
10886 for (gli.toFirst();(gd=gli.current());++gli)
10888 if (gd->isLinkableInProject()) gd->writeTagFile(tagFile);
10891 PageSDict::Iterator pdi(*Doxygen::pageSDict);
10893 for (pdi.toFirst();(pd=pdi.current());++pdi)
10895 if (pd->isLinkableInProject()) pd->writeTagFile(tagFile);
10897 if (Doxygen::mainPage) Doxygen::mainPage->writeTagFile(tagFile);
10900 if (Doxygen::mainPage && !Config_getString(GENERATE_TAGFILE).isEmpty())
10902 tagFile << " <compound kind=\"page\">" << endl
10904 << convertToXML(Doxygen::mainPage->name())
10905 << "</name>" << endl
10907 << convertToXML(Doxygen::mainPage->title())
10908 << "</title>" << endl
10910 << convertToXML(Doxygen::mainPage->getOutputFileBase())
10911 << "</filename>" << endl;
10913 mainPage->writeDocAnchorsToTagFile();
10914 tagFile << " </compound>" << endl;
10918 tagFile << "</tagfile>" << endl;
10921 static void exitDoxygen()
10923 if (!g_successfulRun) // premature exit
10926 msg("Exiting...\n");
10927 if (!Doxygen::entryDBFileName.isEmpty())
10929 thisDir.remove(Doxygen::entryDBFileName);
10931 if (!Doxygen::objDBFileName.isEmpty())
10933 thisDir.remove(Doxygen::objDBFileName);
10935 if (!Doxygen::filterDBFileName.isEmpty())
10937 thisDir.remove(Doxygen::filterDBFileName);
10942 static QCString createOutputDirectory(const QCString &baseDirName,
10943 QCString &formatDirName,
10944 const char *defaultDirName)
10946 // Note the & on the next line, we modify the formatDirOption!
10947 if (formatDirName.isEmpty())
10949 formatDirName = baseDirName + defaultDirName;
10951 else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
10953 formatDirName.prepend(baseDirName+'/');
10955 QDir formatDir(formatDirName);
10956 if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
10958 err("Could not create output directory %s\n", formatDirName.data());
10962 return formatDirName;
10965 static QCString getQchFileName()
10967 QCString const & qchFile = Config_getString(QCH_FILE);
10968 if (!qchFile.isEmpty())
10973 QCString const & projectName = Config_getString(PROJECT_NAME);
10974 QCString const & versionText = Config_getString(PROJECT_NUMBER);
10976 return QCString("../qch/")
10977 + (projectName.isEmpty() ? QCString("index") : projectName)
10978 + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
10979 + QCString(".qch");
10982 void searchInputFiles()
10984 QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
10985 bool alwaysRecursive = Config_getBool(RECURSIVE);
10986 StringDict excludeNameDict(1009);
10987 excludeNameDict.setAutoDelete(TRUE);
10989 // gather names of all files in the include path
10990 g_s.begin("Searching for include files...\n");
10991 QStrList &includePathList = Config_getList(INCLUDE_PATH);
10992 char *s=includePathList.first();
10995 QStrList &pl = Config_getList(INCLUDE_FILE_PATTERNS);
10998 pl = Config_getList(FILE_PATTERNS);
11000 readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
11003 s=includePathList.next();
11007 g_s.begin("Searching for example files...\n");
11008 QStrList &examplePathList = Config_getList(EXAMPLE_PATH);
11009 s=examplePathList.first();
11012 readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
11013 &Config_getList(EXAMPLE_PATTERNS),
11015 (alwaysRecursive || Config_getBool(EXAMPLE_RECURSIVE)));
11016 s=examplePathList.next();
11020 g_s.begin("Searching for images...\n");
11021 QStrList &imagePathList=Config_getList(IMAGE_PATH);
11022 s=imagePathList.first();
11025 readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
11028 s=imagePathList.next();
11032 g_s.begin("Searching for dot files...\n");
11033 QStrList &dotFileList=Config_getList(DOTFILE_DIRS);
11034 s=dotFileList.first();
11037 readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
11040 s=dotFileList.next();
11044 g_s.begin("Searching for msc files...\n");
11045 QStrList &mscFileList=Config_getList(MSCFILE_DIRS);
11046 s=mscFileList.first();
11049 readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
11052 s=mscFileList.next();
11056 g_s.begin("Searching for dia files...\n");
11057 QStrList &diaFileList=Config_getList(DIAFILE_DIRS);
11058 s=diaFileList.first();
11061 readFileOrDirectory(s,0,Doxygen::diaFileNameDict,0,0,
11064 s=diaFileList.next();
11068 g_s.begin("Searching for files to exclude\n");
11069 QStrList &excludeList = Config_getList(EXCLUDE);
11070 s=excludeList.first();
11073 readFileOrDirectory(s,0,0,0,&Config_getList(FILE_PATTERNS),
11074 0,0,&excludeNameDict,
11077 s=excludeList.next();
11081 /**************************************************************************
11082 * Determine Input Files *
11083 **************************************************************************/
11085 g_s.begin("Searching INPUT for files to process...\n");
11086 QDict<void> *killDict = new QDict<void>(10007);
11087 QStrList &inputList=Config_getList(INPUT);
11088 g_inputFiles.setAutoDelete(TRUE);
11089 s=inputList.first();
11093 uint l = path.length();
11096 // strip trailing slashes
11097 if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
11099 readFileOrDirectory(
11101 Doxygen::inputNameList,
11102 Doxygen::inputNameDict,
11104 &Config_getList(FILE_PATTERNS),
11110 &Doxygen::inputPaths);
11112 s=inputList.next();
11114 Doxygen::inputNameList->sort();
11122 atexit(exitDoxygen);
11125 /**************************************************************************
11126 * Make sure the output directory exists
11127 **************************************************************************/
11128 QCString &outputDirectory = Config_getString(OUTPUT_DIRECTORY);
11129 if (outputDirectory.isEmpty())
11131 outputDirectory=QDir::currentDirPath().utf8();
11135 QDir dir(outputDirectory);
11138 dir.setPath(QDir::currentDirPath());
11139 if (!dir.mkdir(outputDirectory))
11141 err("tag OUTPUT_DIRECTORY: Output directory `%s' does not "
11142 "exist and cannot be created\n",outputDirectory.data());
11148 msg("Notice: Output directory `%s' does not exist. "
11149 "I have created it for you.\n", outputDirectory.data());
11151 dir.cd(outputDirectory);
11153 outputDirectory=dir.absPath().utf8();
11156 /**************************************************************************
11157 * Initialize global lists and dictionaries
11158 **************************************************************************/
11160 Doxygen::symbolStorage = new Store;
11162 // also scale lookup cache with SYMBOL_CACHE_SIZE
11163 int cacheSize = Config_getInt(LOOKUP_CACHE_SIZE);
11164 if (cacheSize<0) cacheSize=0;
11165 if (cacheSize>9) cacheSize=9;
11166 uint lookupSize = 65536 << cacheSize;
11167 Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
11168 Doxygen::lookupCache->setAutoDelete(TRUE);
11171 signal(SIGINT, stopDoxygen);
11174 uint pid = portable_pid();
11175 Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
11176 Doxygen::objDBFileName.prepend(outputDirectory+"/");
11177 Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
11178 Doxygen::entryDBFileName.prepend(outputDirectory+"/");
11179 Doxygen::filterDBFileName.sprintf("doxygen_filterdb_%d.tmp",pid);
11180 Doxygen::filterDBFileName.prepend(outputDirectory+"/");
11182 if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
11184 err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
11190 /**************************************************************************
11191 * Check/create output directories *
11192 **************************************************************************/
11194 QCString htmlOutput;
11195 bool &generateHtml = Config_getBool(GENERATE_HTML);
11196 if (generateHtml || g_useOutputTemplate /* TODO: temp hack */)
11197 htmlOutput = createOutputDirectory(outputDirectory,Config_getString(HTML_OUTPUT),"/html");
11199 QCString docbookOutput;
11200 bool &generateDocbook = Config_getBool(GENERATE_DOCBOOK);
11201 if (generateDocbook)
11202 docbookOutput = createOutputDirectory(outputDirectory,Config_getString(DOCBOOK_OUTPUT),"/docbook");
11204 QCString xmlOutput;
11205 bool &generateXml = Config_getBool(GENERATE_XML);
11207 xmlOutput = createOutputDirectory(outputDirectory,Config_getString(XML_OUTPUT),"/xml");
11209 QCString latexOutput;
11210 bool &generateLatex = Config_getBool(GENERATE_LATEX);
11212 latexOutput = createOutputDirectory(outputDirectory,Config_getString(LATEX_OUTPUT),"/latex");
11214 QCString rtfOutput;
11215 bool &generateRtf = Config_getBool(GENERATE_RTF);
11217 rtfOutput = createOutputDirectory(outputDirectory,Config_getString(RTF_OUTPUT),"/rtf");
11219 QCString manOutput;
11220 bool &generateMan = Config_getBool(GENERATE_MAN);
11222 manOutput = createOutputDirectory(outputDirectory,Config_getString(MAN_OUTPUT),"/man");
11224 //QCString sqlOutput;
11225 //bool &generateSql = Config_getBool(GENERATE_SQLITE3);
11227 // sqlOutput = createOutputDirectory(outputDirectory,"SQLITE3_OUTPUT","/sqlite3");
11229 if (Config_getBool(HAVE_DOT))
11231 QCString curFontPath = Config_getString(DOT_FONTPATH);
11232 if (curFontPath.isEmpty())
11234 portable_getenv("DOTFONTPATH");
11235 QCString newFontPath = ".";
11236 if (!curFontPath.isEmpty())
11238 newFontPath+=portable_pathListSeparator();
11239 newFontPath+=curFontPath;
11241 portable_setenv("DOTFONTPATH",newFontPath);
11245 portable_setenv("DOTFONTPATH",curFontPath);
11251 /**************************************************************************
11252 * Handle layout file *
11253 **************************************************************************/
11255 LayoutDocManager::instance().init();
11256 QCString &layoutFileName = Config_getString(LAYOUT_FILE);
11257 bool defaultLayoutUsed = FALSE;
11258 if (layoutFileName.isEmpty())
11260 layoutFileName = "DoxygenLayout.xml";
11261 defaultLayoutUsed = TRUE;
11264 QFile layoutFile(layoutFileName);
11265 if (layoutFile.open(IO_ReadOnly))
11267 msg("Parsing layout file %s...\n",layoutFileName.data());
11268 QTextStream t(&layoutFile);
11269 t.setEncoding(QTextStream::Latin1);
11270 LayoutDocManager::instance().parse(t,layoutFileName);
11272 else if (!defaultLayoutUsed)
11274 warn_uncond("failed to open layout file '%s' for reading!\n",layoutFileName.data());
11277 /**************************************************************************
11278 * Read and preprocess input *
11279 **************************************************************************/
11281 // prevent search in the output directories
11282 QStrList &exclPatterns = Config_getList(EXCLUDE_PATTERNS);
11283 if (generateHtml) exclPatterns.append(htmlOutput);
11284 if (generateDocbook) exclPatterns.append(docbookOutput);
11285 if (generateXml) exclPatterns.append(xmlOutput);
11286 if (generateLatex) exclPatterns.append(latexOutput);
11287 if (generateRtf) exclPatterns.append(rtfOutput);
11288 if (generateMan) exclPatterns.append(manOutput);
11290 searchInputFiles();
11292 // Notice: the order of the function calls below is very important!
11294 if (Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX))
11296 readFormulaRepository(Config_getString(HTML_OUTPUT));
11298 if (Config_getBool(GENERATE_RTF))
11300 // in case GENERRATE_HTML is set we just have to compare, both repositories should be identical
11301 readFormulaRepository(Config_getString(RTF_OUTPUT),Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX));
11303 if (Config_getBool(GENERATE_DOCBOOK))
11305 // in case GENERRATE_HTML is set we just have to compare, both repositories should be identical
11306 readFormulaRepository(Config_getString(DOCBOOK_OUTPUT),
11307 (Config_getBool(GENERATE_HTML) && !Config_getBool(USE_MATHJAX)) || Config_getBool(GENERATE_RTF));
11310 /**************************************************************************
11311 * Handle Tag Files *
11312 **************************************************************************/
11314 g_storage = new FileStorage;
11315 g_storage->setName(Doxygen::entryDBFileName);
11316 if (!g_storage->open(IO_WriteOnly))
11318 err("Failed to create temporary storage file %s\n",
11319 Doxygen::entryDBFileName.data());
11322 Entry *root=new Entry;
11323 EntryNav *rootNav = new EntryNav(0,root);
11324 rootNav->setEntry(root);
11325 msg("Reading and parsing tag files\n");
11327 QStrList &tagFileList = Config_getList(TAGFILES);
11328 char *s=tagFileList.first();
11331 readTagFile(root,s);
11332 root->createNavigationIndex(rootNav,g_storage,0);
11333 s=tagFileList.next();
11336 /**************************************************************************
11337 * Parse source files *
11338 **************************************************************************/
11340 if (Config_getBool(BUILTIN_STL_SUPPORT))
11342 addSTLClasses(rootNav);
11345 g_s.begin("Parsing files\n");
11346 parseFiles(root,rootNav);
11347 g_storage->close();
11350 // we are done with input scanning now, so free up the buffers used by flex
11351 // (can be around 4MB)
11354 pyscanFreeScanner();
11356 if (!g_storage->open(IO_ReadOnly))
11358 err("Failed to open temporary storage file %s for reading",
11359 Doxygen::entryDBFileName.data());
11363 /**************************************************************************
11364 * Gather information *
11365 **************************************************************************/
11367 g_s.begin("Building group list...\n");
11368 buildGroupList(rootNav);
11369 organizeSubGroups(rootNav);
11372 g_s.begin("Building directory list...\n");
11373 buildDirectories();
11374 findDirDocumentation(rootNav);
11377 g_s.begin("Building namespace list...\n");
11378 buildNamespaceList(rootNav);
11379 findUsingDirectives(rootNav);
11382 g_s.begin("Building file list...\n");
11383 buildFileList(rootNav);
11385 //generateFileTree();
11387 g_s.begin("Building class list...\n");
11388 buildClassList(rootNav);
11391 g_s.begin("Associating documentation with classes...\n");
11392 buildClassDocList(rootNav);
11394 // build list of using declarations here (global list)
11395 buildListOfUsingDecls(rootNav);
11398 g_s.begin("Computing nesting relations for classes...\n");
11399 resolveClassNestingRelations();
11401 // 1.8.2-20121111: no longer add nested classes to the group as well
11402 //distributeClassGroupRelations();
11404 // calling buildClassList may result in cached relations that
11405 // become invalid after resolveClassNestingRelations(), that's why
11406 // we need to clear the cache here
11407 Doxygen::lookupCache->clear();
11408 // we don't need the list of using declaration anymore
11409 g_usingDeclarations.clear();
11411 g_s.begin("Building example list...\n");
11412 buildExampleList(rootNav);
11415 g_s.begin("Searching for enumerations...\n");
11416 findEnums(rootNav);
11419 // Since buildVarList calls isVarWithConstructor
11420 // and this calls getResolvedClass we need to process
11421 // typedefs first so the relations between classes via typedefs
11422 // are properly resolved. See bug 536385 for an example.
11423 g_s.begin("Searching for documented typedefs...\n");
11424 buildTypedefList(rootNav);
11427 if (Config_getBool(OPTIMIZE_OUTPUT_SLICE))
11429 g_s.begin("Searching for documented sequences...\n");
11430 buildSequenceList(rootNav);
11433 g_s.begin("Searching for documented dictionaries...\n");
11434 buildDictionaryList(rootNav);
11438 g_s.begin("Searching for members imported via using declarations...\n");
11439 // this should be after buildTypedefList in order to properly import
11441 findUsingDeclarations(rootNav);
11444 g_s.begin("Searching for included using directives...\n");
11445 findIncludedUsingDirectives();
11448 g_s.begin("Searching for documented variables...\n");
11449 buildVarList(rootNav);
11452 g_s.begin("Building interface member list...\n");
11453 buildInterfaceAndServiceList(rootNav); // UNO IDL
11455 g_s.begin("Building member list...\n"); // using class info only !
11456 buildFunctionList(rootNav);
11459 g_s.begin("Searching for friends...\n");
11463 g_s.begin("Searching for documented defines...\n");
11464 findDefineDocumentation(rootNav);
11467 g_s.begin("Computing class inheritance relations...\n");
11468 findClassEntries(rootNav);
11469 findInheritedTemplateInstances();
11472 g_s.begin("Computing class usage relations...\n");
11473 findUsedTemplateInstances();
11476 if (Config_getBool(INLINE_SIMPLE_STRUCTS))
11478 g_s.begin("Searching for tag less structs...\n");
11479 findTagLessClasses();
11483 g_s.begin("Flushing cached template relations that have become invalid...\n");
11484 flushCachedTemplateRelations();
11487 g_s.begin("Computing class relations...\n");
11488 computeTemplateClassRelations();
11489 flushUnresolvedRelations();
11490 if (Config_getBool(OPTIMIZE_OUTPUT_VHDL))
11492 VhdlDocGen::computeVhdlComponentRelations();
11494 computeClassRelations();
11495 g_classEntries.clear();
11498 g_s.begin("Add enum values to enums...\n");
11499 addEnumValuesToEnums(rootNav);
11500 findEnumDocumentation(rootNav);
11503 g_s.begin("Searching for member function documentation...\n");
11504 findObjCMethodDefinitions(rootNav);
11505 findMemberDocumentation(rootNav); // may introduce new members !
11506 findUsingDeclImports(rootNav); // may introduce new members !
11508 transferRelatedFunctionDocumentation();
11509 transferFunctionDocumentation();
11512 // moved to after finding and copying documentation,
11513 // as this introduces new members see bug 722654
11514 g_s.begin("Creating members for template instances...\n");
11515 createTemplateInstanceMembers();
11518 g_s.begin("Building page list...\n");
11519 buildPageList(rootNav);
11522 g_s.begin("Search for main page...\n");
11523 findMainPage(rootNav);
11524 findMainPageTagFiles(rootNav);
11527 g_s.begin("Computing page relations...\n");
11528 computePageRelations(rootNav);
11529 checkPageRelations();
11532 g_s.begin("Determining the scope of groups...\n");
11533 findGroupScope(rootNav);
11536 g_s.begin("Sorting lists...\n");
11537 Doxygen::memberNameSDict->sort();
11538 Doxygen::functionNameSDict->sort();
11539 Doxygen::hiddenClasses->sort();
11540 Doxygen::classSDict->sort();
11543 msg("Freeing entry tree\n");
11545 g_storage->close();
11550 thisDir.remove(Doxygen::entryDBFileName);
11552 g_s.begin("Determining which enums are documented\n");
11553 findDocumentedEnumValues();
11556 g_s.begin("Computing member relations...\n");
11558 computeMemberRelations();
11561 g_s.begin("Building full member lists recursively...\n");
11562 buildCompleteMemberLists();
11565 g_s.begin("Adding members to member groups.\n");
11566 addMembersToMemberGroup();
11569 if (Config_getBool(DISTRIBUTE_GROUP_DOC))
11571 g_s.begin("Distributing member group documentation.\n");
11572 distributeMemberGroupDocumentation();
11576 g_s.begin("Computing member references...\n");
11577 computeMemberReferences();
11580 if (Config_getBool(INHERIT_DOCS))
11582 g_s.begin("Inheriting documentation...\n");
11583 inheritDocumentation();
11587 // compute the shortest possible names of all files
11588 // without losing the uniqueness of the file names.
11589 g_s.begin("Generating disk names...\n");
11590 Doxygen::inputNameList->generateDiskNames();
11593 g_s.begin("Adding source references...\n");
11594 addSourceReferences();
11597 g_s.begin("Adding xrefitems...\n");
11598 addListReferences();
11599 generateXRefPages();
11602 g_s.begin("Sorting member lists...\n");
11606 if (Config_getBool(DIRECTORY_GRAPH))
11608 g_s.begin("Computing dependencies between directories...\n");
11609 computeDirDependencies();
11613 //g_s.begin("Resolving citations...\n");
11614 //Doxygen::citeDict->resolve();
11616 g_s.begin("Generating citations page...\n");
11617 Doxygen::citeDict->generatePage();
11620 g_s.begin("Counting data structures...\n");
11621 countDataStructures();
11624 g_s.begin("Resolving user defined references...\n");
11625 resolveUserReferences();
11628 g_s.begin("Finding anchors and sections in the documentation...\n");
11629 findSectionsInDocumentation();
11632 g_s.begin("Transferring function references...\n");
11633 transferFunctionReferences();
11636 g_s.begin("Combining using relations...\n");
11637 combineUsingRelations();
11640 g_s.begin("Adding members to index pages...\n");
11641 addMembersToIndex();
11645 void generateOutput()
11647 /**************************************************************************
11648 * Initialize output generators *
11649 **************************************************************************/
11651 /// add extra languages for which we can only produce syntax highlighted code
11652 addCodeOnlyMappings();
11654 //// dump all symbols
11655 if (g_dumpSymbolMap)
11661 initSearchIndexer();
11663 bool generateHtml = Config_getBool(GENERATE_HTML);
11664 bool generateLatex = Config_getBool(GENERATE_LATEX);
11665 bool generateMan = Config_getBool(GENERATE_MAN);
11666 bool generateRtf = Config_getBool(GENERATE_RTF);
11667 bool generateDocbook = Config_getBool(GENERATE_DOCBOOK);
11670 g_outputList = new OutputList(TRUE);
11673 g_outputList->add(new HtmlGenerator);
11674 HtmlGenerator::init();
11676 // add HTML indexers that are enabled
11677 bool generateHtmlHelp = Config_getBool(GENERATE_HTMLHELP);
11678 bool generateEclipseHelp = Config_getBool(GENERATE_ECLIPSEHELP);
11679 bool generateQhp = Config_getBool(GENERATE_QHP);
11680 bool generateTreeView = Config_getBool(GENERATE_TREEVIEW);
11681 bool generateDocSet = Config_getBool(GENERATE_DOCSET);
11682 if (generateEclipseHelp) Doxygen::indexList->addIndex(new EclipseHelp);
11683 if (generateHtmlHelp) Doxygen::indexList->addIndex(new HtmlHelp);
11684 if (generateQhp) Doxygen::indexList->addIndex(new Qhp);
11685 if (generateTreeView) Doxygen::indexList->addIndex(new FTVHelp(TRUE));
11686 if (generateDocSet) Doxygen::indexList->addIndex(new DocSets);
11687 Doxygen::indexList->initialize();
11688 HtmlGenerator::writeTabData();
11692 g_outputList->add(new LatexGenerator);
11693 LatexGenerator::init();
11695 if (generateDocbook)
11697 g_outputList->add(new DocbookGenerator);
11698 DocbookGenerator::init();
11702 g_outputList->add(new ManGenerator);
11703 ManGenerator::init();
11707 g_outputList->add(new RTFGenerator);
11708 RTFGenerator::init();
11710 if (Config_getBool(USE_HTAGS))
11712 Htags::useHtags = TRUE;
11713 QCString htmldir = Config_getString(HTML_OUTPUT);
11714 if (!Htags::execute(htmldir))
11715 err("USE_HTAGS is YES but htags(1) failed. \n");
11716 if (!Htags::loadFilemap(htmldir))
11717 err("htags(1) ended normally but failed to load the filemap. \n");
11720 /**************************************************************************
11721 * Generate documentation *
11722 **************************************************************************/
11724 if (generateHtml) writeDoxFont(Config_getString(HTML_OUTPUT));
11725 if (generateLatex) writeDoxFont(Config_getString(LATEX_OUTPUT));
11726 if (generateDocbook) writeDoxFont(Config_getString(DOCBOOK_OUTPUT));
11727 if (generateRtf) writeDoxFont(Config_getString(RTF_OUTPUT));
11729 g_s.begin("Generating style sheet...\n");
11730 //printf("writing style info\n");
11731 g_outputList->writeStyleInfo(0); // write first part
11734 static bool searchEngine = Config_getBool(SEARCHENGINE);
11735 static bool serverBasedSearch = Config_getBool(SERVER_BASED_SEARCH);
11737 g_s.begin("Generating search indices...\n");
11738 if (searchEngine && !serverBasedSearch && (generateHtml || g_useOutputTemplate))
11740 createJavascriptSearchIndex();
11743 // generate search indices (need to do this before writing other HTML
11744 // pages as these contain a drop down menu with options depending on
11745 // what categories we find in this function.
11746 if (generateHtml && searchEngine)
11748 QCString searchDirName = Config_getString(HTML_OUTPUT)+"/search";
11749 QDir searchDir(searchDirName);
11750 if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
11752 err("Could not create search results directory '%s' $PWD='%s'\n",
11753 searchDirName.data(),QDir::currentDirPath().data());
11756 HtmlGenerator::writeSearchData(searchDirName);
11757 if (!serverBasedSearch) // client side search index
11759 writeJavascriptSearchIndex();
11764 g_s.begin("Generating example documentation...\n");
11765 generateExampleDocs();
11768 if (!Htags::useHtags)
11770 g_s.begin("Generating file sources...\n");
11771 generateFileSources();
11775 g_s.begin("Generating file documentation...\n");
11776 generateFileDocs();
11779 g_s.begin("Generating page documentation...\n");
11780 generatePageDocs();
11783 g_s.begin("Generating group documentation...\n");
11784 generateGroupDocs();
11787 g_s.begin("Generating class documentation...\n");
11788 generateClassDocs();
11791 g_s.begin("Generating namespace index...\n");
11792 generateNamespaceDocs();
11795 if (Config_getBool(GENERATE_LEGEND))
11797 g_s.begin("Generating graph info page...\n");
11798 writeGraphInfo(*g_outputList);
11802 g_s.begin("Generating directory documentation...\n");
11803 generateDirDocs(*g_outputList);
11806 if (Doxygen::formulaList->count()>0 && generateHtml
11807 && !Config_getBool(USE_MATHJAX))
11809 g_s.begin("Generating bitmaps for formulas in HTML...\n");
11810 Doxygen::formulaList->generateBitmaps(Config_getString(HTML_OUTPUT));
11813 if (Doxygen::formulaList->count()>0 && generateRtf)
11815 g_s.begin("Generating bitmaps for formulas in RTF...\n");
11816 Doxygen::formulaList->generateBitmaps(Config_getString(RTF_OUTPUT));
11820 if (Doxygen::formulaList->count()>0 && generateDocbook)
11822 g_s.begin("Generating bitmaps for formulas in Docbook...\n");
11823 Doxygen::formulaList->generateBitmaps(Config_getString(DOCBOOK_OUTPUT));
11827 if (Config_getBool(SORT_GROUP_NAMES))
11829 Doxygen::groupSDict->sort();
11830 GroupSDict::Iterator gli(*Doxygen::groupSDict);
11832 for (gli.toFirst();(gd=gli.current());++gli)
11834 gd->sortSubGroups();
11838 if (g_outputList->count()>0)
11840 writeIndexHierarchy(*g_outputList);
11843 g_s.begin("finalizing index lists...\n");
11844 Doxygen::indexList->finalize();
11847 g_s.begin("writing tag file...\n");
11851 if (Config_getBool(DOT_CLEANUP))
11854 removeDoxFont(Config_getString(HTML_OUTPUT));
11856 removeDoxFont(Config_getString(RTF_OUTPUT));
11858 removeDoxFont(Config_getString(LATEX_OUTPUT));
11859 if (generateDocbook)
11860 removeDoxFont(Config_getString(DOCBOOK_OUTPUT));
11863 if (Config_getBool(GENERATE_XML))
11865 g_s.begin("Generating XML output...\n");
11866 Doxygen::generatingXmlOutput=TRUE;
11868 Doxygen::generatingXmlOutput=FALSE;
11873 g_s.begin("Generating SQLITE3 output...\n");
11878 if (Config_getBool(GENERATE_AUTOGEN_DEF))
11880 g_s.begin("Generating AutoGen DEF output...\n");
11884 if (Config_getBool(GENERATE_PERLMOD))
11886 g_s.begin("Generating Perl module output...\n");
11890 if (generateHtml && searchEngine && serverBasedSearch)
11892 g_s.begin("Generating search index\n");
11893 if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
11895 HtmlGenerator::writeSearchPage();
11896 Doxygen::searchIndex->write(Config_getString(HTML_OUTPUT)+"/search/search.idx");
11898 else // write data for external search index
11900 HtmlGenerator::writeExternalSearchPage();
11901 QCString searchDataFile = Config_getString(SEARCHDATA_FILE);
11902 if (searchDataFile.isEmpty())
11904 searchDataFile="searchdata.xml";
11906 if (!portable_isAbsolutePath(searchDataFile))
11908 searchDataFile.prepend(Config_getString(OUTPUT_DIRECTORY)+"/");
11910 Doxygen::searchIndex->write(searchDataFile);
11915 if (g_useOutputTemplate) generateOutputViaTemplate();
11919 g_s.begin("Combining RTF output...\n");
11920 if (!RTFGenerator::preProcessFileInplace(Config_getString(RTF_OUTPUT),"refman.rtf"))
11922 err("An error occurred during post-processing the RTF files!\n");
11927 if (Config_getBool(HAVE_DOT))
11929 g_s.begin("Running dot...\n");
11930 DotManager::instance()->run();
11934 // copy static stuff
11937 FTVHelp::generateTreeViewImages();
11939 copyLogo(Config_getString(HTML_OUTPUT));
11940 copyExtraFiles(Config_getList(HTML_EXTRA_FILES),"HTML_EXTRA_FILES",Config_getString(HTML_OUTPUT));
11944 copyLatexStyleSheet();
11945 copyLogo(Config_getString(LATEX_OUTPUT));
11946 copyExtraFiles(Config_getList(LATEX_EXTRA_FILES),"LATEX_EXTRA_FILES",Config_getString(LATEX_OUTPUT));
11948 if (generateDocbook)
11950 copyLogo(Config_getString(DOCBOOK_OUTPUT));
11954 copyLogo(Config_getString(RTF_OUTPUT));
11957 if (generateHtml &&
11958 Config_getBool(GENERATE_HTMLHELP) &&
11959 !Config_getString(HHC_LOCATION).isEmpty())
11961 g_s.begin("Running html help compiler...\n");
11962 QString oldDir = QDir::currentDirPath();
11963 QDir::setCurrent(Config_getString(HTML_OUTPUT));
11964 portable_sysTimerStart();
11965 if (portable_system(Config_getString(HHC_LOCATION), "index.hhp", Debug::isFlagSet(Debug::ExtCmd))!=1)
11967 err("failed to run html help compiler on index.hhp\n");
11969 portable_sysTimerStop();
11970 QDir::setCurrent(oldDir);
11973 if ( generateHtml &&
11974 Config_getBool(GENERATE_QHP) &&
11975 !Config_getString(QHG_LOCATION).isEmpty())
11977 g_s.begin("Running qhelpgenerator...\n");
11978 QCString const qhpFileName = Qhp::getQhpFileName();
11979 QCString const qchFileName = getQchFileName();
11981 QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
11982 QString const oldDir = QDir::currentDirPath();
11983 QDir::setCurrent(Config_getString(HTML_OUTPUT));
11984 portable_sysTimerStart();
11985 if (portable_system(Config_getString(QHG_LOCATION), args.data(), FALSE))
11987 err("failed to run qhelpgenerator on index.qhp\n");
11989 portable_sysTimerStop();
11990 QDir::setCurrent(oldDir);
11995 msg("lookup cache used %d/%d hits=%d misses=%d\n",
11996 Doxygen::lookupCache->count(),
11997 Doxygen::lookupCache->size(),
11998 Doxygen::lookupCache->hits(),
11999 Doxygen::lookupCache->misses());
12000 cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
12001 if (cacheParam>Config_getInt(LOOKUP_CACHE_SIZE))
12003 msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
12006 if (Debug::isFlagSet(Debug::Time))
12008 msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
12009 ((double)Doxygen::runningTime.elapsed())/1000.0,
12010 portable_getSysElapsedTime()
12016 msg("finished...\n");
12020 /**************************************************************************
12021 * Start cleaning up *
12022 **************************************************************************/
12026 finializeSearchIndexer();
12027 Doxygen::symbolStorage->close();
12029 thisDir.remove(Doxygen::objDBFileName);
12030 thisDir.remove(Doxygen::filterDBFileName);
12032 QTextCodec::deleteAllCodecs();
12033 delete Doxygen::symbolMap;
12034 delete Doxygen::clangUsrMap;
12035 delete Doxygen::symbolStorage;
12036 g_successfulRun=TRUE;