1 /******************************************************************************
3 * Copyright (C) 1997-2012 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.
17 #include <qfileinfo.h>
26 #include <qtextcodec.h>
41 #include "tagreader.h"
44 #include "docparser.h"
46 #include "outputlist.h"
60 #include "perlmodgen.h"
64 #include "commentcnv.h"
65 #include "cmdmapper.h"
66 #include "searchindex.h"
67 #include "parserintf.h"
69 #include "pyscanner.h"
70 #include "fortranscanner.h"
71 #include "dbusxmlscanner.h"
72 #include "tclscanner.h"
78 #include "vhdlscanner.h"
79 #include "vhdldocgen.h"
80 #include "eclipsehelp.h"
82 #include "filestorage.h"
84 #include "arguments.h"
88 #define RECURSE_ENTRYTREE(func,var) \
89 do { if (var->children()) { \
90 EntryNavListIterator eli(*var->children()); \
91 for (;eli.current();++eli) func(eli.current()); \
95 #if !defined(_WIN32) || defined(__CYGWIN__)
100 // globally accessible variables
101 ClassSDict *Doxygen::classSDict = 0;
102 ClassSDict *Doxygen::hiddenClasses = 0;
103 NamespaceSDict *Doxygen::namespaceSDict = 0;
104 MemberNameSDict *Doxygen::memberNameSDict = 0;
105 MemberNameSDict *Doxygen::functionNameSDict = 0;
106 FileNameList *Doxygen::inputNameList = 0; // all input files
107 FileNameDict *Doxygen::inputNameDict = 0;
108 GroupSDict *Doxygen::groupSDict = 0;
109 FormulaList Doxygen::formulaList; // all formulas
110 FormulaDict Doxygen::formulaDict(1009); // all formulas
111 FormulaDict Doxygen::formulaNameDict(1009); // the label name of all formulas
112 PageSDict *Doxygen::pageSDict = 0;
113 PageSDict *Doxygen::exampleSDict = 0;
114 SectionDict Doxygen::sectionDict(257); // all page sections
115 CiteDict *Doxygen::citeDict=0; // database of bibliographic references
116 StringDict Doxygen::aliasDict(257); // aliases
117 FileNameDict *Doxygen::includeNameDict = 0; // include names
118 FileNameDict *Doxygen::exampleNameDict = 0; // examples
119 FileNameDict *Doxygen::imageNameDict = 0; // images
120 FileNameDict *Doxygen::dotFileNameDict = 0; // dot files
121 FileNameDict *Doxygen::mscFileNameDict = 0; // dot files
122 StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases
123 StringDict Doxygen::tagDestinationDict(257); // all tag locations
124 QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
125 QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
126 PageDef *Doxygen::mainPage = 0;
127 bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
128 FTextStream Doxygen::tagFile;
129 NamespaceDef *Doxygen::globalScope = 0;
130 QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
131 bool Doxygen::parseSourcesNeeded = FALSE;
132 QTime Doxygen::runningTime;
133 SearchIndexIntf *Doxygen::searchIndex=0;
134 QDict<DefinitionIntf> *Doxygen::symbolMap;
135 bool Doxygen::outputToWizard=FALSE;
136 QDict<int> * Doxygen::htmlDirMap = 0;
137 QCache<LookupInfo> *Doxygen::lookupCache;
138 DirSDict *Doxygen::directories;
139 SDict<DirRelation> Doxygen::dirRelations(257);
140 ParserManager *Doxygen::parserManager = 0;
141 QCString Doxygen::htmlFileExtension;
142 bool Doxygen::suppressDocWarnings = FALSE;
143 ObjCache *Doxygen::symbolCache = 0;
144 Store *Doxygen::symbolStorage;
145 QCString Doxygen::objDBFileName;
146 QCString Doxygen::entryDBFileName;
147 bool Doxygen::gatherDefines = TRUE;
148 IndexList Doxygen::indexList;
149 int Doxygen::subpageNestingLevel = 0;
150 bool Doxygen::userComments = FALSE;
151 QCString Doxygen::spaces;
152 bool Doxygen::generatingXmlOutput = FALSE;
153 bool Doxygen::markdownSupport = TRUE;
154 GenericsSDict Doxygen::genericsDict;
156 // locally accessible globals
157 static QDict<EntryNav> g_classEntries(1009);
158 static StringList g_inputFiles;
159 static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds
160 static OutputList *g_outputList = 0; // list of output generating objects
161 static QDict<FileDef> g_usingDeclarations(1009); // used classes
162 static FileStorage *g_storage = 0;
163 static bool g_successfulRun = FALSE;
164 static bool g_dumpSymbolMap = FALSE;
165 static bool g_dumpConfigAsXML = FALSE;
169 g_inputFiles.clear();
170 //g_excludeNameDict.clear();
171 //delete g_outputList; g_outputList=0;
173 Doxygen::classSDict->clear();
174 Doxygen::namespaceSDict->clear();
175 Doxygen::pageSDict->clear();
176 Doxygen::exampleSDict->clear();
177 Doxygen::inputNameList->clear();
178 Doxygen::formulaList.clear();
179 Doxygen::sectionDict.clear();
180 Doxygen::inputNameDict->clear();
181 Doxygen::includeNameDict->clear();
182 Doxygen::exampleNameDict->clear();
183 Doxygen::imageNameDict->clear();
184 Doxygen::dotFileNameDict->clear();
185 Doxygen::mscFileNameDict->clear();
186 Doxygen::formulaDict.clear();
187 Doxygen::formulaNameDict.clear();
188 Doxygen::tagDestinationDict.clear();
189 delete Doxygen::citeDict;
190 delete Doxygen::mainPage; Doxygen::mainPage=0;
195 fprintf(stderr,"--- inputNameDict stats ----\n");
196 Doxygen::inputNameDict->statistics();
197 fprintf(stderr,"--- includeNameDict stats ----\n");
198 Doxygen::includeNameDict->statistics();
199 fprintf(stderr,"--- exampleNameDict stats ----\n");
200 Doxygen::exampleNameDict->statistics();
201 fprintf(stderr,"--- imageNameDict stats ----\n");
202 Doxygen::imageNameDict->statistics();
203 fprintf(stderr,"--- dotFileNameDict stats ----\n");
204 Doxygen::dotFileNameDict->statistics();
205 fprintf(stderr,"--- mscFileNameDict stats ----\n");
206 Doxygen::mscFileNameDict->statistics();
207 //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
208 //g_excludeNameDict.statistics();
209 fprintf(stderr,"--- aliasDict stats ----\n");
210 Doxygen::aliasDict.statistics();
211 fprintf(stderr,"--- typedefDict stats ----\n");
212 fprintf(stderr,"--- namespaceAliasDict stats ----\n");
213 Doxygen::namespaceAliasDict.statistics();
214 fprintf(stderr,"--- formulaDict stats ----\n");
215 Doxygen::formulaDict.statistics();
216 fprintf(stderr,"--- formulaNameDict stats ----\n");
217 Doxygen::formulaNameDict.statistics();
218 fprintf(stderr,"--- tagDestinationDict stats ----\n");
219 Doxygen::tagDestinationDict.statistics();
220 fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
221 g_compoundKeywordDict.statistics();
222 fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
223 Doxygen::expandAsDefinedDict.statistics();
224 fprintf(stderr,"--- memGrpInfoDict stats ----\n");
225 Doxygen::memGrpInfoDict.statistics();
230 static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
231 ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
232 static void findMember(EntryNav *rootNav,
238 /** A struct contained the data for an STL class */
241 const char *className;
242 const char *baseClass1;
243 const char *baseClass2;
244 const char *templType1;
245 const char *templName1;
246 const char *templType2;
247 const char *templName2;
248 bool virtualInheritance;
252 static STLInfo g_stlinfo[] =
254 // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators
255 { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
256 { "array", 0, 0, "T", "elements", 0, 0, FALSE, FALSE }, // C++11
257 { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // deprecated
258 { "smart_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
259 { "unique_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
260 { "weak_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE }, // C++11
261 { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
262 { "error_code", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
263 { "error_category", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
264 { "system_error", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
265 { "error_condition", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
266 { "thread", 0, 0, 0, 0, 0, 0, FALSE, FALSE }, // C++11
267 { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE },
268 { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
269 { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
270 { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE },
271 { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
272 { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
273 { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
274 { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
275 { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
276 { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
277 { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
278 { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
279 { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
280 { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
281 { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
282 { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
283 { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
284 { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
285 { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
286 { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
287 { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
288 { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
289 { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
290 { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
291 { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
292 { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
293 { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
294 { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
295 { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE },
296 { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE },
297 { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE },
298 { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
299 { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE },
300 { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
301 { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
302 { "forward_list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE }, // C++11
303 { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
304 { "unordered_map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
305 { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
306 { "unordered_multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE }, // C++11
307 { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
308 { "unordered_set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
309 { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
310 { "unordered_multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE }, // C++11
311 { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
312 { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
313 { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
314 { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
315 { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
316 { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
317 { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
318 { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
319 { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
320 { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
321 { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
322 { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
323 { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
324 { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
325 { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
326 { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
327 { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
328 { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
329 { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
330 { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
331 { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE }
334 static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
336 Entry *memEntry = new Entry;
337 memEntry->name = name;
338 memEntry->type = type;
339 memEntry->protection = Public;
340 memEntry->section = Entry::VARIABLE_SEC;
341 memEntry->brief = "STL member";
342 memEntry->hidden = FALSE;
343 memEntry->artificial = TRUE;
344 //memEntry->parent = root;
345 //root->addSubEntry(memEntry);
346 EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
347 memEntryNav->setEntry(memEntry);
348 rootNav->addChild(memEntryNav);
351 static void addSTLIterator(EntryNav *classEntryNav,const char *name)
353 Entry *iteratorClassEntry = new Entry;
354 iteratorClassEntry->fileName = "[STL]";
355 iteratorClassEntry->startLine = 1;
356 iteratorClassEntry->name = name;
357 iteratorClassEntry->section = Entry::CLASS_SEC;
358 iteratorClassEntry->brief = "STL iterator class";
359 iteratorClassEntry->hidden = FALSE;
360 iteratorClassEntry->artificial= TRUE;
361 EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
362 iteratorClassEntryNav->setEntry(iteratorClassEntry);
363 classEntryNav->addChild(iteratorClassEntryNav);
367 static void addSTLClasses(EntryNav *rootNav)
369 Entry *namespaceEntry = new Entry;
370 namespaceEntry->fileName = "[STL]";
371 namespaceEntry->startLine = 1;
372 //namespaceEntry->parent = rootNav->entry();
373 namespaceEntry->name = "std";
374 namespaceEntry->section = Entry::NAMESPACE_SEC;
375 namespaceEntry->brief = "STL namespace";
376 namespaceEntry->hidden = FALSE;
377 namespaceEntry->artificial= TRUE;
378 //root->addSubEntry(namespaceEntry);
379 EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
380 namespaceEntryNav->setEntry(namespaceEntry);
381 rootNav->addChild(namespaceEntryNav);
383 STLInfo *info = g_stlinfo;
384 while (info->className)
386 //printf("Adding STL class %s\n",info->className);
387 QCString fullName = info->className;
388 fullName.prepend("std::");
390 // add fake Entry for the class
391 Entry *classEntry = new Entry;
392 classEntry->fileName = "[STL]";
393 classEntry->startLine = 1;
394 classEntry->name = fullName;
395 //classEntry->parent = namespaceEntry;
396 classEntry->section = Entry::CLASS_SEC;
397 classEntry->brief = "STL class";
398 classEntry->hidden = FALSE;
399 classEntry->artificial= TRUE;
400 //namespaceEntry->addSubEntry(classEntry);
401 EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
402 classEntryNav->setEntry(classEntry);
403 namespaceEntryNav->addChild(classEntryNav);
405 // add template arguments to class
406 if (info->templType1)
408 ArgumentList *al = new ArgumentList;
409 Argument *a=new Argument;
411 a->name=info->templType1;
413 if (info->templType2) // another template argument
417 a->name=info->templType2;
420 classEntry->tArgLists = new QList<ArgumentList>;
421 classEntry->tArgLists->setAutoDelete(TRUE);
422 classEntry->tArgLists->append(al);
424 // add member variables
425 if (info->templName1)
427 addSTLMember(classEntryNav,info->templType1,info->templName1);
429 if (info->templName2)
431 addSTLMember(classEntryNav,info->templType2,info->templName2);
433 if (fullName=="std::auto_ptr" || fullName=="std::smart_ptr" ||
434 fullName=="std::unique_ptr" || fullName=="std::weak_ptr")
436 Entry *memEntry = new Entry;
437 memEntry->name = "operator->";
438 memEntry->args = "()";
439 memEntry->type = "T*";
440 memEntry->protection = Public;
441 memEntry->section = Entry::FUNCTION_SEC;
442 memEntry->brief = "STL member";
443 memEntry->hidden = FALSE;
444 memEntry->artificial = FALSE;
445 EntryNav *memEntryNav = new EntryNav(classEntryNav,memEntry);
446 memEntryNav->setEntry(memEntry);
447 classEntryNav->addChild(memEntryNav);
449 if (info->baseClass1)
451 classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
453 if (info->baseClass2)
455 classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
459 // add iterator class
460 addSTLIterator(classEntryNav,fullName+"::iterator");
461 addSTLIterator(classEntryNav,fullName+"::const_iterator");
462 addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
463 addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
469 //----------------------------------------------------------------------------
471 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
472 FileDef *fileScope=0);
474 static void addPageToContext(PageDef *pd,EntryNav *rootNav)
476 if (rootNav->parent()) // add the page to it's scope
478 QCString scope = rootNav->parent()->name();
479 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
481 scope=substitute(scope,".","::");
483 scope = stripAnonymousNamespaceScope(scope);
484 scope+="::"+pd->name();
485 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
493 static void addRelatedPage(EntryNav *rootNav)
495 Entry *root = rootNav->entry();
497 QListIterator<Grouping> gli(*root->groups);
499 for (;(g=gli.current());++gli)
501 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
503 //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
505 if (root->brief.isEmpty())
507 doc=root->doc+root->inbodyDocs;
511 doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
513 PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
514 root->docFile,root->docLine,
516 gd,rootNav->tagInfo(),
521 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
522 pd->addSectionsToDefinition(root->anchors);
523 pd->setShowToc(root->stat);
524 addPageToContext(pd,rootNav);
528 static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
530 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
531 ((!includeExternal && rootNav->tagInfo()==0) ||
532 ( includeExternal && rootNav->tagInfo()!=0))
535 rootNav->loadEntry(g_storage);
536 Entry *root = rootNav->entry();
538 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
539 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
541 GroupDef *gd = Doxygen::groupSDict->find(root->name);
542 //printf("Processing group '%s':'%s' add=%d ext=%d gd=%p\n",
543 // root->type.data(),root->name.data(),additional,includeExternal,gd);
547 if ( !gd->hasGroupTitle() )
549 gd->setGroupTitle( root->type );
551 else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
553 warn( root->fileName,root->startLine,
554 "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
555 qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
557 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
558 gd->setDocumentation( root->doc, root->docFile, root->docLine );
559 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
560 gd->addSectionsToDefinition(root->anchors);
561 gd->setRefItems(root->sli);
562 gd->setLanguage(root->lang);
566 if (rootNav->tagInfo())
568 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
569 gd->setReference(rootNav->tagInfo()->tagName);
573 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
575 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
576 // allow empty docs for group
577 gd->setDocumentation(!root->doc.isEmpty() ? root->doc : QCString(" "),root->docFile,root->docLine,FALSE);
578 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
579 gd->addSectionsToDefinition(root->anchors);
580 Doxygen::groupSDict->append(root->name,gd);
581 gd->setRefItems(root->sli);
582 gd->setLanguage(root->lang);
586 rootNav->releaseEntry();
588 if (rootNav->children())
590 EntryNavListIterator eli(*rootNav->children());
592 for (;(e=eli.current());++eli)
594 buildGroupListFiltered(e,additional,includeExternal);
599 static void buildGroupList(EntryNav *rootNav)
601 // --- first process only local groups
602 // first process the @defgroups blocks
603 buildGroupListFiltered(rootNav,FALSE,FALSE);
604 // then process the @addtogroup, @weakgroup blocks
605 buildGroupListFiltered(rootNav,TRUE,FALSE);
607 // --- then also process external groups
608 // first process the @defgroups blocks
609 buildGroupListFiltered(rootNav,FALSE,TRUE);
610 // then process the @addtogroup, @weakgroup blocks
611 buildGroupListFiltered(rootNav,TRUE,TRUE);
614 static void findGroupScope(EntryNav *rootNav)
616 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
617 rootNav->parent() && !rootNav->parent()->name().isEmpty())
620 if ((gd=Doxygen::groupSDict->find(rootNav->name())))
622 QCString scope = rootNav->parent()->name();
623 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
625 scope=substitute(scope,".","::");
627 scope = stripAnonymousNamespaceScope(scope);
628 scope+="::"+gd->name();
629 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
632 gd->setGroupScope(d);
636 RECURSE_ENTRYTREE(findGroupScope,rootNav);
639 static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
641 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
643 rootNav->loadEntry(g_storage);
644 Entry *root = rootNav->entry();
646 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
647 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
650 if ((gd=Doxygen::groupSDict->find(root->name)))
652 //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
653 addGroupToGroups(root,gd);
657 rootNav->releaseEntry();
659 if (rootNav->children())
661 EntryNavListIterator eli(*rootNav->children());
663 for (;(e=eli.current());++eli)
665 organizeSubGroupsFiltered(e,additional);
670 static void organizeSubGroups(EntryNav *rootNav)
672 //printf("Defining groups\n");
673 // first process the @defgroups blocks
674 organizeSubGroupsFiltered(rootNav,FALSE);
675 //printf("Additional groups\n");
676 // then process the @addtogroup, @weakgroup blocks
677 organizeSubGroupsFiltered(rootNav,TRUE);
680 //----------------------------------------------------------------------
682 static void buildFileList(EntryNav *rootNav)
684 if (((rootNav->section()==Entry::FILEDOC_SEC) ||
685 ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
686 !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
689 rootNav->loadEntry(g_storage);
690 Entry *root = rootNav->entry();
693 FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
694 //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
698 if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
699 (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
702 root->fileName,root->startLine,
703 "warning: file %s already documented. "
704 "Skipping documentation.",
711 //printf("Adding documentation!\n");
712 // using FALSE in setDocumentation is small hack to make sure a file
713 // is documented even if a \file command is used without further
715 fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
716 fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
717 fd->addSectionsToDefinition(root->anchors);
718 fd->setRefItems(root->sli);
719 QListIterator<Grouping> gli(*root->groups);
721 for (;(g=gli.current());++gli)
724 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
727 fd->makePartOfGroup(gd);
728 //printf("File %s: in group %s\n",fd->name().data(),s->data());
735 const char *fn = root->fileName.data();
737 text.sprintf("warning: the name `%s' supplied as "
738 "the second argument in the \\file statement ",
740 if (ambig) // name is ambiguous
742 text+="matches the following input files:\n";
743 text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
744 text+="Please use a more specific name by "
745 "including a (larger) part of the path!";
747 else // name is not an input file
749 text+="is not an input file";
751 warn(fn,root->startLine,text);
754 rootNav->releaseEntry();
756 RECURSE_ENTRYTREE(buildFileList,rootNav);
759 static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
762 (!root->doc.stripWhiteSpace().isEmpty() ||
763 !root->brief.stripWhiteSpace().isEmpty() ||
764 Config_getBool("EXTRACT_ALL")
765 ) && root->protection!=Private
768 //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
770 bool local=Config_getBool("FORCE_LOCAL_INCLUDES");
771 QCString includeFile = root->includeFile;
772 if (!includeFile.isEmpty() && includeFile.at(0)=='"')
775 includeFile=includeFile.mid(1,includeFile.length()-2);
777 else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
780 includeFile=includeFile.mid(1,includeFile.length()-2);
785 // see if we need to include a verbatim copy of the header file
786 //printf("root->includeFile=%s\n",root->includeFile.data());
787 if (!includeFile.isEmpty() &&
788 (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
790 { // explicit request
792 text.sprintf("warning: the name `%s' supplied as "
793 "the argument of the \\class, \\struct, \\union, or \\include command ",
796 if (ambig) // name is ambiguous
798 text+="matches the following input files:\n";
799 text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
800 text+="Please use a more specific name by "
801 "including a (larger) part of the path!";
803 else // name is not an input file
805 text+="is not an input file";
807 warn(root->fileName,root->startLine,text);
809 else if (includeFile.isEmpty() && ifd &&
810 // see if the file extension makes sense
811 guessSection(ifd->name())==Entry::HEADER_SEC)
812 { // implicit assumption
816 // if a file is found, we mark it as a source file.
819 QCString iName = !root->includeName.isEmpty() ?
820 root->includeName : includeFile;
821 if (!iName.isEmpty()) // user specified include file
823 if (iName.at(0)=='<') local=FALSE; // explicit override
824 else if (iName.at(0)=='"') local=TRUE;
825 if (iName.at(0)=='"' || iName.at(0)=='<')
827 iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
834 else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty())
836 iName=stripFromIncludePath(fd->absFilePath());
838 else // use name of the file containing the class definition
842 if (fd->generateSourceFile()) // generate code for header
844 cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
846 else // put #include in the class documentation without link
848 cd->setIncludeFile(0,iName,local,TRUE);
855 static bool addNamespace(Entry *root,ClassDef *cd)
857 // see if this class is defined inside a namespace
858 if (root->section & Entry::COMPOUND_MASK)
860 Entry *e = root->parent;
863 if (e->section==Entry::NAMESPACE_SEC)
866 QCString nsName = stripAnonymousNamespaceScope(e->name);
867 //printf("addNameSpace() trying: %s\n",nsName.data());
868 if (!nsName.isEmpty() && nsName.at(0)!='@' &&
869 (nd=getResolvedNamespace(nsName))
872 cd->setNamespace(nd);
873 cd->setOuterScope(nd);
886 static Definition *findScope(Entry *root,int level=0)
888 if (root==0) return 0;
889 //printf("start findScope name=%s\n",root->name.data());
890 Definition *result=0;
891 if (root->section&Entry::SCOPE_MASK)
893 result = findScope(root->parent,level+1); // traverse to the root of the tree
896 //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
897 // TODO: look at template arguments
898 result = result->findInnerCompound(root->name);
900 else // reached the global scope
902 // TODO: look at template arguments
903 result = Doxygen::globalScope->findInnerCompound(root->name);
904 //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
907 //printf("end findScope(%s,%d)=%s\n",root->name.data(),
908 // level,result==0 ? "<none>" : result->name().data());
913 /*! returns the Definition object belonging to the first \a level levels of
914 * full qualified name \a name. Creates an artificial scope if the scope is
915 * not found and set the parent/child scope relation if the scope is found.
917 static Definition *buildScopeFromQualifiedName(const QCString name,int level,SrcLangExt lang)
921 Definition *prevScope=Doxygen::globalScope;
925 int idx=getScopeFragment(name,p,&l);
926 QCString nsName = name.mid(idx,l);
927 if (nsName.isEmpty()) return prevScope;
928 if (!fullScope.isEmpty()) fullScope+="::";
930 NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
931 Definition *innerScope = nd;
933 if (nd==0) cd = getClass(fullScope);
934 if (nd==0 && cd) // scope is a class
938 else if (nd==0 && cd==0) // scope is not known!
940 // introduce bogus namespace
941 //printf("++ adding dummy namespace %s to %s\n",nsName.data(),prevScope->name().data());
943 "[generated]",1,fullScope);
944 nd->setLanguage(lang);
946 // add namespace to the list
947 Doxygen::namespaceSDict->inSort(fullScope,nd);
950 else // scope is a namespace
953 // make the parent/child scope relation
954 prevScope->addInnerCompound(innerScope);
955 innerScope->setOuterScope(prevScope);
956 // proceed to the next scope fragment
958 prevScope=innerScope;
964 static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
967 //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
968 Definition *resultScope=startScope;
969 if (resultScope==0) resultScope=Doxygen::globalScope;
970 QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
972 i1=getScopeFragment(scope,0,&l1);
975 //printf(">no fragments!\n");
979 while ((i2=getScopeFragment(scope,p,&l2))!=-1)
981 QCString nestedNameSpecifier = scope.mid(i1,l1);
982 Definition *orgScope = resultScope;
983 //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
984 resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
985 //printf(" resultScope=%p\n",resultScope);
988 NamespaceSDict *usedNamespaces;
989 if (orgScope==Doxygen::globalScope && fileScope &&
990 (usedNamespaces = fileScope->getUsedNamespaces()))
991 // also search for used namespaces
993 NamespaceSDict::Iterator ni(*usedNamespaces);
995 for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
997 // restart search within the used namespace
998 resultScope = findScopeFromQualifiedName(nd,n,fileScope);
1002 // for a nested class A::I in used namespace N, we get
1003 // N::A::I while looking for A, so we should compare
1004 // resultScope->name() against scope.left(i2+l2)
1005 //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
1006 if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
1014 // also search for used classes. Complication: we haven't been able
1015 // to put them in the right scope yet, because we are still resolving
1016 // the scope relations!
1017 // Therefore loop through all used classes and see if there is a right
1018 // scope match between the used class and nestedNameSpecifier.
1019 QDictIterator<FileDef> ui(g_usingDeclarations);
1021 for (ui.toFirst();(usedFd=ui.current());++ui)
1023 //printf("Checking using class %s\n",ui.currentKey());
1024 if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
1026 // ui.currentKey() is the fully qualified name of nestedNameSpecifier
1027 // so use this instead.
1028 QCString fqn = QCString(ui.currentKey())+
1029 scope.right(scope.length()-p);
1030 resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"),startScope->getLanguage());
1031 //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
1034 //printf("> Match! resultScope=%s\n",resultScope->name().data());
1040 //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
1048 //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1052 ArgumentList *getTemplateArgumentsFromName(
1053 const QCString &name,
1054 const QList<ArgumentList> *tArgLists)
1056 if (tArgLists==0) return 0;
1058 QListIterator<ArgumentList> ali(*tArgLists);
1059 // for each scope fragment, check if it is a template and advance through
1062 while ((i=name.find("::",p))!=-1)
1064 NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1067 ClassDef *cd = getClass(name.left(i));
1070 if (cd->templateArguments())
1078 return ali.current();
1081 static ClassDef::CompoundType convertToCompoundType(int section,int specifier)
1083 ClassDef::CompoundType sec=ClassDef::Class;
1084 if (specifier&Entry::Struct)
1085 sec=ClassDef::Struct;
1086 else if (specifier&Entry::Union)
1087 sec=ClassDef::Union;
1088 else if (specifier&Entry::Category)
1089 sec=ClassDef::Category;
1090 else if (specifier&Entry::Interface)
1091 sec=ClassDef::Interface;
1092 else if (specifier&Entry::Protocol)
1093 sec=ClassDef::Protocol;
1094 else if (specifier&Entry::Exception)
1095 sec=ClassDef::Exception;
1099 //case Entry::UNION_SEC:
1100 case Entry::UNIONDOC_SEC:
1101 sec=ClassDef::Union;
1103 //case Entry::STRUCT_SEC:
1104 case Entry::STRUCTDOC_SEC:
1105 sec=ClassDef::Struct;
1107 //case Entry::INTERFACE_SEC:
1108 case Entry::INTERFACEDOC_SEC:
1109 sec=ClassDef::Interface;
1111 //case Entry::PROTOCOL_SEC:
1112 case Entry::PROTOCOLDOC_SEC:
1113 sec=ClassDef::Protocol;
1115 //case Entry::CATEGORY_SEC:
1116 case Entry::CATEGORYDOC_SEC:
1117 sec=ClassDef::Category;
1119 //case Entry::EXCEPTION_SEC:
1120 case Entry::EXCEPTIONDOC_SEC:
1121 sec=ClassDef::Exception;
1128 static void addClassToContext(EntryNav *rootNav)
1130 //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1131 rootNav->loadEntry(g_storage);
1132 Entry *root = rootNav->entry();
1134 //NamespaceDef *nd = 0;
1135 FileDef *fd = rootNav->fileDef();
1138 if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1140 scName=rootNav->parent()->name();
1142 // name without parent's scope
1143 QCString fullName = root->name;
1145 // strip off any template parameters (but not those for specializations)
1146 fullName=stripTemplateSpecifiersFromScope(fullName);
1148 // name with scope (if not present already)
1149 QCString qualifiedName = fullName;
1150 if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1152 qualifiedName.prepend(scName+"::");
1155 // see if we already found the class before
1156 ClassDef *cd = getClass(qualifiedName);
1158 Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1159 cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);
1163 fullName=cd->name();
1164 Debug::print(Debug::Classes,0," Existing class %s!\n",cd->name().data());
1165 //if (cd->templateArguments()==0)
1167 // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1168 // cd->setTemplateArguments(tArgList);
1171 cd->setDocumentation(root->doc,root->docFile,root->docLine);
1172 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1174 if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1176 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1179 //cd->setName(fullName); // change name to match docs
1181 if (cd->templateArguments()==0)
1183 // this happens if a template class declared with @class is found
1184 // before the actual definition.
1185 ArgumentList *tArgList =
1186 getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1187 cd->setTemplateArguments(tArgList);
1190 cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1194 ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1197 QCString namespaceName;
1198 extractNamespaceName(fullName,className,namespaceName);
1200 //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1201 // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1204 QCString refFileName;
1205 if (rootNav->tagInfo())
1207 tagName = rootNav->tagInfo()->tagName;
1208 refFileName = rootNav->tagInfo()->fileName;
1210 cd=new ClassDef(root->fileName,root->startLine,fullName,sec,
1211 tagName,refFileName,TRUE,root->spec&Entry::Enum);
1212 Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d\n",
1213 fullName.data(),sec,root->tArgLists ? (int)root->tArgLists->count() : -1);
1214 cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1215 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1216 cd->setLanguage(root->lang);
1217 cd->setHidden(root->hidden);
1218 cd->setArtificial(root->artificial);
1219 cd->setClassSpecifier(root->spec);
1220 cd->setTypeConstraints(root->typeConstr);
1221 //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1223 ArgumentList *tArgList =
1224 getTemplateArgumentsFromName(fullName,root->tArgLists);
1225 //printf("class %s template args=%s\n",fullName.data(),
1226 // tArgList ? tempArgListToString(tArgList).data() : "<none>");
1227 cd->setTemplateArguments(tArgList);
1228 cd->setProtection(root->protection);
1229 cd->setIsStatic(root->stat);
1231 // file definition containing the class cd
1232 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1235 // see if the class is found inside a namespace
1236 //bool found=addNamespace(root,cd);
1238 // the empty string test is needed for extract all case
1239 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1240 cd->insertUsedFile(root->fileName);
1242 // add class to the list
1243 //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
1244 Doxygen::classSDict->append(fullName,cd);
1246 if (cd->isGeneric()) // generics are also stored in a separate dictionary for fast lookup of instantions
1248 Doxygen::genericsDict.insert(fullName,cd);
1252 cd->addSectionsToDefinition(root->anchors);
1253 if (!root->subGrouping) cd->setSubGrouping(FALSE);
1254 if (cd->hasDocumentation())
1256 addIncludeFile(cd,fd,root);
1258 if (fd && (root->section & Entry::COMPOUND_MASK))
1260 //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1261 // cd->name().data(),
1262 // fd->name().data(),
1263 // root->fileName.data()
1266 fd->insertClass(cd);
1268 addClassToGroups(root,cd);
1269 cd->setRefItems(root->sli);
1271 rootNav->releaseEntry();
1274 //----------------------------------------------------------------------
1275 // build a list of all classes mentioned in the documentation
1276 // and all classes that have a documentation block before their definition.
1277 static void buildClassList(EntryNav *rootNav)
1280 ((rootNav->section() & Entry::COMPOUND_MASK) ||
1281 rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1284 addClassToContext(rootNav);
1286 RECURSE_ENTRYTREE(buildClassList,rootNav);
1289 static void buildClassDocList(EntryNav *rootNav)
1292 (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1295 addClassToContext(rootNav);
1297 RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1300 static void resolveClassNestingRelations()
1302 ClassSDict::Iterator cli(*Doxygen::classSDict);
1303 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1312 for (cli.toFirst();(cd=cli.current());++cli)
1316 QCString name = stripAnonymousNamespaceScope(cd->name());
1317 //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1318 // also add class to the correct structural context
1319 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1320 name,cd->getFileDef());
1323 //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1324 d->addInnerCompound(cd);
1325 cd->setOuterScope(d);
1331 // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1337 //give warnings for unresolved compounds
1339 for (cli.toFirst();(cd=cli.current());++cli)
1343 QCString name = stripAnonymousNamespaceScope(cd->name());
1344 //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1345 /// create the scope artificially
1346 // anyway, so we can at least relate scopes properly.
1347 Definition *d = buildScopeFromQualifiedName(name,name.contains("::"),cd->getLanguage());
1348 if (d!=cd && !cd->getDefFileName().isEmpty())
1349 // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1350 // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1351 // also avoid warning for stuff imported via a tagfile.
1353 d->addInnerCompound(cd);
1354 cd->setOuterScope(d);
1355 warn(cd->getDefFileName(),cd->getDefLine(),
1356 "warning: Internal inconsistency: scope for class %s not "
1357 "found!",name.data()
1364 void distributeClassGroupRelations()
1366 //static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES");
1367 //if (!inlineGroupedClasses) return;
1368 //printf("** distributeClassGroupRelations()\n");
1370 ClassSDict::Iterator cli(*Doxygen::classSDict);
1371 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1374 for (cli.toFirst();(cd=cli.current());++cli)
1376 //printf("Checking %s\n",cd->name().data());
1377 // distribute the group to nested classes as well
1378 if (!cd->visited && cd->partOfGroups()!=0 && cd->getClassSDict())
1380 //printf(" Candidate for merging\n");
1381 ClassSDict::Iterator ncli(*cd->getClassSDict());
1383 GroupDef *gd = cd->partOfGroups()->at(0);
1384 for (ncli.toFirst();(ncd=ncli.current());++ncli)
1386 if (ncd->partOfGroups()==0)
1388 //printf(" Adding %s to group '%s'\n",ncd->name().data(),
1389 // gd->groupTitle());
1390 ncd->makePartOfGroup(gd);
1394 cd->visited=TRUE; // only visit every class once
1399 //----------------------------
1401 static ClassDef *createTagLessInstance(ClassDef *rootCd,ClassDef *templ,const QCString &fieldName)
1403 QCString fullName = removeAnonymousScopes(templ->name());
1404 if (fullName.right(2)=="::") fullName=fullName.left(fullName.length()-2);
1405 fullName+="."+fieldName;
1406 ClassDef *cd = new ClassDef(templ->getDefFileName(),
1407 templ->getDefLine(),
1409 templ->compoundType());
1410 cd->setDocumentation(templ->documentation(),templ->docFile(),templ->docLine()); // copy docs to definition
1411 cd->setBriefDescription(templ->briefDescription(),templ->briefFile(),templ->briefLine());
1412 cd->setLanguage(templ->getLanguage());
1413 cd->setBodySegment(templ->getStartBodyLine(),templ->getEndBodyLine());
1414 cd->setBodyDef(templ->getBodyDef());
1416 cd->setOuterScope(rootCd->getOuterScope());
1417 if (rootCd->getOuterScope()!=Doxygen::globalScope)
1419 rootCd->getOuterScope()->addInnerCompound(cd);
1422 FileDef *fd = templ->getFileDef();
1426 fd->insertClass(cd);
1428 LockingPtr<GroupList> groups = rootCd->partOfGroups();
1431 GroupListIterator gli(*groups);
1433 for (gli.toFirst();(gd=gli.current());++gli)
1435 cd->makePartOfGroup(gd);
1439 //cd->insertUsedFile(root->fileName);
1440 //printf("** adding class %s based on %s\n",fullName.data(),templ->name().data());
1441 Doxygen::classSDict->append(fullName,cd);
1443 MemberList *ml = templ->getMemberList(MemberList::pubAttribs);
1446 MemberListIterator li(*ml);
1448 for (li.toFirst();(md=li.current());++li)
1450 //printf(" Member %s type=%s\n",md->name().data(),md->typeString());
1451 MemberDef *imd = new MemberDef(md->getDefFileName(),md->getDefLine(),
1452 md->typeString(),md->name(),md->argsString(),md->excpString(),
1453 md->protection(),md->virtualness(),md->isStatic(),Member,
1456 imd->setMemberClass(cd);
1457 imd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1458 imd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1459 imd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1460 imd->setMemberSpecifiers(md->getMemberSpecifiers());
1461 imd->setMemberGroupId(md->getMemberGroupId());
1462 imd->setInitializer(md->initializer());
1463 imd->setMaxInitLines(md->initializerLines());
1464 imd->setBitfields(md->bitfieldString());
1465 imd->setLanguage(md->getLanguage());
1466 cd->insertMember(imd);
1472 /** Look through the members of class \a cd and its public members.
1473 * If there is a member m of a tag less struct/union,
1474 * then we create a duplicate of the struct/union with the name of the
1475 * member to identify it.
1476 * So if cd has name S, then the tag less struct/union will get name S.m
1477 * Since tag less structs can be nested we need to call this function
1478 * recursively. Later on we need to patch the member types so we keep
1479 * track of the hierarchy of classes we create.
1481 static void processTagLessClasses(ClassDef *rootCd,
1483 ClassDef *tagParentCd,
1484 const QCString &prefix,int count)
1486 //printf("%d: processTagLessClasses %s\n",count,cd->name().data());
1487 //printf("checking members for %s\n",cd->name().data());
1488 if (cd->getClassSDict())
1490 MemberList *ml = cd->getMemberList(MemberList::pubAttribs);
1493 MemberListIterator li(*ml);
1495 for (li.toFirst();(md=li.current());++li)
1497 QCString type = md->typeString();
1498 if (type.find("::@")!=-1) // member of tag less struct/union
1500 ClassSDict::Iterator it(*cd->getClassSDict());
1502 for (it.toFirst();(icd=it.current());++it)
1504 //printf(" member %s: type='%s'\n",md->name().data(),type.data());
1505 //printf(" comparing '%s'<->'%s'\n",type.data(),icd->name().data());
1506 if (type.find(icd->name())!=-1) // matching tag less struct/union
1508 QCString name = md->name();
1509 if (name.at(0)=='@') name = "__unnamed__";
1510 if (!prefix.isEmpty()) name.prepend(prefix+".");
1511 //printf(" found %s for class %s\n",name.data(),cd->name().data());
1512 ClassDef *ncd = createTagLessInstance(rootCd,icd,name);
1513 processTagLessClasses(rootCd,icd,ncd,name,count+1);
1514 //printf(" addTagged %s to %s\n",ncd->name().data(),tagParentCd->name().data());
1515 tagParentCd->addTaggedInnerClass(ncd);
1516 ncd->setTagLessReference(icd);
1518 // replace tag-less type for generated/original member
1519 // by newly created class name.
1520 // note the difference between changing cd and tagParentCd.
1521 // for the initial call this is the same pointer, but for
1522 // recursive calls cd is the original tag-less struct (of which
1523 // there is only one instance) and tagParentCd is the newly
1524 // generated tagged struct of which there can be multiple instances!
1525 MemberList *pml = tagParentCd->getMemberList(MemberList::pubAttribs);
1528 MemberListIterator pli(*pml);
1530 for (pli.toFirst();(pmd=pli.current());++pli)
1532 if (pmd->name()==md->name())
1534 pmd->setAccessorType(ncd,substitute(pmd->typeString(),icd->name(),ncd->name()));
1535 //pmd->setType(substitute(pmd->typeString(),icd->name(),ncd->name()));
1547 static void writeMainPageTagFileData()
1549 if (Doxygen::mainPage && !Config_getString("GENERATE_TAGFILE").isEmpty())
1551 Doxygen::tagFile << " <compound kind=\"page\">" << endl
1553 << convertToXML(Doxygen::mainPage->name())
1554 << "</name>" << endl
1556 << convertToXML(Doxygen::mainPage->title())
1557 << "</title>" << endl
1559 << convertToXML(Doxygen::mainPage->getOutputFileBase())
1560 << "</filename>" << endl;
1562 Doxygen::mainPage->writeDocAnchorsToTagFile();
1563 Doxygen::tagFile << " </compound>" << endl;
1567 static void findTagLessClasses(ClassDef *cd)
1569 if (cd->getClassSDict())
1571 ClassSDict::Iterator it(*cd->getClassSDict());
1573 for (it.toFirst();(icd=it.current());++it)
1575 if (icd->name().find("@")==-1) // process all non-anonymous inner classes
1577 findTagLessClasses(icd);
1582 processTagLessClasses(cd,cd,cd,"",0); // process tag less inner struct/classes (if any)
1585 static void findTagLessClasses()
1587 ClassSDict::Iterator cli(*Doxygen::classSDict);
1589 for (cli.toFirst();(cd=cli.current());++cli) // for each class
1591 Definition *scope = cd->getOuterScope();
1592 if (scope && scope->definitionType()!=Definition::TypeClass) // that is not nested
1594 findTagLessClasses(cd);
1600 //----------------------------------------------------------------------
1601 // build a list of all namespaces mentioned in the documentation
1602 // and all namespaces that have a documentation block before their definition.
1603 static void buildNamespaceList(EntryNav *rootNav)
1606 (rootNav->section()==Entry::NAMESPACE_SEC ||
1607 rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1608 rootNav->section()==Entry::PACKAGEDOC_SEC
1610 !rootNav->name().isEmpty()
1613 rootNav->loadEntry(g_storage);
1614 Entry *root = rootNav->entry();
1616 //printf("** buildNamespaceList(%s)\n",root->name.data());
1618 QCString fName = root->name;
1619 if (root->section==Entry::PACKAGEDOC_SEC)
1621 fName=substitute(fName,".","::");
1624 QCString fullName = stripAnonymousNamespaceScope(fName);
1625 if (!fullName.isEmpty())
1627 //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1628 // root->fileName.data(), root->startLine);
1630 if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1632 nd->setDocumentation(root->doc,root->docFile,root->docLine);
1633 nd->setName(fullName); // change name to match docs
1634 nd->addSectionsToDefinition(root->anchors);
1635 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1636 if (nd->getLanguage()==SrcLangExt_Unknown)
1638 nd->setLanguage(root->lang);
1641 // file definition containing the namespace nd
1642 FileDef *fd=rootNav->fileDef();
1643 // insert the namespace in the file definition
1644 if (fd) fd->insertNamespace(nd);
1645 addNamespaceToGroups(root,nd);
1646 nd->setRefItems(root->sli);
1648 else // fresh namespace
1651 QCString tagFileName;
1652 if (rootNav->tagInfo())
1654 tagName=rootNav->tagInfo()->tagName;
1655 tagFileName=rootNav->tagInfo()->fileName;
1657 //printf("++ new namespace %s lang=%s\n",fullName.data(),langToString(root->lang).data());
1658 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName,tagFileName);
1659 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1660 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1661 nd->addSectionsToDefinition(root->anchors);
1662 nd->setHidden(root->hidden);
1663 nd->setArtificial(root->artificial);
1664 nd->setLanguage(root->lang);
1666 //printf("Adding namespace to group\n");
1667 addNamespaceToGroups(root,nd);
1668 nd->setRefItems(root->sli);
1670 // file definition containing the namespace nd
1671 FileDef *fd=rootNav->fileDef();
1672 // insert the namespace in the file definition
1673 if (fd) fd->insertNamespace(nd);
1675 // the empty string test is needed for extract all case
1676 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1677 nd->insertUsedFile(root->fileName);
1678 nd->setBodySegment(root->bodyLine,root->endBodyLine);
1680 // add class to the list
1681 Doxygen::namespaceSDict->inSort(fullName,nd);
1683 // also add namespace to the correct structural context
1684 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName);
1685 //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1686 if (d==0) // we didn't find anything, create the scope artificially
1687 // anyway, so we can at least relate scopes properly.
1689 Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"),nd->getLanguage());
1690 d->addInnerCompound(nd);
1691 nd->setOuterScope(d);
1692 // TODO: Due to the order in which the tag file is written
1693 // a nested class can be found before its parent!
1697 d->addInnerCompound(nd);
1698 nd->setOuterScope(d);
1703 rootNav->releaseEntry();
1705 RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1708 //----------------------------------------------------------------------
1710 static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1711 const QCString &name)
1713 NamespaceDef *usingNd =0;
1716 //printf("Found namespace dict %d\n",unl->count());
1717 NamespaceSDict::Iterator unli(*unl);
1719 for (unli.toFirst();(und=unli.current());++unli)
1721 QCString uScope=und->name()+"::";
1722 usingNd = getResolvedNamespace(uScope+name);
1723 //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1729 static void findUsingDirectives(EntryNav *rootNav)
1731 if (rootNav->section()==Entry::USINGDIR_SEC)
1733 rootNav->loadEntry(g_storage);
1734 Entry *root = rootNav->entry();
1736 //printf("Found using directive %s at line %d of %s\n",
1737 // root->name.data(),root->startLine,root->fileName.data());
1738 QCString name=substitute(root->name,".","::");
1739 if (!name.isEmpty())
1741 NamespaceDef *usingNd = 0;
1742 NamespaceDef *nd = 0;
1743 FileDef *fd = rootNav->fileDef();
1746 // see if the using statement was found inside a namespace or inside
1747 // the global file scope.
1748 if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1749 (fd==0 || fd->getLanguage()!=SrcLangExt_Java) // not a .java file
1752 nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1753 if (!nsName.isEmpty())
1755 nd = getResolvedNamespace(nsName);
1759 // find the scope in which the `using' namespace is defined by prepending
1760 // the possible scopes in which the using statement was found, starting
1761 // with the most inner scope and going to the most outer scope (i.e.
1763 int scopeOffset = nsName.length();
1766 QCString scope=scopeOffset>0 ?
1767 nsName.left(scopeOffset)+"::" : QCString();
1768 usingNd = getResolvedNamespace(scope+name);
1769 //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1774 else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1778 } while (scopeOffset>=0 && usingNd==0);
1780 if (usingNd==0 && nd) // not found, try used namespaces in this scope
1781 // or in one of the parent namespace scopes
1783 NamespaceDef *pnd = nd;
1784 while (pnd && usingNd==0)
1786 // also try with one of the used namespaces found earlier
1787 usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1790 Definition *s = pnd->getOuterScope();
1791 if (s && s->definitionType()==Definition::TypeNamespace)
1793 pnd = (NamespaceDef*)s;
1801 if (usingNd==0 && fd) // still nothing, also try used namespace in the
1804 usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1807 //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1809 // add the namespace the correct scope
1812 //printf("using fd=%p nd=%p\n",fd,nd);
1815 //printf("Inside namespace %s\n",nd->name().data());
1816 nd->addUsingDirective(usingNd);
1820 //printf("Inside file %s\n",fd->name().data());
1821 fd->addUsingDirective(usingNd);
1824 else // unknown namespace, but add it anyway.
1826 //printf("++ new unknown namespace %s lang=%s\n",name.data(),langToString(root->lang).data());
1827 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,name);
1828 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1829 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1830 nd->addSectionsToDefinition(root->anchors);
1831 //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1832 nd->setHidden(root->hidden);
1833 nd->setArtificial(TRUE);
1834 nd->setLanguage(root->lang);
1836 QListIterator<Grouping> gli(*root->groups);
1838 for (;(g=gli.current());++gli)
1841 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1842 gd->addNamespace(nd);
1845 // insert the namespace in the file definition
1848 fd->insertNamespace(nd);
1849 fd->addUsingDirective(nd);
1852 // the empty string test is needed for extract all case
1853 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1854 nd->insertUsedFile(root->fileName);
1855 // add class to the list
1856 Doxygen::namespaceSDict->inSort(name,nd);
1857 nd->setRefItems(root->sli);
1861 rootNav->releaseEntry();
1863 RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
1866 //----------------------------------------------------------------------
1868 static void buildListOfUsingDecls(EntryNav *rootNav)
1870 if (rootNav->section()==Entry::USINGDECL_SEC &&
1871 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1874 rootNav->loadEntry(g_storage);
1875 Entry *root = rootNav->entry();
1877 QCString name = substitute(root->name,".","::");
1879 if (g_usingDeclarations.find(name)==0)
1881 FileDef *fd = rootNav->fileDef();
1884 g_usingDeclarations.insert(name,fd);
1888 rootNav->releaseEntry();
1890 RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
1894 static void findUsingDeclarations(EntryNav *rootNav)
1896 if (rootNav->section()==Entry::USINGDECL_SEC &&
1897 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1900 rootNav->loadEntry(g_storage);
1901 Entry *root = rootNav->entry();
1903 //printf("Found using declaration %s at line %d of %s inside section %x\n",
1904 // root->name.data(),root->startLine,root->fileName.data(),
1905 // rootNav->parent()->section());
1906 if (!root->name.isEmpty())
1908 ClassDef *usingCd = 0;
1909 NamespaceDef *nd = 0;
1910 FileDef *fd = rootNav->fileDef();
1913 // see if the using statement was found inside a namespace or inside
1914 // the global file scope.
1915 if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
1917 scName=rootNav->parent()->name();
1918 if (!scName.isEmpty())
1920 nd = getResolvedNamespace(scName);
1924 // Assume the using statement was used to import a class.
1925 // Find the scope in which the `using' namespace is defined by prepending
1926 // the possible scopes in which the using statement was found, starting
1927 // with the most inner scope and going to the most outer scope (i.e.
1930 QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
1931 usingCd = getClass(name);
1934 usingCd = Doxygen::hiddenClasses->find(name);
1937 //printf("%s -> %p\n",root->name.data(),usingCd);
1938 if (usingCd==0) // definition not in the input => add an artificial class
1940 Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
1941 name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
1942 usingCd = new ClassDef(
1944 name,ClassDef::Class);
1945 Doxygen::hiddenClasses->append(root->name,usingCd);
1946 usingCd->setArtificial(TRUE);
1947 usingCd->setLanguage(root->lang);
1951 Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",
1952 usingCd->name().data(),nd?nd->name().data():fd->name().data());
1955 if (usingCd) // add the class to the correct scope
1959 //printf("Inside namespace %s\n",nd->name().data());
1960 nd->addUsingDeclaration(usingCd);
1964 //printf("Inside file %s\n",fd->name().data());
1965 fd->addUsingDeclaration(usingCd);
1970 rootNav->releaseEntry();
1972 RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
1975 //----------------------------------------------------------------------
1977 static void findUsingDeclImports(EntryNav *rootNav)
1979 if (rootNav->section()==Entry::USINGDECL_SEC &&
1980 (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
1983 //printf("Found using declaration %s at line %d of %s inside section %x\n",
1984 // root->name.data(),root->startLine,root->fileName.data(),
1985 // root->parent->section);
1986 QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
1987 fullName=stripAnonymousNamespaceScope(fullName);
1988 fullName=stripTemplateSpecifiersFromScope(fullName);
1989 ClassDef *cd = getClass(fullName);
1992 //printf("found class %s\n",cd->name().data());
1993 int i=rootNav->name().find("::");
1996 QCString scope=rootNav->name().left(i);
1997 QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
1998 ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
2001 //printf("found class %s\n",bcd->name().data());
2002 MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
2005 MemberNameInfo *mni = mndict->find(memName);
2008 MemberNameInfoIterator mnii(*mni);
2010 for ( ; (mi=mnii.current()) ; ++mnii )
2012 MemberDef *md = mi->memberDef;
2013 if (md && md->protection()!=Private)
2016 rootNav->loadEntry(g_storage);
2017 Entry *root = rootNav->entry();
2019 //printf("found member %s\n",mni->memberName());
2020 MemberDef *newMd = 0;
2022 LockingPtr<ArgumentList> templAl = md->templateArguments();
2023 LockingPtr<ArgumentList> al = md->templateArguments();
2024 newMd = new MemberDef(
2025 root->fileName,root->startLine,
2026 md->typeString(),memName,md->argsString(),
2027 md->excpString(),root->protection,root->virt,
2028 md->isStatic(),Member,md->memberType(),
2029 templAl.pointer(),al.pointer()
2032 newMd->setMemberClass(cd);
2033 cd->insertMember(newMd);
2034 if (!root->doc.isEmpty() || !root->brief.isEmpty())
2036 newMd->setDocumentation(root->doc,root->docFile,root->docLine);
2037 newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2038 newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2042 newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
2043 newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
2044 newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
2046 newMd->setDefinition(md->definition());
2047 newMd->enableCallGraph(root->callGraph);
2048 newMd->enableCallerGraph(root->callerGraph);
2049 newMd->setBitfields(md->bitfieldString());
2050 newMd->addSectionsToDefinition(root->anchors);
2051 newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
2052 newMd->setBodyDef(md->getBodyDef());
2053 newMd->setInitializer(md->initializer());
2054 newMd->setMaxInitLines(md->initializerLines());
2055 newMd->setMemberGroupId(root->mGrpId);
2056 newMd->setMemberSpecifiers(md->getMemberSpecifiers());
2057 newMd->setLanguage(root->lang);
2059 rootNav->releaseEntry();
2069 RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
2072 //----------------------------------------------------------------------
2074 static void findIncludedUsingDirectives()
2076 // first mark all files as not visited
2077 FileNameListIterator fnli(*Doxygen::inputNameList);
2079 for (fnli.toFirst();(fn=fnli.current());++fnli)
2081 FileNameIterator fni(*fn);
2083 for (;(fd=fni.current());++fni)
2088 // then recursively add using directives found in #include files
2089 // to files that have not been visited.
2090 for (fnli.toFirst();(fn=fnli.current());++fnli)
2092 FileNameIterator fni(*fn);
2094 for (fni.toFirst();(fd=fni.current());++fni)
2098 //printf("----- adding using directives for file %s\n",fd->name().data());
2099 fd->addIncludedUsingDirectives();
2105 //----------------------------------------------------------------------
2107 static MemberDef *addVariableToClass(
2110 MemberDef::MemberType mtype,
2111 const QCString &name,
2113 MemberDef *fromAnnMemb,
2115 Relationship related)
2117 Entry *root = rootNav->entry();
2119 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2120 QCString scopeSeparator="::";
2121 SrcLangExt lang = cd->getLanguage();
2122 if (lang==SrcLangExt_Java || lang==SrcLangExt_CSharp)
2124 qualScope = substitute(qualScope,"::",".");
2127 Debug::print(Debug::Variables,0,
2128 " class variable:\n"
2129 " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
2136 root->initializer.data()
2140 if (!root->type.isEmpty())
2142 if (related || mtype==MemberDef::Friend || Config_getBool("HIDE_SCOPE_NAMES"))
2144 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2146 def="using "+name+" = "+root->type.mid(7);
2150 def=root->type+" "+name+root->args;
2155 if (root->spec&Entry::Alias) // turn 'typedef B C::A' into 'using C::A = B'
2157 def="using "+qualScope+scopeSeparator+name+" = "+root->type.mid(7);
2161 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2167 if (Config_getBool("HIDE_SCOPE_NAMES"))
2169 def=name+root->args;
2173 def=qualScope+scopeSeparator+name+root->args;
2176 def.stripPrefix("static ");
2178 // see if the member is already found in the same scope
2179 // (this may be the case for a static member that is initialized
2180 // outside the class)
2181 MemberName *mn=Doxygen::memberNameSDict->find(name);
2184 MemberNameIterator mni(*mn);
2186 for (mni.toFirst();(md=mni.current());++mni)
2188 //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
2189 // md->getClassDef(),cd,root->type.data(),md->typeString());
2190 if (md->getClassDef()==cd &&
2191 removeRedundantWhiteSpace(root->type)==md->typeString())
2192 // member already in the scope
2195 if (root->lang==SrcLangExt_ObjC &&
2196 root->mtype==Property &&
2197 md->memberType()==MemberDef::Variable)
2198 { // Objective-C 2.0 property
2199 // turn variable into a property
2200 md->setProtection(root->protection);
2201 cd->reclassifyMember(md,MemberDef::Property);
2203 addMemberDocs(rootNav,md,def,0,FALSE);
2204 //printf(" Member already found!\n");
2210 // new member variable, typedef or enum value
2211 MemberDef *md=new MemberDef(
2212 root->fileName,root->startLine,
2213 root->type,name,root->args,0,
2214 prot,Normal,root->stat,related,
2215 mtype,root->tArgLists ? root->tArgLists->last() : 0,0);
2216 md->setTagInfo(rootNav->tagInfo());
2217 md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
2218 //md->setDefFile(root->fileName);
2219 //md->setDefLine(root->startLine);
2220 md->setDocumentation(root->doc,root->docFile,root->docLine);
2221 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2222 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2223 md->setDefinition(def);
2224 md->setBitfields(root->bitfields);
2225 md->addSectionsToDefinition(root->anchors);
2226 md->setFromAnonymousScope(fromAnnScope);
2227 md->setFromAnonymousMember(fromAnnMemb);
2228 //md->setIndentDepth(indentDepth);
2229 md->setBodySegment(root->bodyLine,root->endBodyLine);
2230 md->setInitializer(root->initializer);
2231 md->setMaxInitLines(root->initLines);
2232 md->setMemberGroupId(root->mGrpId);
2233 md->setMemberSpecifiers(root->spec);
2234 md->setReadAccessor(root->read);
2235 md->setWriteAccessor(root->write);
2236 md->enableCallGraph(root->callGraph);
2237 md->enableCallerGraph(root->callerGraph);
2238 md->setHidden(root->hidden);
2239 md->setArtificial(root->artificial);
2240 md->setLanguage(root->lang);
2241 addMemberToGroups(root,md);
2242 //if (root->mGrpId!=-1)
2244 // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2245 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
2247 md->setBodyDef(rootNav->fileDef());
2249 //printf(" Adding member=%s\n",md->name().data());
2250 // add the member to the global list
2255 else // new variable name
2257 mn = new MemberName(name);
2259 //printf("Adding memberName=%s\n",mn->memberName());
2260 //Doxygen::memberNameDict.insert(name,mn);
2261 //Doxygen::memberNameList.append(mn);
2262 Doxygen::memberNameSDict->append(name,mn);
2263 // add the member to the class
2265 //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd);
2266 cd->insertMember(md);
2267 md->setRefItems(root->sli);
2269 //TODO: insert FileDef instead of filename strings.
2270 cd->insertUsedFile(root->fileName);
2271 rootNav->changeSection(Entry::EMPTY_SEC);
2275 //----------------------------------------------------------------------
2277 static MemberDef *addVariableToFile(
2279 MemberDef::MemberType mtype,
2280 const QCString &scope,
2281 const QCString &name,
2283 /*int indentDepth,*/
2284 MemberDef *fromAnnMemb)
2286 Entry *root = rootNav->entry();
2287 Debug::print(Debug::Variables,0,
2288 " global variable:\n"
2289 " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d lang=%d\n",
2299 FileDef *fd = rootNav->fileDef();
2301 // see if we have a typedef that should hide a struct or union
2302 if (mtype==MemberDef::Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))
2304 QCString type = root->type;
2305 type.stripPrefix("typedef ");
2306 if (type.left(7)=="struct " || type.left(6)=="union ")
2308 type.stripPrefix("struct ");
2309 type.stripPrefix("union ");
2310 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2312 s = re.match(type,0,&l);
2315 QCString typeValue = type.mid(s,l);
2316 ClassDef *cd = getClass(typeValue);
2319 // this typedef should hide compound name cd, so we
2320 // change the name that is displayed from cd.
2321 cd->setClassName(name);
2322 cd->setDocumentation(root->doc,root->docFile,root->docLine);
2323 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2330 // see if the function is inside a namespace
2331 NamespaceDef *nd = 0;
2333 if (!scope.isEmpty())
2335 if (scope.find('@')!=-1) return 0; // anonymous scope!
2336 //nscope=removeAnonymousScopes(scope);
2337 //if (!nscope.isEmpty())
2339 nd = getResolvedNamespace(scope);
2344 // determine the definition of the global variable
2345 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' &&
2346 !Config_getBool("HIDE_SCOPE_NAMES")
2348 // variable is inside a namespace, so put the scope before the name
2350 SrcLangExt lang = nd->getLanguage();
2351 QCString sep=getLanguageSpecificSeparator(lang);
2353 if (!root->type.isEmpty())
2355 if (root->spec&Entry::Alias) // turn 'typedef B NS::A' into 'using NS::A = B'
2357 def="using "+nd->name()+sep+name+" = "+root->type;
2359 else // normal member
2361 def=root->type+" "+nd->name()+sep+name+root->args;
2366 def=nd->name()+sep+name+root->args;
2371 if (!root->type.isEmpty() && !root->name.isEmpty())
2373 if (name.at(0)=='@') // dummy variable representing anonymous union
2379 if (root->spec&Entry::Alias) // turn 'typedef B A' into 'using A = B'
2381 def="using "+root->name+" = "+root->type.mid(7);
2383 else // normal member
2385 def=root->type+" "+name+root->args;
2391 def=name+root->args;
2394 def.stripPrefix("static ");
2396 MemberName *mn=Doxygen::functionNameSDict->find(name);
2399 //QCString nscope=removeAnonymousScopes(scope);
2400 //NamespaceDef *nd=0;
2401 //if (!nscope.isEmpty())
2402 if (!scope.isEmpty())
2404 nd = getResolvedNamespace(scope);
2406 MemberNameIterator mni(*mn);
2408 for (mni.toFirst();(md=mni.current());++mni)
2411 ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2412 root->fileName==md->getFileDef()->absFilePath()
2413 ) // both variable names in the same file
2414 || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2416 && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2417 && !md->isEnumerate() // in C# an enum value and enum can have the same name
2419 // variable already in the scope
2421 bool isPHPArray = md->getLanguage()==SrcLangExt_PHP &&
2422 md->argsString()!=root->args &&
2423 root->args.find('[')!=-1;
2424 bool staticsInDifferentFiles =
2425 root->stat && md->isStatic() &&
2426 root->fileName!=md->getDefFileName();
2428 if (md->getFileDef() &&
2429 !isPHPArray && // not a php array
2430 !staticsInDifferentFiles
2432 // not a php array variable
2435 Debug::print(Debug::Variables,0,
2436 " variable already found: scope=%s\n",md->getOuterScope()->name().data());
2437 addMemberDocs(rootNav,md,def,0,FALSE);
2438 md->setRefItems(root->sli);
2444 Debug::print(Debug::Variables,0,
2445 " new variable, nd=%s!\n",nd?nd->name().data():"<global>");
2446 // new global variable, enum value or typedef
2447 MemberDef *md=new MemberDef(
2448 root->fileName,root->startLine,
2449 root->type,name,root->args,0,
2450 Public, Normal,root->stat,Member,
2451 mtype,root->tArgLists ? root->tArgLists->last() : 0,0);
2452 md->setTagInfo(rootNav->tagInfo());
2453 md->setMemberSpecifiers(root->spec);
2454 md->setDocumentation(root->doc,root->docFile,root->docLine);
2455 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2456 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2457 md->addSectionsToDefinition(root->anchors);
2458 md->setFromAnonymousScope(fromAnnScope);
2459 md->setFromAnonymousMember(fromAnnMemb);
2460 md->setInitializer(root->initializer);
2461 md->setMaxInitLines(root->initLines);
2462 md->setMemberGroupId(root->mGrpId);
2463 md->setDefinition(def);
2464 md->setLanguage(root->lang);
2465 md->enableCallGraph(root->callGraph);
2466 md->enableCallerGraph(root->callerGraph);
2467 md->setExplicitExternal(root->explicitExternal);
2468 //md->setOuterScope(fd);
2469 if (!root->explicitExternal)
2471 md->setBodySegment(root->bodyLine,root->endBodyLine);
2474 addMemberToGroups(root,md);
2476 md->setRefItems(root->sli);
2477 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2479 md->setNamespace(nd);
2480 nd->insertMember(md);
2483 // add member to the file (we do this even if we have already inserted
2484 // it into the namespace.
2488 fd->insertMember(md);
2491 // add member definition to the list of globals
2498 mn = new MemberName(name);
2500 Doxygen::functionNameSDict->append(name,mn);
2502 rootNav->changeSection(Entry::EMPTY_SEC);
2506 /*! See if the return type string \a type is that of a function pointer
2507 * \returns -1 if this is not a function pointer variable or
2508 * the index at which the closing brace of (...*name) was found.
2510 static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2512 if (lang == SrcLangExt_Fortran) return -1; // Fortran does not have function pointers
2513 static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2515 int bb=type.find('<');
2516 int be=type.findRev('>');
2517 if (!type.isEmpty() && // return type is non-empty
2518 (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2519 type.find("operator")==-1 && // not an operator
2520 (type.find(")(")==-1 || type.find("typedef ")!=-1) &&
2521 // not a function pointer return type
2522 !(bb<i && i<be) // bug665855: avoid treating "typedef A<void (T*)> type" as a function pointer
2525 if (pLength) *pLength=l;
2526 //printf("findFunctionPtr=%d\n",i);
2531 //printf("findFunctionPtr=%d\n",-1);
2537 /*! Returns TRUE iff \a type is a class within scope \a context.
2538 * Used to detect variable declarations that look like function prototypes.
2540 static bool isVarWithConstructor(EntryNav *rootNav)
2542 static QRegExp initChars("[0-9\"'&*!^]+");
2543 static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2547 Definition *ctx = 0;
2551 //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2552 rootNav->loadEntry(g_storage);
2553 Entry *root = rootNav->entry();
2555 if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2560 else if ((fd = rootNav->fileDef()) &&
2561 (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2563 { // inside a .c file
2567 if (root->type.isEmpty())
2572 if (!rootNav->parent()->name().isEmpty())
2574 ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2577 // remove qualifiers
2578 findAndRemoveWord(type,"const");
2579 findAndRemoveWord(type,"static");
2580 findAndRemoveWord(type,"volatile");
2581 //if (type.left(6)=="const ") type=type.right(type.length()-6);
2582 typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2583 if (!typeIsClass && (ti=type.find('<'))!=-1)
2585 typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2587 if (typeIsClass) // now we still have to check if the arguments are
2588 // types or values. Since we do not have complete type info
2589 // we need to rely on heuristics :-(
2591 //printf("typeIsClass\n");
2592 ArgumentList *al = root->argList;
2593 if (al==0 || al->isEmpty())
2595 result=FALSE; // empty arg list -> function prototype.
2598 ArgumentListIterator ali(*al);
2600 for (ali.toFirst();(a=ali.current());++ali)
2602 if (!a->name.isEmpty() || !a->defval.isEmpty())
2604 if (a->name.find(initChars)==0)
2610 result=FALSE; // arg has (type,name) pair -> function prototype
2614 if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0)
2616 result=FALSE; // arg type is a known type
2619 if (checkIfTypedef(ctx,fd,a->type))
2621 //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2622 result=FALSE; // argument is a typedef
2625 if (a->type.at(a->type.length()-1)=='*' ||
2626 a->type.at(a->type.length()-1)=='&')
2627 // type ends with * or & => pointer or reference
2632 if (a->type.find(initChars)==0)
2634 result=TRUE; // argument type starts with typical initializer char
2637 QCString resType=resolveTypeDef(ctx,a->type);
2638 if (resType.isEmpty()) resType=a->type;
2640 if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2642 resType=resType.left(len);
2643 //printf("resType=%s\n",resType.data());
2644 if (resType=="int" || resType=="long" || resType=="float" ||
2645 resType=="double" || resType=="char" || resType=="signed" ||
2646 resType=="const" || resType=="unsigned" || resType=="void")
2648 result=FALSE; // type keyword -> function prototype
2657 //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2658 // root->type.data(),result);
2659 rootNav->releaseEntry();
2663 static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2665 rootNav->loadEntry(g_storage);
2666 Entry *root = rootNav->entry();
2668 Debug::print(Debug::Variables,0,
2670 " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d relates=%s\n",
2676 root->relates.data()
2678 //printf("root->parent->name=%s\n",root->parent->name.data());
2680 if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2681 (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2683 // recover from parse error caused by redundant braces
2684 // like in "int *(var[10]);", which is parsed as
2685 // type="" name="int *" args="(var[10])"
2687 root->type=root->name;
2688 static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2690 int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2691 root->name=root->args.mid(i,l);
2692 root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2693 //printf("new: type=`%s' name=`%s' args=`%s'\n",
2694 // root->type.data(),root->name.data(),root->args.data());
2699 if (i==-1 && (root->spec&Entry::Alias)==0) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2700 Debug::print(Debug::Variables,0," functionPtr? %s\n",i!=-1?"yes":"no");
2701 if (i!=-1) // function pointer
2703 int ai = root->type.find('[',i);
2704 if (ai>i) // function pointer array
2706 root->args.prepend(root->type.right(root->type.length()-ai));
2707 root->type=root->type.left(ai);
2709 else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2711 root->type=root->type.left(root->type.length()-1);
2712 root->args.prepend(")");
2713 //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2716 else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
2718 root->type=root->type.left(root->type.length()-1);
2719 root->args.prepend(")");
2723 QCString scope,name=removeRedundantWhiteSpace(root->name);
2725 // find the scope of this variable
2726 EntryNav *p = rootNav->parent();
2727 while ((p->section() & Entry::SCOPE_MASK))
2729 QCString scopeName = p->name();
2730 if (!scopeName.isEmpty())
2732 scope.prepend(scopeName);
2738 MemberDef::MemberType mtype;
2739 QCString type=root->type.stripWhiteSpace();
2741 bool isRelated=FALSE;
2742 bool isMemberOf=FALSE;
2744 QCString classScope=stripAnonymousNamespaceScope(scope);
2745 classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2746 QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2748 if (root->name.findRev("::")!=-1)
2750 if (root->type=="friend class" || root->type=="friend struct" ||
2751 root->type=="friend union")
2756 addVariableToClass(rootNav, // entry
2757 cd, // class to add member to
2758 MemberDef::Friend, // type of member
2759 name, // name of the member
2760 FALSE, // from Anonymous scope
2761 0, // anonymous member
2762 Public, // protection
2763 Member // related to a class
2768 /* skip this member, because it is a
2769 * static variable definition (always?), which will be
2770 * found in a class scope as well, but then we know the
2771 * correct protection level, so only then it will be
2772 * inserted in the correct list!
2777 mtype=MemberDef::EnumValue;
2778 else if (type.left(8)=="typedef ")
2779 mtype=MemberDef::Typedef;
2780 else if (type.left(7)=="friend ")
2781 mtype=MemberDef::Friend;
2782 else if (root->mtype==Property)
2783 mtype=MemberDef::Property;
2784 else if (root->mtype==Event)
2785 mtype=MemberDef::Event;
2787 mtype=MemberDef::Variable;
2789 if (!root->relates.isEmpty()) // related variable
2792 isMemberOf=(root->relatesType == MemberOf);
2793 if (getClass(root->relates)==0 && !scope.isEmpty())
2794 scope=mergeScopes(scope,root->relates);
2796 scope=root->relates;
2800 if (cd==0 && classScope!=scope) cd=getClass(classScope);
2805 // if cd is an anonymous (=tag less) scope we insert the member
2806 // into a non-anonymous parent scope as well. This is needed to
2807 // be able to refer to it using \var or \fn
2809 //int indentDepth=0;
2810 int si=scope.find('@');
2811 //int anonyScopes = 0;
2814 static bool inlineSimpleStructs = Config_getBool("INLINE_SIMPLE_STRUCTS");
2815 if (si!=-1 && !inlineSimpleStructs) // anonymous scope or type
2819 pScope = scope.left(QMAX(si-2,0)); // scope without tag less parts
2820 if (!pScope.isEmpty())
2821 pScope.prepend(annScopePrefix);
2822 else if (annScopePrefix.length()>2)
2823 pScope=annScopePrefix.left(annScopePrefix.length()-2);
2824 if (name.at(0)!='@')
2826 if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2828 md=addVariableToClass(rootNav, // entry
2829 pcd, // class to add member to
2830 mtype, // member type
2831 name, // member name
2832 TRUE, // from anonymous scope
2833 0, // from anonymous member
2835 isMemberOf ? Foreign : isRelated ? Related : Member
2839 else // anonymous scope inside namespace or file => put variable in the global scope
2841 if (mtype==MemberDef::Variable)
2843 md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0);
2850 //printf("name=`%s' scope=%s scope.right=%s\n",
2851 // name.data(),scope.data(),
2852 // scope.right(scope.length()-si).data());
2853 addVariableToClass(rootNav, // entry
2854 cd, // class to add member to
2855 mtype, // member type
2856 name, // name of the member
2857 FALSE, // from anonymous scope
2858 md, // from anonymous member
2860 isMemberOf ? Foreign : isRelated ? Related : Member);
2862 else if (!name.isEmpty()) // global variable
2864 //printf("Inserting member in global scope %s!\n",scope.data());
2865 addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
2869 rootNav->releaseEntry();
2872 //----------------------------------------------------------------------
2873 // Searches the Entry tree for typedef documentation sections.
2874 // If found they are stored in their class or in the global list.
2875 static void buildTypedefList(EntryNav *rootNav)
2877 //printf("buildVarList(%s)\n",rootNav->name().data());
2878 if (!rootNav->name().isEmpty() &&
2879 rootNav->section()==Entry::VARIABLE_SEC &&
2880 rootNav->type().find("typedef ")!=-1 // its a typedef
2883 addVariable(rootNav);
2885 if (rootNav->children())
2887 EntryNavListIterator eli(*rootNav->children());
2889 for (;(e=eli.current());++eli)
2891 if (e->section()!=Entry::ENUM_SEC)
2893 buildTypedefList(e);
2899 //----------------------------------------------------------------------
2900 // Searches the Entry tree for Variable documentation sections.
2901 // If found they are stored in their class or in the global list.
2903 static void buildVarList(EntryNav *rootNav)
2905 //printf("buildVarList(%s) section=%08x\n",rootNav->name().data(),rootNav->section());
2907 if (!rootNav->name().isEmpty() &&
2908 (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
2910 (rootNav->section()==Entry::VARIABLE_SEC // it's a variable
2912 (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable
2913 (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
2915 (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
2916 isVarWithConstructor(rootNav)
2919 ) // documented variable
2921 addVariable(rootNav,isFuncPtr);
2923 if (rootNav->children())
2925 EntryNavListIterator eli(*rootNav->children());
2927 for (;(e=eli.current());++eli)
2929 if (e->section()!=Entry::ENUM_SEC)
2937 //----------------------------------------------------------------------
2938 // Searches the Entry tree for Function sections.
2939 // If found they are stored in their class or in the global list.
2941 static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
2942 const QCString &rname,bool isFriend)
2944 Entry *root = rootNav->entry();
2945 FileDef *fd=rootNav->fileDef();
2948 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
2949 int ts=root->type.find('<');
2950 int te=root->type.findRev('>');
2951 int i=re.match(root->type,0,&l);
2952 if (i!=-1 && ts!=-1 && ts<te && ts<i && i<te) // avoid changing A<int(int*)>, see bug 677315
2957 if (cd->getLanguage()==SrcLangExt_Cpp && // only C has pointers
2958 !root->type.isEmpty() && (root->spec&Entry::Alias)==0 && i!=-1) // function variable
2960 root->args+=root->type.right(root->type.length()-i-l);
2961 root->type=root->type.left(i+l);
2964 QCString name=removeRedundantWhiteSpace(rname);
2965 if (name.left(2)=="::") name=name.right(name.length()-2);
2967 MemberDef::MemberType mtype;
2968 if (isFriend) mtype=MemberDef::Friend;
2969 else if (root->mtype==Signal) mtype=MemberDef::Signal;
2970 else if (root->mtype==Slot) mtype=MemberDef::Slot;
2971 else if (root->mtype==DCOP) mtype=MemberDef::DCOP;
2972 else mtype=MemberDef::Function;
2974 // strip redundant template specifier for constructors
2975 if ((fd==0 || fd->getLanguage()==SrcLangExt_Cpp) &&
2976 name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
2981 //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
2982 // root->name.data(),root->args.data(),argListToString(root->argList).data()
2985 // adding class member
2986 MemberDef *md=new MemberDef(
2987 root->fileName,root->startLine,
2988 root->type,name,root->args,root->exception,
2989 root->protection,root->virt,
2990 root->stat && root->relatesType != MemberOf,
2991 root->relates.isEmpty() ? Member :
2992 root->relatesType == MemberOf ? Foreign : Related,
2993 mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList);
2994 md->setTagInfo(rootNav->tagInfo());
2995 md->setMemberClass(cd);
2996 md->setDocumentation(root->doc,root->docFile,root->docLine);
2997 md->setDocsForDefinition(!root->proto);
2998 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2999 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3000 md->setBodySegment(root->bodyLine,root->endBodyLine);
3001 md->setMemberSpecifiers(root->spec);
3002 md->setMemberGroupId(root->mGrpId);
3003 md->setTypeConstraints(root->typeConstr);
3004 md->setLanguage(root->lang);
3007 //md->setScopeTemplateArguments(root->tArgList);
3008 md->addSectionsToDefinition(root->anchors);
3010 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
3011 SrcLangExt lang = cd->getLanguage();
3012 QCString scopeSeparator=getLanguageSpecificSeparator(lang);
3013 if (scopeSeparator!="::")
3015 qualScope = substitute(qualScope,"::",scopeSeparator);
3017 if (lang==SrcLangExt_PHP)
3019 // for PHP we use Class::method and Namespace\method
3020 scopeSeparator="::";
3022 if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
3024 if (!root->type.isEmpty())
3028 def=root->type+" "+name;
3032 def=root->type+" "+name+root->args;
3043 def=name+root->args;
3049 if (!root->type.isEmpty())
3053 def=root->type+" "+qualScope+scopeSeparator+name;
3057 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
3064 def=qualScope+scopeSeparator+name;
3068 def=qualScope+scopeSeparator+name+root->args;
3072 if (def.left(7)=="friend ") def=def.right(def.length()-7);
3073 md->setDefinition(def);
3074 md->enableCallGraph(root->callGraph);
3075 md->enableCallerGraph(root->callerGraph);
3077 Debug::print(Debug::Functions,0,
3079 " `%s' `%s'::`%s' `%s' proto=%d\n"
3089 // add member to the global list of all members
3090 //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
3092 if ((mn=Doxygen::memberNameSDict->find(name)))
3098 mn = new MemberName(name);
3100 Doxygen::memberNameSDict->append(name,mn);
3103 // add member to the class cd
3104 cd->insertMember(md);
3105 // add file to list of used files
3106 cd->insertUsedFile(root->fileName);
3108 addMemberToGroups(root,md);
3109 rootNav->changeSection(Entry::EMPTY_SEC);
3110 md->setRefItems(root->sli);
3114 static void buildFunctionList(EntryNav *rootNav)
3116 if (rootNav->section()==Entry::FUNCTION_SEC)
3118 rootNav->loadEntry(g_storage);
3119 Entry *root = rootNav->entry();
3121 Debug::print(Debug::Functions,0,
3123 " `%s' `%s'::`%s' `%s' relates=`%s' relatesType=`%d' file=`%s' line=`%d' bodyLine=`%d' #tArgLists=%d mGrpId=%d spec=%d proto=%d docFile=%s\n",
3125 rootNav->parent()->name().data(),
3128 root->relates.data(),
3130 root->fileName.data(),
3133 root->tArgLists ? (int)root->tArgLists->count() : -1,
3137 root->docFile.data()
3140 bool isFriend=root->type.find("friend ")!=-1;
3141 QCString rname = removeRedundantWhiteSpace(root->name);
3142 //printf("rname=%s\n",rname.data());
3144 QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
3145 if (!rname.isEmpty() && scope.find('@')==-1)
3148 // check if this function's parent is a class
3149 scope=stripTemplateSpecifiersFromScope(scope,FALSE);
3151 FileDef *rfd=rootNav->fileDef();
3153 int memIndex=rname.findRev("::");
3156 if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
3158 // strip scope from name
3159 rname=rname.right(rname.length()-rootNav->parent()->name().length()-2);
3162 NamespaceDef *nd = 0;
3163 bool isMember=FALSE;
3166 int ts=rname.find('<');
3167 int te=rname.find('>');
3168 if (memIndex>0 && (ts==-1 || te==-1))
3170 // note: the following code was replaced by inMember=TRUE to deal with a
3171 // function rname='X::foo' of class X inside a namespace also called X...
3173 //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
3177 // // strip namespace scope from name
3178 // scope=rname.left(memIndex);
3179 // rname=rname.right(rname.length()-memIndex-2);
3185 isMember=memIndex<ts || memIndex>te;
3189 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
3190 int ts=root->type.find('<');
3191 int te=root->type.findRev('>');
3193 if (!rootNav->parent()->name().isEmpty() &&
3194 (rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
3196 // do some fuzzy things to exclude function pointers
3197 (root->type.isEmpty() ||
3198 ((ti=root->type.find(re,0))==-1 || // type does not contain ..(..*
3199 (ts!=-1 && ts<te && ts<ti && ti<te) || // outside of < ... >
3200 root->args.find(")[")!=-1) || // and args not )[.. -> function pointer
3201 root->type.find(")(")!=-1 || root->type.find("operator")!=-1 || // type contains ..)(.. and not "operator"
3202 cd->getLanguage()!=SrcLangExt_Cpp // language other than C
3206 Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
3207 rname.data(),cd->name().data());
3208 addMethodToClass(rootNav,cd,rname,isFriend);
3210 else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK)
3211 || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
3214 (root->relates.isEmpty() || root->relatesType == Duplicate) &&
3215 root->type.left(7)!="extern " && root->type.left(8)!="typedef "
3217 // no member => unrelated function
3219 /* check the uniqueness of the function name in the file.
3220 * A file could contain a function prototype and a function definition
3221 * or even multiple function prototypes.
3226 if ((mn=Doxygen::functionNameSDict->find(rname)))
3228 Debug::print(Debug::Functions,0," --> function %s already found!\n",rname.data());
3229 MemberNameIterator mni(*mn);
3230 for (mni.toFirst();(!found && (md=mni.current()));++mni)
3232 NamespaceDef *mnd = md->getNamespaceDef();
3233 NamespaceDef *rnd = 0;
3234 //printf("root namespace=%s\n",rootNav->parent()->name().data());
3235 QCString fullScope = scope;
3236 QCString parentScope = rootNav->parent()->name();
3237 if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
3239 if (!scope.isEmpty()) fullScope.prepend("::");
3240 fullScope.prepend(parentScope);
3242 //printf("fullScope=%s\n",fullScope.data());
3243 rnd = getResolvedNamespace(fullScope);
3244 FileDef *mfd = md->getFileDef();
3245 QCString nsName,rnsName;
3246 if (mnd) nsName = mnd->name().copy();
3247 if (rnd) rnsName = rnd->name().copy();
3248 //printf("matching arguments for %s%s %s%s\n",
3249 // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
3250 LockingPtr<ArgumentList> mdAl = md->argumentList();
3251 LockingPtr<ArgumentList> mdTempl = md->templateArguments();
3253 // in case of template functions, we need to check if the
3254 // functions have the same number of template parameters
3255 bool sameNumTemplateArgs = TRUE;
3256 if (mdTempl!=0 && root->tArgLists)
3258 if (mdTempl->count()!=root->tArgLists->getLast()->count())
3260 sameNumTemplateArgs = FALSE;
3264 bool staticsInDifferentFiles =
3265 root->stat && md->isStatic() && root->fileName!=md->getDefFileName();
3268 matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(),
3269 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
3271 sameNumTemplateArgs &&
3272 !staticsInDifferentFiles
3276 if (root->groups->first()!=0)
3278 gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data());
3280 //printf("match!\n");
3281 //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
3282 // see if we need to create a new member
3283 found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace
3284 ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and
3285 mfd->absFilePath()==root->fileName // prototype in the same file
3288 // otherwise, allow a duplicate global member with the same argument list
3289 if (!found && gd && gd==md->getGroupDef() && nsName==rnsName)
3291 // member is already in the group, so we don't want to add it again.
3295 //printf("combining function with prototype found=%d in namespace %s\n",
3296 // found,nsName.data());
3300 // merge argument lists
3301 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
3302 // merge documentation
3303 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3305 ArgumentList *argList = new ArgumentList;
3306 stringToArgumentList(root->args,argList);
3309 //printf("setDeclArgumentList to %p\n",argList);
3310 md->setDeclArgumentList(argList);
3314 md->setArgumentList(argList);
3318 md->setDocumentation(root->doc,root->docFile,root->docLine);
3319 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3320 md->setDocsForDefinition(!root->proto);
3321 if (md->getStartBodyLine()!=-1 && md->getStartBodyLine()==-1)
3323 md->setBodySegment(root->bodyLine,root->endBodyLine);
3324 md->setBodyDef(rfd);
3327 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3329 md->setArgsString(root->args);
3331 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3333 md->addSectionsToDefinition(root->anchors);
3335 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3336 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3338 // merge ingroup specifiers
3339 if (md->getGroupDef()==0 && root->groups->first()!=0)
3341 addMemberToGroups(root,md);
3343 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3345 //printf("existing member is grouped, new member not\n");
3346 root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3348 else if (md->getGroupDef()!=0 && root->groups->first()!=0)
3350 //printf("both members are grouped\n");
3353 // if md is a declaration and root is the corresponding
3354 // definition, then turn md into a definition.
3355 if (md->isPrototype() && !root->proto)
3357 md->setPrototype(FALSE);
3363 if (!found) /* global function is unique with respect to the file */
3365 Debug::print(Debug::Functions,0," --> new function %s found!\n",rname.data());
3366 //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3367 // root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3369 // new global function
3370 ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0;
3371 QCString name=removeRedundantWhiteSpace(rname);
3373 root->fileName,root->startLine,
3374 root->type,name,root->args,root->exception,
3375 root->protection,root->virt,root->stat,Member,
3376 MemberDef::Function,tArgList,root->argList);
3378 md->setTagInfo(rootNav->tagInfo());
3379 md->setLanguage(root->lang);
3380 //md->setDefFile(root->fileName);
3381 //md->setDefLine(root->startLine);
3382 md->setDocumentation(root->doc,root->docFile,root->docLine);
3383 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3384 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3385 md->setPrototype(root->proto);
3386 md->setDocsForDefinition(!root->proto);
3387 md->setTypeConstraints(root->typeConstr);
3388 //md->setBody(root->body);
3389 md->setBodySegment(root->bodyLine,root->endBodyLine);
3390 FileDef *fd=rootNav->fileDef();
3392 md->addSectionsToDefinition(root->anchors);
3393 md->setMemberSpecifiers(root->spec);
3394 md->setMemberGroupId(root->mGrpId);
3396 // see if the function is inside a namespace that was not part of
3397 // the name already (in that case nd should be non-zero already)
3398 if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3400 //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3401 QCString nscope=rootNav->parent()->name();
3402 if (!nscope.isEmpty())
3404 nd = getResolvedNamespace(nscope);
3408 if (!scope.isEmpty())
3410 QCString sep = getLanguageSpecificSeparator(root->lang);
3413 scope = substitute(scope,"::",sep);
3419 if (!root->type.isEmpty())
3423 def=root->type+" "+scope+name;
3427 def=root->type+" "+scope+name+root->args;
3434 def=scope+name.copy();
3438 def=scope+name+root->args;
3441 Debug::print(Debug::Functions,0,
3442 " Global Function:\n"
3443 " `%s' `%s'::`%s' `%s' proto=%d\n"
3446 rootNav->parent()->name().data(),
3452 md->setDefinition(def);
3453 md->enableCallGraph(root->callGraph);
3454 md->enableCallerGraph(root->callerGraph);
3455 //if (root->mGrpId!=-1)
3457 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
3460 md->setRefItems(root->sli);
3461 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3463 // add member to namespace
3464 md->setNamespace(nd);
3465 nd->insertMember(md);
3469 // add member to the file (we do this even if we have already
3470 // inserted it into the namespace)
3472 fd->insertMember(md);
3475 // add member to the list of file members
3476 //printf("Adding member=%s\n",md->name().data());
3478 if ((mn=Doxygen::functionNameSDict->find(name)))
3484 mn = new MemberName(name);
3486 Doxygen::functionNameSDict->append(name,mn);
3488 addMemberToGroups(root,md);
3489 if (root->relatesType == Simple) // if this is a relatesalso command,
3490 // allow find Member to pick it up
3492 rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished
3499 FileDef *fd=rootNav->fileDef();
3502 // add member to the file (we do this even if we have already
3503 // inserted it into the namespace)
3504 fd->insertMember(md);
3508 //printf("unrelated function %d `%s' `%s' `%s'\n",
3509 // root->parent->section,root->type.data(),rname.data(),root->args.data());
3513 Debug::print(Debug::Functions,0," --> %s not processed!\n",rname.data());
3516 else if (rname.isEmpty())
3518 warn(root->fileName,root->startLine,
3519 "warning: Illegal member name found."
3523 rootNav->releaseEntry();
3525 RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3528 //----------------------------------------------------------------------
3530 static void findFriends()
3532 //printf("findFriends()\n");
3533 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3535 for (;(fn=fnli.current());++fnli) // for each global function name
3537 //printf("Function name=`%s'\n",fn->memberName());
3539 if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3540 { // there are members with the same name
3541 //printf("Function name is also a member name\n");
3542 MemberNameIterator fni(*fn);
3544 for (;(fmd=fni.current());++fni) // for each function with that name
3546 MemberNameIterator mni(*mn);
3548 for (;(mmd=mni.current());++mni) // for each member with that name
3550 //printf("Checking for matching arguments
3551 // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3552 // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3553 LockingPtr<ArgumentList> mmdAl = mmd->argumentList();
3554 LockingPtr<ArgumentList> fmdAl = fmd->argumentList();
3555 if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3556 matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(),
3557 fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(),
3561 ) // if the member is related and the arguments match then the
3562 // function is actually a friend.
3564 mergeArguments(mmdAl.pointer(),fmdAl.pointer());
3565 if (!fmd->documentation().isEmpty())
3567 mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3569 else if (!mmd->documentation().isEmpty())
3571 fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3573 if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3575 mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3577 else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3579 fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3581 if (!fmd->inbodyDocumentation().isEmpty())
3583 mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3585 else if (!mmd->inbodyDocumentation().isEmpty())
3587 fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3589 //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3590 if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3592 mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3593 mmd->setBodyDef(fmd->getBodyDef());
3594 //mmd->setBodyMember(fmd);
3596 else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3598 fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3599 fmd->setBodyDef(mmd->getBodyDef());
3600 //fmd->setBodyMember(mmd);
3602 mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3604 mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3605 mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3606 fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3607 fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3615 //----------------------------------------------------------------------
3617 static void transferFunctionDocumentation()
3619 //printf("---- transferFunctionDocumentation()\n");
3621 // find matching function declaration and definitions.
3622 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3624 for (;(mn=mnli.current());++mnli)
3626 //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3627 MemberDef *mdef=0,*mdec=0;
3628 MemberNameIterator mni1(*mn);
3629 /* find a matching function declaration and definition for this function */
3630 for (;(mdec=mni1.current());++mni1)
3632 if (mdec->isPrototype() ||
3633 (mdec->isVariable() && mdec->isExternal())
3636 MemberNameIterator mni2(*mn);
3637 for (;(mdef=mni2.current());++mni2)
3639 combineDeclarationAndDefinition(mdec,mdef);
3646 //----------------------------------------------------------------------
3648 static void transferFunctionReferences()
3650 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3652 for (;(mn=mnli.current());++mnli)
3654 MemberDef *md,*mdef=0,*mdec=0;
3655 MemberNameIterator mni(*mn);
3656 /* find a matching function declaration and definition for this function */
3657 for (;(md=mni.current());++mni)
3659 if (md->isPrototype())
3661 else if (md->isVariable() && md->isExternal())
3664 if (md->isFunction() && !md->isStatic() && !md->isPrototype())
3666 else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3671 LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
3672 LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
3674 matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
3675 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
3680 LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers();
3681 LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers();
3684 MemberSDict::Iterator msdi(*defDict);
3686 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3688 if (decDict==0 || decDict->find(rmd->name())==0)
3690 mdec->addSourceReferences(rmd);
3696 MemberSDict::Iterator msdi(*decDict);
3698 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3700 if (defDict==0 || defDict->find(rmd->name())==0)
3702 mdef->addSourceReferences(rmd);
3707 defDict = mdef->getReferencedByMembers();
3708 decDict = mdec->getReferencedByMembers();
3711 MemberSDict::Iterator msdi(*defDict);
3713 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3715 if (decDict==0 || decDict->find(rmd->name())==0)
3717 mdec->addSourceReferencedBy(rmd);
3723 MemberSDict::Iterator msdi(*decDict);
3725 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3727 if (defDict==0 || defDict->find(rmd->name())==0)
3729 mdef->addSourceReferencedBy(rmd);
3738 //----------------------------------------------------------------------
3740 static void transferRelatedFunctionDocumentation()
3742 // find match between function declaration and definition for
3743 // related functions
3744 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3746 for (mnli.toFirst();(mn=mnli.current());++mnli)
3749 MemberNameIterator mni(*mn);
3750 /* find a matching function declaration and definition for this function */
3751 for (mni.toFirst();(md=mni.current());++mni) // for each global function
3753 //printf(" Function `%s'\n",md->name().data());
3755 if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
3757 //printf(" Member name found\n");
3759 MemberNameIterator rmni(*rmn);
3760 for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
3762 LockingPtr<ArgumentList> mdAl = md->argumentList();
3763 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
3764 //printf(" Member found: related=`%d'\n",rmd->isRelated());
3765 if ((rmd->isRelated() || rmd->isForeign()) && // related function
3766 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
3767 rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
3772 //printf(" Found related member `%s'\n",md->name().data());
3773 if (rmd->relatedAlso())
3774 md->setRelatedAlso(rmd->relatedAlso());
3775 else if (rmd->isForeign())
3786 //----------------------------------------------------------------------
3788 /*! make a dictionary of all template arguments of class cd
3789 * that are part of the base class name.
3790 * Example: A template class A with template arguments <R,S,T>
3791 * that inherits from B<T,T,S> will have T and S in the dictionary.
3793 static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
3795 QDict<int> *templateNames = new QDict<int>(17);
3796 templateNames->setAutoDelete(TRUE);
3797 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
3798 if (templateArguments)
3800 ArgumentListIterator ali(*templateArguments);
3803 for (ali.toFirst();(arg=ali.current());++ali,count++)
3806 while ((i=re.match(name,p,&l))!=-1)
3808 QCString n = name.mid(i,l);
3811 if (templateNames->find(n)==0)
3813 templateNames->insert(n,new int(count));
3820 return templateNames;
3823 /*! Searches a class from within \a context and \a cd and returns its
3824 * definition if found (otherwise 0 is returned).
3826 static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
3828 FileDef *fd=cd->getFileDef();
3830 if (context && cd!=context)
3832 result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
3836 result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
3838 if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
3840 result = getClass(name);
3842 if (result==0 && cd && cd->getLanguage()==SrcLangExt_CSharp && name.find('<')!=-1)
3844 result = Doxygen::genericsDict.find(name);
3846 //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
3848 // context ? context->name().data() : "<none>",
3849 // cd ? cd->name().data() : "<none>",
3850 // result ? result->name().data() : "<none>",
3851 // Doxygen::classSDict->find(name)
3856 enum FindBaseClassRelation_Mode
3863 static bool findClassRelation(
3865 Definition *context,
3868 QDict<int> *templateNames,
3869 /*bool insertUndocumented*/
3870 FindBaseClassRelation_Mode mode,
3875 static void findUsedClassesForClass(EntryNav *rootNav,
3876 Definition *context,
3878 ClassDef *instanceCd,
3880 ArgumentList *actualArgs=0,
3881 QDict<int> *templateNames=0
3884 masterCd->visited=TRUE;
3885 ArgumentList *formalArgs = masterCd->templateArguments();
3886 if (masterCd->memberNameInfoSDict())
3888 MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
3889 MemberNameInfo *mni;
3890 for (;(mni=mnili.current());++mnili)
3892 MemberNameInfoIterator mnii(*mni);
3894 for (mnii.toFirst();(mi=mnii.current());++mnii)
3896 MemberDef *md=mi->memberDef;
3897 if (md->isVariable() || md->isObjCProperty()) // for each member variable in this class
3899 //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
3900 QCString type=removeRedundantWhiteSpace(md->typeString());
3901 QCString typedefValue = resolveTypeDef(masterCd,type);
3902 if (!typedefValue.isEmpty())
3904 type = typedefValue;
3907 QCString usedClassName;
3910 // the type can contain template variables, replace them if present
3913 type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
3916 //printf(" template substitution gives=%s\n",type.data());
3917 while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec,rootNav->lang())!=-1)
3919 // find the type (if any) that matches usedClassName
3920 ClassDef *typeCd = getResolvedClass(masterCd,
3921 masterCd->getFileDef(),
3926 //printf("====> usedClassName=%s -> typeCd=%s\n",
3927 // usedClassName.data(),typeCd?typeCd->name().data():"<none>");
3930 usedClassName = typeCd->name();
3933 int sp=usedClassName.find('<');
3935 int si=usedClassName.findRev("::",sp);
3938 // replace any namespace aliases
3939 replaceNamespaceAliases(usedClassName,si);
3941 // add any template arguments to the class
3942 QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
3943 //printf(" usedName=%s\n",usedName.data());
3945 bool delTempNames=FALSE;
3946 if (templateNames==0)
3948 templateNames = getTemplateArgumentsInName(formalArgs,usedName);
3951 BaseInfo bi(usedName,Public,Normal);
3952 findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
3954 if (masterCd->templateArguments())
3956 ArgumentListIterator ali(*masterCd->templateArguments());
3959 for (ali.toFirst();(arg=ali.current());++ali,++count)
3961 if (arg->name==usedName) // type is a template argument
3964 Debug::print(Debug::Classes,0," New used class `%s'\n", usedName.data());
3966 ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
3969 usedCd = new ClassDef(
3970 masterCd->getDefFileName(),masterCd->getDefLine(),
3971 usedName,ClassDef::Class);
3972 //printf("making %s a template argument!!!\n",usedCd->name().data());
3973 usedCd->makeTemplateArgument();
3974 usedCd->setUsedOnly(TRUE);
3975 usedCd->setLanguage(masterCd->getLanguage());
3976 Doxygen::hiddenClasses->append(usedName,usedCd);
3980 if (isArtificial) usedCd->setArtificial(TRUE);
3981 Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", usedCd->name().data());
3982 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
3983 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
3991 ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
3992 //printf("Looking for used class %s: result=%s master=%s\n",
3993 // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
3998 Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", usedCd->name().data());
3999 instanceCd->addUsedClass(usedCd,md->name(),md->protection()); // class exists
4000 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4005 delete templateNames;
4009 if (!found && !type.isEmpty()) // used class is not documented in any scope
4011 ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
4012 if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
4014 if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
4016 type+=md->argsString();
4018 Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", type.data());
4019 usedCd = new ClassDef(
4020 masterCd->getDefFileName(),masterCd->getDefLine(),
4021 type,ClassDef::Class);
4022 usedCd->setUsedOnly(TRUE);
4023 usedCd->setLanguage(masterCd->getLanguage());
4024 Doxygen::hiddenClasses->append(type,usedCd);
4028 if (isArtificial) usedCd->setArtificial(TRUE);
4029 Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", usedCd->name().data());
4030 instanceCd->addUsedClass(usedCd,md->name(),md->protection());
4031 usedCd->addUsedByClass(instanceCd,md->name(),md->protection());
4040 //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
4044 static void findBaseClassesForClass(
4046 Definition *context,
4048 ClassDef *instanceCd,
4049 FindBaseClassRelation_Mode mode,
4051 ArgumentList *actualArgs=0,
4052 QDict<int> *templateNames=0
4055 Entry *root = rootNav->entry();
4056 //if (masterCd->visited) return;
4057 masterCd->visited=TRUE;
4058 // The base class could ofcouse also be a non-nested class
4059 ArgumentList *formalArgs = masterCd->templateArguments();
4060 QListIterator<BaseInfo> bii(*root->extends);
4062 for (bii.toFirst();(bi=bii.current());++bii)
4064 //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
4065 // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
4066 bool delTempNames=FALSE;
4067 if (templateNames==0)
4069 templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
4072 BaseInfo tbi(bi->name,bi->prot,bi->virt);
4073 if (actualArgs) // substitute the formal template arguments of the base class
4075 tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
4077 //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
4079 if (mode==DocumentedOnly)
4081 // find a documented base class in the correct scope
4082 if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
4084 // 1.8.2: decided to show inheritance relations even if not documented,
4085 // we do make them artificial, so they do not appear in the index
4086 //if (!Config_getBool("HIDE_UNDOC_RELATIONS"))
4087 bool b = Config_getBool("HIDE_UNDOC_RELATIONS") ? TRUE : isArtificial;
4089 // no documented base class -> try to find an undocumented one
4090 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,b);
4094 else if (mode==TemplateInstances)
4096 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
4100 delete templateNames;
4106 //----------------------------------------------------------------------
4108 static bool findTemplateInstanceRelation(Entry *root,
4109 Definition *context,
4110 ClassDef *templateClass,const QCString &templSpec,
4111 QDict<int> *templateNames,
4114 Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n",
4115 templateClass->name().data(),templSpec.data());
4116 //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
4117 // templateClass->name().data(),templSpec.data());
4118 //if (templateNames)
4120 // QDictIterator<int> qdi(*templateNames);
4121 // int *tempArgIndex;
4122 // for (;(tempArgIndex=qdi.current());++qdi)
4124 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4129 bool existingClass = (templSpec ==
4130 tempArgListToString(templateClass->templateArguments())
4132 if (existingClass) return TRUE;
4134 bool freshInstance=FALSE;
4135 ClassDef *instanceClass = templateClass->insertTemplateInstance(
4136 root->fileName,root->startLine,templSpec,freshInstance);
4137 if (isArtificial) instanceClass->setArtificial(TRUE);
4138 instanceClass->setLanguage(root->lang);
4142 Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",instanceClass->name().data());
4143 Doxygen::classSDict->append(instanceClass->name(),instanceClass);
4144 instanceClass->setTemplateBaseClassNames(templateNames);
4146 // search for new template instances caused by base classes of
4148 EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
4149 if (templateRootNav)
4151 bool unloadNeeded=FALSE;
4152 Entry *templateRoot = templateRootNav->entry();
4153 if (templateRoot==0) // not yet loaded
4155 templateRootNav->loadEntry(g_storage);
4156 templateRoot = templateRootNav->entry();
4157 ASSERT(templateRoot!=0); // now it should really be loaded
4161 Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",
4162 templateRoot->name.data(),templSpec.data());
4163 ArgumentList *templArgs = new ArgumentList;
4164 stringToArgumentList(templSpec,templArgs);
4165 findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4166 TemplateInstances,isArtificial,templArgs,templateNames);
4168 findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4169 isArtificial,templArgs,templateNames);
4172 if (unloadNeeded) // still cleanup to do
4174 templateRootNav->releaseEntry();
4179 Debug::print(Debug::Classes,0," no template root entry found!\n");
4180 // TODO: what happened if we get here?
4183 //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data());
4184 //ArgumentList *tl = templateClass->templateArguments();
4188 Debug::print(Debug::Classes,0," instance already exists!\n");
4193 static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4196 int index=n.find('<');
4201 bool result = rightScopeMatch(scope,n);
4205 /*! Searches for the end of a template in prototype \a s starting from
4206 * character position \a startPos. If the end was found the position
4207 * of the closing \> is returned, otherwise -1 is returned.
4209 * Handles exotic cases such as
4218 static int findEndOfTemplate(const QCString &s,int startPos)
4220 // locate end of template
4224 int len = s.length();
4225 bool insideString=FALSE;
4226 bool insideChar=FALSE;
4228 while (e<len && brCount!=0)
4234 if (!insideString && !insideChar)
4236 if (e<len-1 && s.at(e+1)=='<')
4238 else if (roundCount==0)
4243 if (!insideString && !insideChar)
4245 if (e<len-1 && s.at(e+1)=='>')
4247 else if (roundCount==0)
4252 if (!insideString && !insideChar)
4256 if (!insideString && !insideChar)
4262 if (insideString && pc!='\\')
4271 if (insideChar && pc!='\\')
4281 return brCount==0 ? e : -1;
4284 static bool findClassRelation(
4286 Definition *context,
4289 QDict<int> *templateNames,
4290 FindBaseClassRelation_Mode mode,
4294 //printf("findClassRelation(class=%s base=%s templateNames=",
4295 // cd->name().data(),bi->name.data());
4296 //if (templateNames)
4298 // QDictIterator<int> qdi(*templateNames);
4299 // int *tempArgIndex;
4300 // for (;(tempArgIndex=qdi.current());++qdi)
4302 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4307 Entry *root = rootNav->entry();
4309 QCString biName=bi->name;
4310 bool explicitGlobalScope=FALSE;
4311 //printf("findClassRelation: biName=`%s'\n",biName.data());
4312 if (biName.left(2)=="::") // explicit global scope
4314 biName=biName.right(biName.length()-2);
4315 explicitGlobalScope=TRUE;
4318 EntryNav *parentNode=rootNav->parent();
4319 bool lastParent=FALSE;
4320 do // for each parent scope, starting with the largest scope
4321 // (in case of nested classes)
4323 QCString scopeName= parentNode ? parentNode->name().data() : "";
4324 int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4325 do // try all parent scope prefixes, starting with the largest scope
4327 //printf("scopePrefix=`%s' biName=`%s'\n",
4328 // scopeName.left(scopeOffset).data(),biName.data());
4330 QCString baseClassName=biName;
4333 baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4335 //QCString stripped;
4336 //baseClassName=stripTemplateSpecifiersFromScope
4337 // (removeRedundantWhiteSpace(baseClassName),TRUE,
4339 MemberDef *baseClassTypeDef=0;
4341 ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4349 //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4350 // baseClassName.data(),baseClass,cd,explicitGlobalScope);
4351 //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4352 // cd ? cd->name().data():"<none>",
4353 // baseClassName.data(),
4354 // baseClass?baseClass->name().data():"<none>",
4357 //if (baseClassName.left(root->name.length())!=root->name ||
4358 // baseClassName.at(root->name.length())!='<'
4359 // ) // Check for base class with the same name.
4360 // // If found then look in the outer scope for a match
4361 // // and prevent recursion.
4362 if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope)
4365 Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4366 baseClassName.data(),
4367 rootNav->name().data(),
4368 (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4369 (bi->virt==Normal)?"normal":"virtual",
4373 int i=baseClassName.find('<');
4374 int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4376 if (baseClass==0 && i!=-1)
4377 // base class has template specifiers
4379 if (root->lang == SrcLangExt_CSharp)
4381 baseClass = Doxygen::genericsDict.find(baseClassName);
4385 // TODO: here we should try to find the correct template specialization
4386 // but for now, we only look for the unspecializated base class.
4387 int e=findEndOfTemplate(baseClassName,i+1);
4388 //printf("baseClass==0 i=%d e=%d\n",i,e);
4389 if (e!=-1) // end of template was found at e
4391 templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4392 baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4393 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4401 //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4402 // baseClass,baseClassName.data(),templSpec.data());
4406 else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4407 // know it is a template, so see if
4408 // we can also link to the explicit
4409 // instance (for instance if a class
4410 // derived from a template argument)
4412 //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4413 ClassDef *templClass=getClass(baseClass->name()+templSpec);
4416 // use the template instance instead of the template base.
4417 baseClass = templClass;
4418 templSpec.resize(0);
4422 //printf("cd=%p baseClass=%p\n",cd,baseClass);
4423 bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4424 //printf("1. found=%d\n",found);
4425 if (!found && si!=-1)
4427 QCString tmpTemplSpec;
4428 // replace any namespace aliases
4429 replaceNamespaceAliases(baseClassName,si);
4430 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4438 found=baseClass!=0 && baseClass!=cd;
4439 if (found) templSpec = tmpTemplSpec;
4441 //printf("2. found=%d\n",found);
4443 //printf("root->name=%s biName=%s baseClassName=%s\n",
4444 // root->name.data(),biName.data(),baseClassName.data());
4445 //if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4447 // baseClassName+="-g";
4452 baseClass=findClassWithinClassContext(context,cd,baseClassName);
4453 //printf("findClassWithinClassContext(%s,%s)=%p\n",
4454 // cd->name().data(),baseClassName.data(),baseClass);
4455 found = baseClass!=0 && baseClass!=cd;
4460 // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4461 // the class name also in the alias mapping.
4462 QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4463 if (aliasName) // see if it is indeed a class.
4465 baseClass=getClass(*aliasName);
4466 found = baseClass!=0 && baseClass!=cd;
4469 bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4470 // make templSpec canonical
4471 // warning: the following line doesn't work for Mixin classes (see bug 560623)
4472 // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4474 //printf("3. found=%d\n",found);
4477 Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
4478 // add base class to this class
4480 // if templSpec is not empty then we should "instantiate"
4481 // the template baseClass. A new ClassDef should be created
4482 // to represent the instance. To be able to add the (instantiated)
4483 // members and documentation of a template class
4484 // (inserted in that template class at a later stage),
4485 // the template should know about its instances.
4486 // the instantiation process, should be done in a recursive way,
4487 // since instantiating a template may introduce new inheritance
4489 if (!templSpec.isEmpty() && mode==TemplateInstances)
4491 // if baseClass is actually a typedef then we should not
4492 // instantiate it, since typedefs are in a different namespace
4493 // see bug531637 for an example where this would otherwise hang
4495 if (baseClassTypeDef==0)
4497 //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4498 findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4501 else if (mode==DocumentedOnly || mode==Undocumented)
4503 //printf(" => insert base class\n");
4505 if (baseClassTypeDef || cd->isCSharp())
4508 //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4510 if (Config_getBool("SIP_SUPPORT")) bi->prot=Public;
4511 cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4512 // add this class as super class to the base class
4513 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4517 else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4519 Debug::print(Debug::Classes,0,
4520 " New undocumented base class `%s' baseClassName=%s templSpec=%s isArtificial=%d\n",
4521 biName.data(),baseClassName.data(),templSpec.data(),isArtificial
4524 if (isATemplateArgument)
4526 baseClass=Doxygen::hiddenClasses->find(baseClassName);
4529 baseClass=new ClassDef(root->fileName,root->startLine,
4530 baseClassName,ClassDef::Class);
4531 Doxygen::hiddenClasses->append(baseClassName,baseClass);
4532 if (isArtificial) baseClass->setArtificial(TRUE);
4533 baseClass->setLanguage(root->lang);
4538 baseClass=Doxygen::classSDict->find(baseClassName);
4539 //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4540 // baseClassName.data(),baseClass,biName.data(),templSpec.data());
4543 baseClass=new ClassDef(root->fileName,root->startLine,
4544 baseClassName,ClassDef::Class);
4545 Doxygen::classSDict->append(baseClassName,baseClass);
4546 if (isArtificial) baseClass->setArtificial(TRUE);
4547 baseClass->setLanguage(root->lang);
4550 if (biName.right(2)=="-p")
4552 biName="<"+biName.left(biName.length()-2)+">";
4554 // add base class to this class
4555 cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4556 // add this class as super class to the base class
4557 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4558 // the undocumented base was found in this file
4559 baseClass->insertUsedFile(root->fileName);
4560 baseClass->setOuterScope(Doxygen::globalScope);
4561 if (baseClassName.right(2)=="-p")
4563 baseClass->setCompoundType(ClassDef::Protocol);
4569 Debug::print(Debug::Classes,0," Base class `%s' not found\n",biName.data());
4574 if (mode!=TemplateInstances)
4576 warn(root->fileName,root->startLine,
4577 "Detected potential recursive class relation "
4578 "between class %s and base class %s!\n",
4579 root->name.data(),baseClassName.data()
4582 // for mode==TemplateInstance this case is quite common and
4583 // indicates a relation between a template class and a template
4584 // instance with the same name.
4590 else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4594 //printf("new scopeOffset=`%d'",scopeOffset);
4595 } while (scopeOffset>=0);
4603 parentNode=parentNode->parent();
4605 } while (lastParent);
4610 //----------------------------------------------------------------------
4611 // Computes the base and super classes for each class in the tree
4613 static bool isClassSection(EntryNav *rootNav)
4615 if ( !rootNav->name().isEmpty() )
4617 if (rootNav->section() & Entry::COMPOUND_MASK)
4618 // is it a compound (class, struct, union, interface ...)
4622 else if (rootNav->section() & Entry::COMPOUNDDOC_MASK)
4623 // is it a documentation block with inheritance info.
4625 rootNav->loadEntry(g_storage);
4626 Entry *root = rootNav->entry();
4627 bool extends = root->extends->count()>0;
4628 rootNav->releaseEntry();
4629 if (extends) return TRUE;
4636 /*! Builds a dictionary of all entry nodes in the tree starting with \a root
4638 static void findClassEntries(EntryNav *rootNav)
4640 if (isClassSection(rootNav))
4642 g_classEntries.insert(rootNav->name(),rootNav);
4644 RECURSE_ENTRYTREE(findClassEntries,rootNav);
4647 /*! Using the dictionary build by findClassEntries(), this
4648 * function will look for additional template specialization that
4649 * exists as inheritance relations only. These instances will be
4650 * added to the template they are derived from.
4652 static void findInheritedTemplateInstances()
4654 ClassSDict::Iterator cli(*Doxygen::classSDict);
4655 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4656 QDictIterator<EntryNav> edi(g_classEntries);
4658 for (;(rootNav=edi.current());++edi)
4661 // strip any anonymous scopes first
4662 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4663 bName=stripTemplateSpecifiersFromScope(bName);
4664 Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",bName.data());
4665 if ((cd=getClass(bName)))
4667 rootNav->loadEntry(g_storage);
4668 //printf("Class %s %d\n",cd->name().data(),root->extends->count());
4669 findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
4670 rootNav->releaseEntry();
4675 static void findUsedTemplateInstances()
4677 ClassSDict::Iterator cli(*Doxygen::classSDict);
4678 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4679 QDictIterator<EntryNav> edi(g_classEntries);
4681 for (;(rootNav=edi.current());++edi)
4684 // strip any anonymous scopes first
4685 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4686 bName=stripTemplateSpecifiersFromScope(bName);
4687 Debug::print(Debug::Classes,0," Usage: Class %s : \n",bName.data());
4688 if ((cd=getClass(bName)))
4690 rootNav->loadEntry(g_storage);
4691 findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
4692 rootNav->releaseEntry();
4697 static void computeClassRelations()
4699 ClassSDict::Iterator cli(*Doxygen::classSDict);
4700 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4701 QDictIterator<EntryNav> edi(g_classEntries);
4703 for (;(rootNav=edi.current());++edi)
4707 rootNav->loadEntry(g_storage);
4708 Entry *root = rootNav->entry();
4710 // strip any anonymous scopes first
4711 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4712 bName=stripTemplateSpecifiersFromScope(bName);
4713 Debug::print(Debug::Classes,0," Relations: Class %s : \n",bName.data());
4714 if ((cd=getClass(bName)))
4716 findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
4718 int numMembers = cd && cd->memberNameInfoSDict() ? cd->memberNameInfoSDict()->count() : 0;
4719 if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) && numMembers>0 &&
4720 bName.right(2)!="::")
4722 if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
4723 (guessSection(root->fileName)==Entry::HEADER_SEC ||
4724 Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
4725 protectionLevelVisible(root->protection) && // hidden by protection
4726 !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
4729 root->fileName,root->startLine,
4730 "warning: Compound %s is not documented.",
4735 rootNav->releaseEntry();
4739 static void computeTemplateClassRelations()
4741 QDictIterator<EntryNav> edi(g_classEntries);
4743 for (;(rootNav=edi.current());++edi)
4745 rootNav->loadEntry(g_storage);
4746 Entry *root = rootNav->entry();
4748 QCString bName=stripAnonymousNamespaceScope(root->name);
4749 bName=stripTemplateSpecifiersFromScope(bName);
4750 ClassDef *cd=getClass(bName);
4751 // strip any anonymous scopes first
4752 QDict<ClassDef> *templInstances = 0;
4753 if (cd && (templInstances=cd->getTemplateInstances()))
4755 Debug::print(Debug::Classes,0," Template class %s : \n",cd->name().data());
4756 QDictIterator<ClassDef> tdi(*templInstances);
4758 for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
4760 Debug::print(Debug::Classes,0," Template instance %s : \n",tcd->name().data());
4761 QCString templSpec = tdi.currentKey();
4762 ArgumentList *templArgs = new ArgumentList;
4763 stringToArgumentList(templSpec,templArgs);
4764 QList<BaseInfo> *baseList=root->extends;
4765 BaseInfo *bi=baseList->first();
4766 while (bi) // for each base class of the template
4768 // check if the base class is a template argument
4769 BaseInfo tbi(bi->name,bi->prot,bi->virt);
4770 ArgumentList *tl = cd->templateArguments();
4773 QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
4774 QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
4775 // for each template name that we inherit from we need to
4776 // substitute the formal with the actual arguments
4777 QDict<int> *actualTemplateNames = new QDict<int>(17);
4778 actualTemplateNames->setAutoDelete(TRUE);
4779 QDictIterator<int> qdi(*templateNames);
4780 for (qdi.toFirst();qdi.current();++qdi)
4782 int templIndex = *qdi.current();
4783 Argument *actArg = 0;
4784 if (templIndex<(int)templArgs->count())
4786 actArg=templArgs->at(templIndex);
4789 baseClassNames!=0 &&
4790 baseClassNames->find(actArg->type)!=0 &&
4791 actualTemplateNames->find(actArg->type)==0
4794 actualTemplateNames->insert(actArg->type,new int(templIndex));
4797 delete templateNames;
4799 tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
4800 // find a documented base class in the correct scope
4801 if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
4803 // no documented base class -> try to find an undocumented one
4804 findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE);
4806 delete actualTemplateNames;
4808 bi=baseList->next();
4811 } // class has no base classes
4814 rootNav->releaseEntry();
4818 //-----------------------------------------------------------------------
4819 // compute the references (anchors in HTML) for each function in the file
4821 static void computeMemberReferences()
4823 ClassSDict::Iterator cli(*Doxygen::classSDict);
4825 for (cli.toFirst();(cd=cli.current());++cli)
4827 cd->computeAnchors();
4829 FileName *fn=Doxygen::inputNameList->first();
4832 FileDef *fd=fn->first();
4835 fd->computeAnchors();
4838 fn=Doxygen::inputNameList->next();
4840 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
4842 for (nli.toFirst();(nd=nli.current());++nli)
4844 nd->computeAnchors();
4846 GroupSDict::Iterator gli(*Doxygen::groupSDict);
4848 for (gli.toFirst();(gd=gli.current());++gli)
4850 gd->computeAnchors();
4854 //----------------------------------------------------------------------
4856 static void addListReferences()
4858 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
4860 for (mnli.toFirst();(mn=mnli.current());++mnli)
4862 MemberNameIterator mni(*mn);
4864 for (mni.toFirst();(md=mni.current());++mni)
4869 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
4870 for (fnli.toFirst();(mn=fnli.current());++fnli)
4872 MemberNameIterator mni(*mn);
4874 for (mni.toFirst();(md=mni.current());++mni)
4880 ClassSDict::Iterator cli(*Doxygen::classSDict);
4882 for (cli.toFirst();(cd=cli.current());++cli)
4884 cd->addListReferences();
4886 FileName *fn=Doxygen::inputNameList->first();
4889 FileDef *fd=fn->first();
4892 fd->addListReferences();
4895 fn=Doxygen::inputNameList->next();
4897 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
4899 for (nli.toFirst();(nd=nli.current());++nli)
4901 nd->addListReferences();
4903 GroupSDict::Iterator gli(*Doxygen::groupSDict);
4905 for (gli.toFirst();(gd=gli.current());++gli)
4907 gd->addListReferences();
4909 PageSDict::Iterator pdi(*Doxygen::pageSDict);
4911 for (pdi.toFirst();(pd=pdi.current());++pdi)
4913 QCString name = pd->getOutputFileBase();
4914 if (pd->getGroupDef())
4916 name = pd->getGroupDef()->getOutputFileBase();
4919 LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems();
4920 addRefItem(xrefItems.pointer(),
4922 theTranslator->trPage(TRUE,TRUE),
4923 name,pd->title(),0);
4926 DirSDict::Iterator ddi(*Doxygen::directories);
4928 for (ddi.toFirst();(dd=ddi.current());++ddi)
4930 QCString name = dd->getOutputFileBase();
4931 //if (dd->getGroupDef())
4933 // name = dd->getGroupDef()->getOutputFileBase();
4935 LockingPtr< QList<ListItemInfo> > xrefItems = dd->xrefListItems();
4936 addRefItem(xrefItems.pointer(),
4938 theTranslator->trDir(TRUE,TRUE),
4939 name,dd->displayName(),0);
4943 //----------------------------------------------------------------------
4945 static void generateXRefPages()
4947 QDictIterator<RefList> di(*Doxygen::xrefLists);
4949 for (di.toFirst();(rl=di.current());++di)
4955 //----------------------------------------------------------------------
4956 // Copy the documentation in entry `root' to member definition `md' and
4957 // set the function declaration of the member to `funcDecl'. If the boolean
4958 // over_load is set the standard overload text is added.
4960 static void addMemberDocs(EntryNav *rootNav,
4961 MemberDef *md, const char *funcDecl,
4967 Entry *root = rootNav->entry();
4968 //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
4969 // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
4970 QCString fDecl=funcDecl;
4971 // strip extern specifier
4972 fDecl.stripPrefix("extern ");
4973 md->setDefinition(fDecl);
4974 md->enableCallGraph(root->callGraph);
4975 md->enableCallerGraph(root->callerGraph);
4976 ClassDef *cd=md->getClassDef();
4977 NamespaceDef *nd=md->getNamespaceDef();
4980 fullName = cd->name();
4982 fullName = nd->name();
4984 if (!fullName.isEmpty()) fullName+="::";
4985 fullName+=md->name();
4986 FileDef *rfd=rootNav->fileDef();
4988 // TODO determine scope based on root not md
4989 Definition *rscope = md->getOuterScope();
4991 LockingPtr<ArgumentList> mdAl = md->argumentList();
4994 //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
4995 mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty());
5000 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
5001 rscope,rfd,root->argList,
5006 //printf("merging arguments (2)\n");
5007 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
5010 if (over_load) // the \overload keyword was used
5012 QCString doc=getOverloadDocs();
5013 if (!root->doc.isEmpty())
5018 md->setDocumentation(doc,root->docFile,root->docLine);
5019 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5020 md->setDocsForDefinition(!root->proto);
5024 //printf("overwrite!\n");
5025 md->setDocumentation(root->doc,root->docFile,root->docLine);
5026 md->setDocsForDefinition(!root->proto);
5028 //printf("overwrite!\n");
5029 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
5032 (md->inbodyDocumentation().isEmpty() ||
5033 !rootNav->parent()->name().isEmpty()
5034 ) && !root->inbodyDocs.isEmpty()
5037 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5041 //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
5042 // md->initializer().data(),md->initializer().isEmpty(),
5043 // root->initializer.data(),root->initializer.isEmpty()
5045 if (md->initializer().isEmpty() && !root->initializer.isEmpty())
5047 //printf("setInitializer\n");
5048 md->setInitializer(root->initializer);
5051 md->setMaxInitLines(root->initLines);
5055 if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
5058 //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
5059 md->setBodySegment(root->bodyLine,root->endBodyLine);
5060 md->setBodyDef(rfd);
5063 md->setRefItems(root->sli);
5066 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
5067 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
5069 md->mergeMemberSpecifiers(root->spec);
5070 md->addSectionsToDefinition(root->anchors);
5071 addMemberToGroups(root,md);
5072 if (cd) cd->insertUsedFile(root->fileName);
5073 //printf("root->mGrpId=%d\n",root->mGrpId);
5074 if (root->mGrpId!=-1)
5076 if (md->getMemberGroupId()!=-1)
5078 if (md->getMemberGroupId()!=root->mGrpId)
5081 root->fileName,root->startLine,
5082 "warning: member %s belongs to two different groups. The second "
5083 "one found here will be ignored.",
5088 else // set group id
5090 //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
5091 md->setMemberGroupId(root->mGrpId);
5096 //----------------------------------------------------------------------
5097 // find a class definition given the scope name and (optionally) a
5098 // template list specifier
5100 static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
5101 const char *scopeName)
5103 ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
5108 //----------------------------------------------------------------------
5109 // Adds the documentation contained in `root' to a global function
5110 // with name `name' and argument list `args' (for overloading) and
5111 // function declaration `decl' to the corresponding member definition.
5113 static bool findGlobalMember(EntryNav *rootNav,
5114 const QCString &namespaceName,
5116 const char *tempArg,
5120 Entry *root = rootNav->entry();
5121 Debug::print(Debug::FindMembers,0,
5122 "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n",
5123 namespaceName.data(),name,tempArg,decl);
5125 if (n.isEmpty()) return FALSE;
5126 if (n.find("::")!=-1) return FALSE; // skip undefined class members
5127 MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
5130 mn=Doxygen::functionNameSDict->find(n); // try without template arguments
5132 if (mn) // function name defined
5134 Debug::print(Debug::FindMembers,0,"3. Found function scope\n");
5136 MemberNameIterator mni(*mn);
5139 for (mni.toFirst();(md=mni.current()) && !found;++mni)
5141 NamespaceDef *nd=md->getNamespaceDef();
5143 //printf("Namespace namespaceName=%s nd=%s\n",
5144 // namespaceName.data(),nd ? nd->name().data() : "<none>");
5146 FileDef *fd=rootNav->fileDef();
5147 //printf("File %s\n",fd ? fd->name().data() : "<none>");
5148 NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
5149 //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0;
5150 //printf("NamespaceList %p\n",nl);
5152 // search in the list of namespaces that are imported via a
5153 // using declaration
5154 bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
5156 if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
5157 (nd && nd->name()==namespaceName) || // or in the same namespace
5158 viaUsingDirective // member in `using' namespace
5161 Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
5162 md->name().data(),namespaceName.data());
5163 QCString nsName = nd ? nd->name().data() : "";
5165 NamespaceDef *rnd = 0;
5166 if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
5168 LockingPtr<ArgumentList> mdAl = md->argumentList();
5170 (mdAl==0 && root->argList->count()==0) ||
5171 md->isVariable() || md->isTypedef() || /* in case of function pointers */
5172 matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(),
5173 rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5176 // for template members we need to check if the number of
5177 // template arguments is the same, otherwise we are dealing with
5178 // different functions.
5179 if (matching && root->tArgLists)
5181 LockingPtr<ArgumentList> mdTempl = md->templateArguments();
5184 if (root->tArgLists->getLast()->count()!=mdTempl->count())
5191 //printf("%s<->%s\n",
5192 // argListToString(md->argumentList()).data(),
5193 // argListToString(root->argList).data());
5195 // for static members we also check if the comment block was found in
5196 // the same file. This is needed because static members with the same
5197 // name can be in different files. Thus it would be wrong to just
5198 // put the comment block at the first syntactically matching member.
5199 if (matching && md->isStatic() &&
5200 md->getDefFileName()!=root->fileName &&
5206 if (matching) // add docs to the member
5208 Debug::print(Debug::FindMembers,0,"5. Match found\n");
5209 addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5214 if (!found && root->relatesType != Duplicate && root->section==Entry::FUNCTION_SEC) // no match
5216 QCString fullFuncDecl=decl;
5217 if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5219 QCString("warning: no matching file member found for \n")+substitute(fullFuncDecl,"%","%%");
5222 warnMsg+="\nPossible candidates:\n";
5223 for (mni.toFirst();(md=mni.current());++mni)
5226 warnMsg+=substitute(md->declaration(),"%","%%");
5227 warnMsg+="' at line "+QCString().setNum(md->getDefLine())+
5228 " of file"+md->getDefFileName()+"\n";
5231 warn(root->fileName,root->startLine,warnMsg);
5234 else // got docs for an undefined member!
5236 if (root->type!="friend class" &&
5237 root->type!="friend struct" &&
5238 root->type!="friend union" &&
5239 (!Config_getBool("TYPEDEF_HIDES_STRUCT") ||
5240 root->type.find("typedef ")==-1)
5243 warn(root->fileName,root->startLine,
5244 "warning: documented function `%s' was not declared or defined.",decl
5251 static bool isSpecialization(
5252 const QList<ArgumentList> &srcTempArgLists,
5253 const QList<ArgumentList> &dstTempArgLists
5256 QListIterator<ArgumentList> srclali(srcTempArgLists);
5257 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5258 for (;srclali.current();++srclali,++dstlali)
5260 ArgumentList *sal = srclali.current();
5261 ArgumentList *dal = dstlali.current();
5262 if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5268 static QCString substituteTemplatesInString(
5269 const QList<ArgumentList> &srcTempArgLists,
5270 const QList<ArgumentList> &dstTempArgLists,
5271 ArgumentList *funcTempArgList, // can be used to match template specializations
5276 QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5277 //printf("type=%s\n",sa->type.data());
5279 while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5282 dst+=src.mid(p,i-p);
5283 QCString name=src.mid(i,l);
5285 QListIterator<ArgumentList> srclali(srcTempArgLists);
5286 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5287 for (;srclali.current() && !found;++srclali,++dstlali)
5289 ArgumentListIterator tsali(*srclali.current());
5290 ArgumentListIterator tdali(*dstlali.current());
5291 Argument *tsa =0,*tda=0, *fa=0;
5292 if (funcTempArgList)
5294 fa=funcTempArgList->first();
5297 for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5299 tda = tdali.current();
5300 //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5301 // tsa->type.data(),tsa->name.data(),
5302 // tda->type.data(),tda->name.data());
5303 if (name==tsa->name)
5305 if (tda && tda->name.isEmpty())
5308 if (tda->type.left(6)=="class ") vc=6;
5309 else if (tda->type.left(9)=="typename ") vc=9;
5310 if (vc>0) // convert type=="class T" to type=="class" name=="T"
5312 tda->name = tda->type.mid(vc);
5313 tda->type = tda->type.left(vc-1);
5316 if (tda && !tda->name.isEmpty())
5318 name=tda->name; // substitute
5330 fa=funcTempArgList->next();
5332 //printf(" srcList='%s' dstList='%s faList='%s'\n",
5333 // argListToString(srclali.current()).data(),
5334 // argListToString(dstlali.current()).data(),
5335 // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5340 dst+=src.right(src.length()-p);
5341 //printf(" substituteTemplatesInString(%s)=%s\n",
5342 // src.data(),dst.data());
5346 static void substituteTemplatesInArgList(
5347 const QList<ArgumentList> &srcTempArgLists,
5348 const QList<ArgumentList> &dstTempArgLists,
5351 ArgumentList *funcTempArgs = 0
5354 ArgumentListIterator sali(*src);
5356 Argument *da=dst->first();
5358 for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5360 QCString dstType = substituteTemplatesInString(
5361 srcTempArgLists,dstTempArgLists,funcTempArgs,
5363 QCString dstArray = substituteTemplatesInString(
5364 srcTempArgLists,dstTempArgLists,funcTempArgs,
5368 da=new Argument(*sa);
5381 dst->constSpecifier = src->constSpecifier;
5382 dst->volatileSpecifier = src->volatileSpecifier;
5383 dst->pureSpecifier = src->pureSpecifier;
5384 dst->trailingReturnType = substituteTemplatesInString(
5385 srcTempArgLists,dstTempArgLists,
5386 funcTempArgs,src->trailingReturnType);
5387 //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5388 // argListToString(src).data(),argListToString(dst).data()
5394 /*! This function tries to find a member (in a documented class/file/namespace)
5395 * that corresponds to the function/variable declaration given in \a funcDecl.
5397 * The boolean \a overloaded is used to specify whether or not a standard
5398 * overload documentation line should be generated.
5400 * The boolean \a isFunc is a hint that indicates that this is a function
5401 * instead of a variable or typedef.
5403 static void findMember(EntryNav *rootNav,
5409 Entry *root = rootNav->entry();
5411 Debug::print(Debug::FindMembers,0,
5412 "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5413 "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5414 "spec=%d lang=%x\n",
5415 root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
5416 root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5417 root->spec,root->lang
5422 QCString namespaceName;
5426 QCString funcTempList;
5427 QCString exceptions;
5429 bool isRelated=FALSE;
5430 bool isMemberOf=FALSE;
5431 bool isFriend=FALSE;
5436 if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5441 if (funcDecl.stripPrefix("inline "))
5443 root->spec|=Entry::Inline;
5446 if (funcDecl.stripPrefix("explicit "))
5448 root->spec|=Entry::Explicit;
5451 if (funcDecl.stripPrefix("mutable "))
5453 root->spec|=Entry::Mutable;
5456 if (funcDecl.stripPrefix("virtual "))
5462 // delete any ; from the function declaration
5464 while ((sep=funcDecl.find(';'))!=-1)
5466 funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5469 // make sure the first character is a space to simplify searching.
5470 if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5472 // remove some superfluous spaces
5473 funcDecl= substitute(
5475 substitute(funcDecl,"~ ","~"),
5479 ).stripWhiteSpace();
5481 //printf("funcDecl=`%s'\n",funcDecl.data());
5482 if (isFriend && funcDecl.left(6)=="class ")
5484 //printf("friend class\n");
5485 funcDecl=funcDecl.right(funcDecl.length()-6);
5486 funcName = funcDecl.copy();
5488 else if (isFriend && funcDecl.left(7)=="struct ")
5490 funcDecl=funcDecl.right(funcDecl.length()-7);
5491 funcName = funcDecl.copy();
5495 // extract information from the declarations
5496 parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5497 funcArgs,funcTempList,exceptions
5500 //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5501 // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5503 // the class name can also be a namespace name, we decide this later.
5504 // if a related class name is specified and the class name could
5505 // not be derived from the function declaration, then use the
5507 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5508 // scopeName.data(),className.data(),namespaceName.data());
5509 if (!root->relates.isEmpty())
5510 { // related member, prefix user specified scope
5512 isMemberOf=(root->relatesType == MemberOf);
5513 if (getClass(root->relates)==0 && !scopeName.isEmpty())
5515 scopeName= mergeScopes(scopeName,root->relates);
5519 scopeName = root->relates;
5523 if (root->relates.isEmpty() && rootNav->parent() &&
5524 ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5525 (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5527 !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName
5528 // with the scope in which it was found
5530 QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5531 if (!scopeName.isEmpty() &&
5532 (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5534 scopeName = joinedName;
5538 scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5541 else // see if we can prefix a namespace or class that is used from the file
5543 FileDef *fd=rootNav->fileDef();
5546 NamespaceSDict *fnl = fd->getUsedNamespaces();
5549 QCString joinedName;
5551 NamespaceSDict::Iterator nsdi(*fnl);
5552 for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5554 joinedName = fnd->name()+"::"+scopeName;
5555 if (Doxygen::namespaceSDict->find(joinedName))
5557 scopeName=joinedName;
5564 scopeName=stripTemplateSpecifiersFromScope(
5565 removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
5567 // funcSpec contains the last template specifiers of the given scope.
5568 // If this method does not have any template arguments or they are
5569 // empty while funcSpec is not empty we assume this is a
5570 // specialization of a method. If not, we clear the funcSpec and treat
5571 // this as a normal method of a template class.
5572 if (!(root->tArgLists &&
5573 root->tArgLists->count()>0 &&
5574 root->tArgLists->first()->count()==0
5581 // split scope into a namespace and a class part
5582 extractNamespaceName(scopeName,className,namespaceName,TRUE);
5583 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5584 // scopeName.data(),className.data(),namespaceName.data());
5586 //namespaceName=removeAnonymousScopes(namespaceName);
5587 if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5589 //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5590 // merge class and namespace scopes again
5591 scopeName.resize(0);
5592 if (!namespaceName.isEmpty())
5594 if (className.isEmpty())
5596 scopeName=namespaceName;
5598 else if (!root->relates.isEmpty() || // relates command with explicit scope
5599 !getClass(className)) // class name only exists in a namespace
5601 scopeName=namespaceName+"::"+className;
5605 scopeName=className;
5608 else if (!className.isEmpty())
5610 scopeName=className;
5612 //printf("new scope=`%s'\n",scopeName.data());
5614 QCString tempScopeName=scopeName;
5615 ClassDef *cd=getClass(scopeName);
5618 if (root->tArgLists) root->tArgLists->first();
5619 if (funcSpec.isEmpty())
5621 tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists);
5625 tempScopeName=scopeName+funcSpec;
5628 //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
5629 // scopeName.data(),cd,root->tArgLists,tempScopeName.data());
5631 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
5632 // rebuild the function declaration (needed to get the scope right).
5633 if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
5635 if (!funcType.isEmpty())
5637 if (isFunc) // a function -> we use argList for the arguments
5639 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
5643 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
5648 if (isFunc) // a function => we use argList for the arguments
5650 funcDecl=tempScopeName+"::"+funcName+funcTempList;
5652 else // variable => add `argument' list
5654 funcDecl=tempScopeName+"::"+funcName+funcArgs;
5658 else // build declaration without scope
5660 if (!funcType.isEmpty()) // but with a type
5662 if (isFunc) // function => omit argument list
5664 funcDecl=funcType+" "+funcName+funcTempList;
5666 else // variable => add `argument' list
5668 funcDecl=funcType+" "+funcName+funcArgs;
5675 funcDecl=funcName+funcTempList;
5679 funcDecl=funcName+funcArgs;
5684 if (funcType=="template class" && !funcTempList.isEmpty())
5685 return; // ignore explicit template instantiations
5687 Debug::print(Debug::FindMembers,0,
5688 "findMember() Parse results:\n"
5689 " namespaceName=`%s'\n"
5695 " funcTempList=`%s'\n"
5698 " exceptions=`%s'\n"
5703 namespaceName.data(),className.data(),
5704 funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
5705 funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,
5710 if (!funcName.isEmpty()) // function name is valid
5712 Debug::print(Debug::FindMembers,0,
5713 "1. funcName=`%s'\n",funcName.data());
5714 if (funcName.left(9)=="operator ") // strip class scope from cast operator
5716 funcName = substitute(funcName,className+"::","");
5718 if (!funcTempList.isEmpty()) // try with member specialization
5720 mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
5722 if (mn==0) // try without specialization
5724 mn=Doxygen::memberNameSDict->find(funcName);
5726 if (!isRelated && mn) // function name already found
5728 Debug::print(Debug::FindMembers,0,
5729 "2. member name exists (%d members with this name)\n",mn->count());
5730 if (!className.isEmpty()) // class name is valid
5732 if (funcSpec.isEmpty()) // not a member specialization
5736 MemberNameIterator mni(*mn);
5738 bool memFound=FALSE;
5739 for (mni.toFirst();!memFound && (md=mni.current());++mni)
5741 ClassDef *cd=md->getClassDef();
5742 Debug::print(Debug::FindMembers,0,
5743 "3. member definition found, "
5744 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
5745 scopeName.data(),cd ? cd->name().data() : "<none>",
5747 root->fileName.data());
5748 //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
5749 FileDef *fd=rootNav->fileDef();
5751 if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
5753 //printf("scopeName %s->%s\n",scopeName.data(),
5754 // stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
5756 ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
5757 if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
5759 // don't be fooled by anonymous scopes
5762 //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
5763 // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
5765 if (cd && tcd==cd) // member's classes match
5767 Debug::print(Debug::FindMembers,0,
5768 "4. class definition %s found\n",cd->name().data());
5770 // get the template parameter lists found at the member declaration
5771 QList<ArgumentList> declTemplArgs;
5772 cd->getTemplateParameterLists(declTemplArgs);
5773 LockingPtr<ArgumentList> templAl = md->templateArguments();
5776 declTemplArgs.append(templAl.pointer());
5779 // get the template parameter lists found at the member definition
5780 QList<ArgumentList> *defTemplArgs = root->tArgLists;
5781 //printf("defTemplArgs=%p\n",defTemplArgs);
5783 // do we replace the decl argument lists with the def argument lists?
5784 bool substDone=FALSE;
5785 ArgumentList *argList=0;
5787 /* substitute the occurrences of class template names in the
5788 * argument list before matching
5790 LockingPtr<ArgumentList> mdAl = md->argumentList();
5791 if (declTemplArgs.count()>0 && defTemplArgs &&
5792 declTemplArgs.count()==defTemplArgs->count() &&
5796 /* the function definition has template arguments
5797 * and the class definition also has template arguments, so
5798 * we must substitute the template names of the class by that
5799 * of the function definition before matching.
5801 argList = new ArgumentList;
5802 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
5803 mdAl.pointer(),argList);
5807 else /* no template arguments, compare argument lists directly */
5809 argList = mdAl.pointer();
5812 Debug::print(Debug::FindMembers,0,
5813 "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
5814 argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
5815 className.data(),namespaceName.data()
5819 md->isVariable() || md->isTypedef() || // needed for function pointers
5820 (mdAl.pointer()==0 && root->argList->count()==0) ||
5822 md->getClassDef(),md->getFileDef(),argList,
5823 cd,fd,root->argList,
5826 if (md->getLanguage()==SrcLangExt_ObjC && md->isVariable() && (root->section&Entry::FUNCTION_SEC))
5828 matching = FALSE; // don't match methods and attributes with the same name
5831 Debug::print(Debug::FindMembers,0,
5832 "6. match results of matchArguments2 = %d\n",matching);
5834 if (substDone) // found a new argument list
5836 if (matching) // replace member's argument list
5838 md->setDefinitionTemplateParameterLists(root->tArgLists);
5839 md->setArgumentList(argList); // new owner of the list => no delete
5843 if (!funcTempList.isEmpty() &&
5844 isSpecialization(declTemplArgs,*defTemplArgs))
5846 // check if we are dealing with a partial template
5847 // specialization. In this case we add it to the class
5848 // even though the member arguments do not match.
5850 // TODO: copy other aspects?
5851 root->protection=md->protection(); // copy protection level
5852 addMethodToClass(rootNav,cd,md->name(),isFriend);
5860 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
5865 else if (cd && cd!=tcd) // we did find a class with the same name as cd
5866 // but in a different namespace
5871 if (count==0 && rootNav->parent() &&
5872 rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5874 goto localObjCMethod;
5876 if (count==0 && !(isFriend && funcType=="class"))
5879 ClassDef *ecd = 0, *ucd = 0;
5880 MemberDef *emd = 0, *umd = 0;
5883 //printf("Assume template class\n");
5884 for (mni.toFirst();(md=mni.current());++mni)
5886 ClassDef *ccd=md->getClassDef();
5888 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
5889 if (ccd!=0 && rightScopeMatch(ccd->name(),className))
5891 LockingPtr<ArgumentList> templAl = md->templateArguments();
5892 if (root->tArgLists && templAl!=0 &&
5893 root->tArgLists->getLast()->count()<=templAl->count())
5895 addMethodToClass(rootNav,ccd,md->name(),isFriend);
5898 if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
5899 { // exact argument list match -> remember
5902 Debug::print(Debug::FindMembers,0,
5903 "7. new candidate className=%s scope=%s args=%s exact match\n",
5904 className.data(),ccd->name().data(),md->argsString());
5906 else // arguments do not match, but member name and scope do -> remember
5910 Debug::print(Debug::FindMembers,0,
5911 "7. new candidate className=%s scope=%s args=%s no match\n",
5912 className.data(),ccd->name().data(),md->argsString());
5918 static bool strictProtoMatching = Config_getBool("STRICT_PROTO_MATCHING");
5919 if (!strictProtoMatching)
5921 if (candidates==1 && ucd && umd)
5923 // we didn't find an actual match on argument lists, but there is only 1 member with this
5924 // name in the same scope, so that has to be the one.
5925 addMemberDocs(rootNav,umd,funcDecl,0,overloaded,0);
5928 else if (candidates>1 && ecd && emd)
5930 // we didn't find a unique match using type resolution,
5931 // but one of the matches has the exact same signature so
5932 // we take that one.
5933 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
5938 QCString warnMsg = "warning: no ";
5939 if (noMatchCount>1) warnMsg+="uniquely ";
5940 warnMsg+="matching class member found for \n";
5942 if (root->tArgLists)
5944 QListIterator<ArgumentList> alli(*root->tArgLists);
5946 for (;(al=alli.current());++alli)
5948 warnMsg+=" template ";
5949 warnMsg+=tempArgListToString(al);
5953 QCString fullFuncDecl=funcDecl.copy();
5954 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
5957 warnMsg+=fullFuncDecl;
5962 warnMsg+="Possible candidates:\n";
5963 for (mni.toFirst();(md=mni.current());++mni)
5965 ClassDef *cd=md->getClassDef();
5966 if (cd!=0 && rightScopeMatch(cd->name(),className))
5968 LockingPtr<ArgumentList> templAl = md->templateArguments();
5971 warnMsg+=" 'template ";
5972 warnMsg+=tempArgListToString(templAl.pointer());
5976 if (md->typeString())
5978 warnMsg+=md->typeString();
5981 QCString qScope = cd->qualifiedNameWithTemplateParameters();
5982 if (!qScope.isEmpty())
5983 warnMsg+=qScope+"::"+md->name();
5984 if (md->argsString())
5985 warnMsg+=md->argsString();
5988 warnMsg+="' at line "+QCString().setNum(md->getDefLine()) +
5989 " of file "+md->getDefFileName();
5996 warn_simple(root->fileName,root->startLine,warnMsg);
5999 else if (cd) // member specialization
6001 MemberNameIterator mni(*mn);
6002 MemberDef *declMd=0;
6004 for (mni.toFirst();(md=mni.current());++mni)
6006 if (md->getClassDef()==cd)
6008 // TODO: we should probably also check for matching arguments
6013 MemberDef::MemberType mtype=MemberDef::Function;
6014 ArgumentList *tArgList = new ArgumentList;
6015 // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6017 root->fileName,root->startLine,
6018 funcType,funcName,funcArgs,exceptions,
6019 declMd ? declMd->protection() : root->protection,
6020 root->virt,root->stat,Member,
6021 mtype,tArgList,root->argList);
6022 //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
6023 md->setTagInfo(rootNav->tagInfo());
6024 md->setLanguage(root->lang);
6025 md->setMemberClass(cd);
6026 md->setTemplateSpecialization(TRUE);
6027 md->setTypeConstraints(root->typeConstr);
6028 md->setDefinition(funcDecl);
6029 md->enableCallGraph(root->callGraph);
6030 md->enableCallerGraph(root->callerGraph);
6031 md->setDocumentation(root->doc,root->docFile,root->docLine);
6032 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6033 md->setDocsForDefinition(!root->proto);
6034 md->setPrototype(root->proto);
6035 md->addSectionsToDefinition(root->anchors);
6036 md->setBodySegment(root->bodyLine,root->endBodyLine);
6037 FileDef *fd=rootNav->fileDef();
6039 md->setMemberSpecifiers(root->spec);
6040 md->setMemberGroupId(root->mGrpId);
6042 cd->insertMember(md);
6043 md->setRefItems(root->sli);
6048 //printf("*** Specialized member %s of unknown scope %s%s found!\n",
6049 // scopeName.data(),funcName.data(),funcArgs.data());
6052 else if (overloaded) // check if the function belongs to only one class
6054 // for unique overloaded member we allow the class to be
6055 // omitted, this is to be Qt compatible. Using this should
6056 // however be avoided, because it is error prone
6057 MemberNameIterator mni(*mn);
6058 MemberDef *md=mni.toFirst();
6060 ClassDef *cd=md->getClassDef();
6062 QCString className=cd->name().copy();
6065 for (;(md=mni.current());++mni)
6067 ClassDef *cd=md->getClassDef();
6068 if (className!=cd->name()) unique=FALSE;
6072 MemberDef::MemberType mtype;
6073 if (root->mtype==Signal) mtype=MemberDef::Signal;
6074 else if (root->mtype==Slot) mtype=MemberDef::Slot;
6075 else if (root->mtype==DCOP) mtype=MemberDef::DCOP;
6076 else mtype=MemberDef::Function;
6078 // new overloaded member function
6079 ArgumentList *tArgList =
6080 getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
6081 //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
6082 MemberDef *md=new MemberDef(
6083 root->fileName,root->startLine,
6084 funcType,funcName,funcArgs,exceptions,
6085 root->protection,root->virt,root->stat,Related,
6086 mtype,tArgList,root->argList);
6087 md->setTagInfo(rootNav->tagInfo());
6088 md->setLanguage(root->lang);
6089 md->setTypeConstraints(root->typeConstr);
6090 md->setMemberClass(cd);
6091 md->setDefinition(funcDecl);
6092 md->enableCallGraph(root->callGraph);
6093 md->enableCallerGraph(root->callerGraph);
6094 QCString doc=getOverloadDocs();
6097 md->setDocumentation(doc,root->docFile,root->docLine);
6098 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6099 md->setDocsForDefinition(!root->proto);
6100 md->setPrototype(root->proto);
6101 md->addSectionsToDefinition(root->anchors);
6102 md->setBodySegment(root->bodyLine,root->endBodyLine);
6103 FileDef *fd=rootNav->fileDef();
6105 md->setMemberSpecifiers(root->spec);
6106 md->setMemberGroupId(root->mGrpId);
6108 cd->insertMember(md);
6109 cd->insertUsedFile(root->fileName);
6110 md->setRefItems(root->sli);
6113 else // unrelated function with the same name as a member
6115 if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
6117 QCString fullFuncDecl=funcDecl.copy();
6118 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6119 warn(root->fileName,root->startLine,
6120 "warning: Cannot determine class for function\n%s",
6126 else if (isRelated && !root->relates.isEmpty())
6128 Debug::print(Debug::FindMembers,0,"2. related function\n"
6129 " scopeName=%s className=%s\n",scopeName.data(),className.data());
6130 if (className.isEmpty()) className=root->relates;
6132 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6133 if ((cd=getClass(scopeName)))
6135 bool newMember=TRUE; // assume we have a new member
6136 bool newMemberName=FALSE;
6137 MemberDef *mdDefine=0;
6138 bool isDefine=FALSE;
6140 MemberName *mn = Doxygen::functionNameSDict->find(funcName);
6143 mdDefine = mn->first();
6144 while (mdDefine && !isDefine)
6146 isDefine = isDefine || mdDefine->isDefine();
6147 if (!isDefine) mdDefine = mn->next();
6152 FileDef *fd=rootNav->fileDef();
6154 if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
6156 mn=new MemberName(funcName);
6157 newMemberName=TRUE; // we create a new member name
6161 MemberDef *rmd=mn->first();
6162 while (rmd && newMember) // see if we got another member with matching arguments
6164 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
6167 className!=rmd->getOuterScope()->name() ||
6168 !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
6169 cd,fd,root->argList,
6171 if (newMember) rmd=mn->next();
6173 if (!newMember && rmd) // member already exists as rmd -> add docs
6175 //printf("addMemberDocs for related member %s\n",root->name.data());
6176 //rmd->setMemberDefTemplateArguments(root->mtArgList);
6177 addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
6181 if (newMember) // need to create a new member
6183 MemberDef::MemberType mtype;
6185 mtype=MemberDef::Define;
6186 else if (root->mtype==Signal)
6187 mtype=MemberDef::Signal;
6188 else if (root->mtype==Slot)
6189 mtype=MemberDef::Slot;
6190 else if (root->mtype==DCOP)
6191 mtype=MemberDef::DCOP;
6193 mtype=MemberDef::Function;
6195 if (isDefine && mdDefine)
6197 mdDefine->setHidden(TRUE);
6199 funcArgs=mdDefine->argsString();
6200 funcDecl=funcType + " " + funcName;
6203 //printf("New related name `%s' `%d'\n",funcName.data(),
6204 // root->argList ? (int)root->argList->count() : -1);
6206 // first note that we pass:
6207 // (root->tArgLists ? root->tArgLists->last() : 0)
6208 // for the template arguments fo the new "member."
6209 // this accurately reflects the template arguments of
6210 // the related function, which don't have to do with
6211 // those of the related class.
6212 MemberDef *md=new MemberDef(
6213 root->fileName,root->startLine,
6214 funcType,funcName,funcArgs,exceptions,
6215 root->protection,root->virt,
6216 root->stat && !isMemberOf,
6217 isMemberOf ? Foreign : isRelated ? Related : Member,
6219 (root->tArgLists ? root->tArgLists->last() : 0),
6220 funcArgs.isEmpty() ? 0 : root->argList);
6222 if (isDefine && mdDefine)
6224 md->setInitializer(mdDefine->initializer());
6228 // we still have the problem that
6229 // MemberDef::writeDocumentation() in memberdef.cpp
6230 // writes the template argument list for the class,
6231 // as if this member is a member of the class.
6232 // fortunately, MemberDef::writeDocumentation() has
6233 // a special mechanism that allows us to totally
6234 // override the set of template argument lists that
6235 // are printed. We use that and set it to the
6236 // template argument lists of the related function.
6238 md->setDefinitionTemplateParameterLists(root->tArgLists);
6240 md->setTagInfo(rootNav->tagInfo());
6244 //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6245 // funcName.data(),funcDecl.data(),root->bodyLine);
6247 // try to find the matching line number of the body from the
6248 // global function list
6250 if (root->bodyLine==-1)
6252 MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6255 MemberDef *rmd=rmn->first();
6256 while (rmd && !found) // see if we got another member with matching arguments
6258 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
6259 // check for matching argument lists
6261 matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
6262 cd,fd,root->argList,
6268 if (!found) rmd=rmn->next();
6270 if (rmd) // member found -> copy line number info
6272 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6273 md->setBodyDef(rmd->getBodyDef());
6274 //md->setBodyMember(rmd);
6278 if (!found) // line number could not be found or is available in this
6281 md->setBodySegment(root->bodyLine,root->endBodyLine);
6285 //if (root->mGrpId!=-1)
6287 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
6289 md->setMemberClass(cd);
6290 md->setMemberSpecifiers(root->spec);
6291 md->setDefinition(funcDecl);
6292 md->enableCallGraph(root->callGraph);
6293 md->enableCallerGraph(root->callerGraph);
6294 md->setDocumentation(root->doc,root->docFile,root->docLine);
6295 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6296 md->setDocsForDefinition(!root->proto);
6297 md->setPrototype(root->proto);
6298 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6299 md->addSectionsToDefinition(root->anchors);
6300 md->setMemberGroupId(root->mGrpId);
6301 md->setLanguage(root->lang);
6302 //md->setMemberDefTemplateArguments(root->mtArgList);
6304 cd->insertMember(md);
6305 cd->insertUsedFile(root->fileName);
6306 md->setRefItems(root->sli);
6307 if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6310 addMemberToGroups(root,md);
6312 //printf("Adding member=%s\n",md->name().data());
6315 //Doxygen::memberNameList.append(mn);
6316 //Doxygen::memberNameDict.insert(funcName,mn);
6317 Doxygen::memberNameSDict->append(funcName,mn);
6320 if (root->relatesType == Duplicate)
6322 if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
6324 QCString fullFuncDecl=funcDecl.copy();
6325 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6326 warn(root->fileName,root->startLine,
6327 "warning: Cannot determine file/namespace for relatedalso function\n%s",
6335 warn_undoc(root->fileName,root->startLine,
6336 "warning: class `%s' for related function `%s' is not "
6338 className.data(),funcName.data()
6342 else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6346 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6347 if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
6349 Debug::print(Debug::FindMembers,0,"4. Local objective C method %s\n"
6350 " scopeName=%s className=%s\n",root->name.data(),scopeName.data(),className.data());
6351 //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6352 MemberDef *md=new MemberDef(
6353 root->fileName,root->startLine,
6354 funcType,funcName,funcArgs,exceptions,
6355 root->protection,root->virt,root->stat,Member,
6356 MemberDef::Function,0,root->argList);
6357 md->setTagInfo(rootNav->tagInfo());
6358 md->setLanguage(root->lang);
6359 md->makeImplementationDetail();
6360 md->setMemberClass(cd);
6361 md->setDefinition(funcDecl);
6362 md->enableCallGraph(root->callGraph);
6363 md->enableCallerGraph(root->callerGraph);
6364 md->setDocumentation(root->doc,root->docFile,root->docLine);
6365 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6366 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6367 md->setDocsForDefinition(!root->proto);
6368 md->setPrototype(root->proto);
6369 md->addSectionsToDefinition(root->anchors);
6370 md->setBodySegment(root->bodyLine,root->endBodyLine);
6371 FileDef *fd=rootNav->fileDef();
6373 md->setMemberSpecifiers(root->spec);
6374 md->setMemberGroupId(root->mGrpId);
6375 cd->insertMember(md);
6376 cd->insertUsedFile(root->fileName);
6377 md->setRefItems(root->sli);
6378 if ((mn=Doxygen::memberNameSDict->find(root->name)))
6384 mn = new MemberName(root->name);
6386 Doxygen::memberNameSDict->append(root->name,mn);
6391 // local objective C method found for class without interface
6394 else // unrelated not overloaded member found
6396 bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl);
6397 if (className.isEmpty() && !globMem)
6399 warn(root->fileName,root->startLine,
6400 "warning: class for member `%s' cannot "
6401 "be found.", funcName.data()
6404 else if (!className.isEmpty() && !globMem)
6406 warn(root->fileName,root->startLine,
6407 "warning: member `%s' of class `%s' cannot be found",
6408 funcName.data(),className.data());
6414 // this should not be called
6415 warn(root->fileName,root->startLine,
6416 "warning: member with no name found.");
6421 //----------------------------------------------------------------------
6422 // find the members corresponding to the different documentation blocks
6423 // that are extracted from the sources.
6425 static void filterMemberDocumentation(EntryNav *rootNav)
6427 Entry *root = rootNav->entry();
6429 Debug::print(Debug::FindMembers,0,
6430 "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n",
6431 root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
6433 //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6436 if (root->relatesType == Duplicate && !root->relates.isEmpty())
6438 QCString tmp = root->relates;
6439 root->relates.resize(0);
6440 filterMemberDocumentation(rootNav);
6441 root->relates = tmp;
6444 if ( // detect func variable/typedef to func ptr
6445 (i=findFunctionPtr(root->type,root->lang,&l))!=-1
6448 //printf("Fixing function pointer!\n");
6449 // fix type and argument
6450 root->args.prepend(root->type.right(root->type.length()-i-l));
6451 root->type=root->type.left(i+l);
6452 //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6455 else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1))
6456 // detect function types marked as functions
6461 //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6462 if (root->section==Entry::MEMBERDOC_SEC)
6464 //printf("Documentation for inline member `%s' found args=`%s'\n",
6465 // root->name.data(),root->args.data());
6466 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6467 if (root->type.isEmpty())
6469 findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6473 findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6476 else if (root->section==Entry::OVERLOADDOC_SEC)
6478 //printf("Overloaded member %s found\n",root->name.data());
6479 findMember(rootNav,root->name,TRUE,isFunc);
6482 ((root->section==Entry::FUNCTION_SEC // function
6484 (root->section==Entry::VARIABLE_SEC && // variable
6485 !root->type.isEmpty() && // with a type
6486 g_compoundKeywordDict.find(root->type)==0 // that is not a keyword
6487 // (to skip forward declaration of class etc.)
6492 //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6493 // root->name.data(),root->args.data(),root->exception.data());
6494 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6495 //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6496 if (root->type=="friend class" || root->type=="friend struct" ||
6497 root->type=="friend union")
6505 else if (!root->type.isEmpty())
6525 else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6527 findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6529 else if (root->section==Entry::VARIABLEDOC_SEC)
6531 //printf("Documentation for variable %s found\n",root->name.data());
6532 //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data());
6533 findMember(rootNav,root->name,FALSE,FALSE);
6538 //printf("skip section\n");
6542 static void findMemberDocumentation(EntryNav *rootNav)
6544 if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6545 rootNav->section()==Entry::OVERLOADDOC_SEC ||
6546 rootNav->section()==Entry::FUNCTION_SEC ||
6547 rootNav->section()==Entry::VARIABLE_SEC ||
6548 rootNav->section()==Entry::VARIABLEDOC_SEC ||
6549 rootNav->section()==Entry::DEFINE_SEC
6552 rootNav->loadEntry(g_storage);
6554 filterMemberDocumentation(rootNav);
6556 rootNav->releaseEntry();
6558 if (rootNav->children())
6560 EntryNavListIterator eli(*rootNav->children());
6562 for (;(e=eli.current());++eli)
6564 if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6569 //----------------------------------------------------------------------
6571 static void findObjCMethodDefinitions(EntryNav *rootNav)
6573 if (rootNav->children())
6575 EntryNavListIterator eli(*rootNav->children());
6576 EntryNav *objCImplNav;
6577 for (;(objCImplNav=eli.current());++eli)
6579 if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
6581 EntryNavListIterator seli(*objCImplNav->children());
6582 EntryNav *objCMethodNav;
6583 for (;(objCMethodNav=seli.current());++seli)
6585 if (objCMethodNav->section()==Entry::FUNCTION_SEC)
6587 objCMethodNav->loadEntry(g_storage);
6588 Entry *objCMethod = objCMethodNav->entry();
6590 //Printf(" Found ObjC method definition %s\n",objCMethod->name.data());
6591 findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
6592 objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
6593 objCMethod->section=Entry::EMPTY_SEC;
6595 objCMethodNav->releaseEntry();
6603 //----------------------------------------------------------------------
6604 // find and add the enumeration to their classes, namespaces or files
6606 static void findEnums(EntryNav *rootNav)
6608 if (rootNav->section()==Entry::ENUM_SEC)
6609 // non anonymous enumeration
6611 rootNav->loadEntry(g_storage);
6612 Entry *root = rootNav->entry();
6618 MemberNameSDict *mnsd=0;
6620 bool isRelated=FALSE;
6621 bool isMemberOf=FALSE;
6622 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
6628 if ((i=root->name.findRev("::"))!=-1) // scope is specified
6630 scope=root->name.left(i); // extract scope
6631 name=root->name.right(root->name.length()-i-2); // extract name
6632 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6634 else // no scope, check the scope in which the docs where found
6636 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
6637 && !rootNav->parent()->name().isEmpty()
6638 ) // found enum docs inside a compound
6640 scope=rootNav->parent()->name();
6641 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6646 if (!root->relates.isEmpty())
6647 { // related member, prefix user specified scope
6649 isMemberOf=(root->relatesType == MemberOf);
6650 if (getClass(root->relates)==0 && !scope.isEmpty())
6651 scope=mergeScopes(scope,root->relates);
6653 scope=root->relates.copy();
6654 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6657 if (cd && !name.isEmpty()) // found a enum inside a compound
6659 //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
6661 mnsd=Doxygen::memberNameSDict;
6664 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
6666 mnsd=Doxygen::functionNameSDict;
6669 else // found a global enum
6671 fd=rootNav->fileDef();
6672 mnsd=Doxygen::functionNameSDict;
6676 if (!name.isEmpty())
6680 root->fileName,root->startLine,
6682 root->protection,Normal,FALSE,
6683 isMemberOf ? Foreign : isRelated ? Related : Member,
6684 MemberDef::Enumeration,
6686 md->setTagInfo(rootNav->tagInfo());
6687 md->setLanguage(root->lang);
6688 if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
6689 md->setBodySegment(root->bodyLine,root->endBodyLine);
6690 md->setBodyDef(rootNav->fileDef());
6691 md->setEnumBaseType(root->args);
6692 //printf("Enum %s definition at line %d of %s: protection=%d\n",
6693 // root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
6694 md->addSectionsToDefinition(root->anchors);
6695 md->setMemberGroupId(root->mGrpId);
6696 md->enableCallGraph(root->callGraph);
6697 md->enableCallerGraph(root->callerGraph);
6698 //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
6699 md->setRefItems(root->sli);
6700 //printf("found enum %s nd=%p\n",name.data(),nd);
6703 QCString baseType = root->args;
6704 if (!baseType.isEmpty())
6706 baseType.prepend(" : ");
6709 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
6711 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
6713 md->setDefinition(name+baseType);
6717 md->setDefinition(nd->name()+"::"+name+baseType);
6719 //printf("definition=%s\n",md->definition());
6721 md->setNamespace(nd);
6722 nd->insertMember(md);
6725 // even if we have already added the enum to a namespace, we still
6726 // also want to add it to other appropriate places such as file
6730 if (!defSet) md->setDefinition(name+baseType);
6731 if (fd==0 && rootNav->parent())
6733 fd=rootNav->parent()->fileDef();
6738 fd->insertMember(md);
6743 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
6745 md->setDefinition(name+baseType);
6749 md->setDefinition(cd->name()+"::"+name+baseType);
6751 cd->insertMember(md);
6752 cd->insertUsedFile(root->fileName);
6754 md->setDocumentation(root->doc,root->docFile,root->docLine);
6755 md->setDocsForDefinition(!root->proto);
6756 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6757 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6759 //printf("Adding member=%s\n",md->name().data());
6761 if ((mn=(*mnsd)[name]))
6763 // this is used if the same enum is in multiple namespaces/classes
6766 else // new enum name
6768 mn = new MemberName(name);
6770 mnsd->append(name,mn);
6771 //printf("add %s to new memberName. Now %d members\n",
6772 // name.data(),mn->count());
6774 addMemberToGroups(root,md);
6777 if (rootNav->children())
6779 EntryNavListIterator eli(*rootNav->children());
6781 for (;(e=eli.current());++eli)
6783 //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated);
6785 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
6786 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
6787 // get list of members with the same name as the field
6789 MemberNameIterator fmni(*fmn);
6791 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
6793 if (fmd->isEnumValue())
6795 //printf("found enum value with same name\n");
6796 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
6798 NamespaceDef *fnd=fmd->getNamespaceDef();
6799 if (fnd==nd) // enum value is inside a namespace
6801 md->insertEnumField(fmd);
6802 fmd->setEnumScope(md);
6807 FileDef *ffd=fmd->getFileDef();
6808 if (ffd==fd) // enum value has file scope
6810 md->insertEnumField(fmd);
6811 fmd->setEnumScope(md);
6814 else if (isRelated && cd) // reparent enum value to
6815 // match the enum's scope
6817 md->insertEnumField(fmd); // add field def to list
6818 fmd->setEnumScope(md); // cross ref with enum name
6819 fmd->setEnumClassScope(cd); // cross ref with enum name
6820 fmd->setOuterScope(cd);
6822 cd->insertMember(fmd);
6826 ClassDef *fcd=fmd->getClassDef();
6827 if (fcd==cd) // enum value is inside a class
6829 //printf("Inserting enum field %s in enum scope %s\n",
6830 // fmd->name().data(),md->name().data());
6831 md->insertEnumField(fmd); // add field def to list
6832 fmd->setEnumScope(md); // cross ref with enum name
6843 rootNav->releaseEntry();
6847 RECURSE_ENTRYTREE(findEnums,rootNav);
6851 //----------------------------------------------------------------------
6853 static void addEnumValuesToEnums(EntryNav *rootNav)
6855 if (rootNav->section()==Entry::ENUM_SEC)
6856 // non anonymous enumeration
6858 rootNav->loadEntry(g_storage);
6859 Entry *root = rootNav->entry();
6864 MemberNameSDict *mnsd=0;
6866 bool isRelated=FALSE;
6867 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
6873 if ((i=root->name.findRev("::"))!=-1) // scope is specified
6875 scope=root->name.left(i); // extract scope
6876 name=root->name.right(root->name.length()-i-2); // extract name
6877 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6879 else // no scope, check the scope in which the docs where found
6881 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
6882 && !rootNav->parent()->name().isEmpty()
6883 ) // found enum docs inside a compound
6885 scope=rootNav->parent()->name();
6886 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6891 if (!root->relates.isEmpty())
6892 { // related member, prefix user specified scope
6894 if (getClass(root->relates)==0 && !scope.isEmpty())
6895 scope=mergeScopes(scope,root->relates);
6897 scope=root->relates.copy();
6898 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6901 if (cd && !name.isEmpty()) // found a enum inside a compound
6903 //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
6905 mnsd=Doxygen::memberNameSDict;
6908 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
6910 //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
6911 mnsd=Doxygen::functionNameSDict;
6914 else // found a global enum
6916 fd=rootNav->fileDef();
6917 //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
6918 mnsd=Doxygen::functionNameSDict;
6922 if (!name.isEmpty())
6924 //printf("** name=%s\n",name.data());
6925 MemberName *mn = mnsd->find(name); // for all members with this name
6928 MemberNameIterator mni(*mn);
6930 for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list
6932 if (md->isEnumerate() && rootNav->children())
6934 //printf(" enum with %d children\n",rootNav->children()->count());
6935 EntryNavListIterator eli(*rootNav->children()); // for each enum value
6937 for (;(e=eli.current());++eli)
6941 (sle=rootNav->lang())==SrcLangExt_CSharp ||
6942 sle==SrcLangExt_Java ||
6943 sle==SrcLangExt_XML ||
6944 (root->spec&Entry::Strong)
6947 // Unlike classic C/C++ enums, for C++11, C# & Java enum
6948 // values are only inside the enum scope, so we must create
6949 // them here and only add them to the enum
6950 e->loadEntry(g_storage);
6951 Entry *root = e->entry();
6952 //printf("md->qualifiedName()=%s rootNav->name()=%s\n",
6953 // md->qualifiedName().data(),rootNav->name().data());
6954 if (md->qualifiedName()==substitute(rootNav->name(),"::",".")) // enum value scope matches that of the enum
6956 MemberDef *fmd=new MemberDef(
6957 root->fileName,root->startLine,
6958 root->type,root->name,root->args,0,
6959 Public, Normal,root->stat,Member,
6960 MemberDef::EnumValue,0,0);
6961 if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
6962 else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
6963 else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
6964 fmd->setOuterScope(md->getOuterScope());
6965 fmd->setTagInfo(e->tagInfo());
6966 fmd->setLanguage(root->lang);
6967 fmd->setDocumentation(root->doc,root->docFile,root->docLine);
6968 fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6969 fmd->addSectionsToDefinition(root->anchors);
6970 fmd->setInitializer(root->initializer);
6971 fmd->setMaxInitLines(root->initLines);
6972 fmd->setMemberGroupId(root->mGrpId);
6973 fmd->setExplicitExternal(root->explicitExternal);
6974 fmd->setRefItems(root->sli);
6977 md->insertEnumField(fmd);
6978 fmd->setEnumScope(md);
6985 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
6987 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
6988 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
6989 // get list of members with the same name as the field
6991 MemberNameIterator fmni(*fmn);
6993 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
6995 if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
6997 //printf("found enum value with same name %s in scope %s\n",
6998 // fmd->name().data(),fmd->getOuterScope()->name().data());
6999 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
7001 NamespaceDef *fnd=fmd->getNamespaceDef();
7002 if (fnd==nd) // enum value is inside a namespace
7004 md->insertEnumField(fmd);
7005 fmd->setEnumScope(md);
7010 FileDef *ffd=fmd->getFileDef();
7011 if (ffd==fd) // enum value has file scope
7013 md->insertEnumField(fmd);
7014 fmd->setEnumScope(md);
7017 else if (isRelated && cd) // reparent enum value to
7018 // match the enum's scope
7020 md->insertEnumField(fmd); // add field def to list
7021 fmd->setEnumScope(md); // cross ref with enum name
7022 fmd->setEnumClassScope(cd); // cross ref with enum name
7023 fmd->setOuterScope(cd);
7025 cd->insertMember(fmd);
7029 ClassDef *fcd=fmd->getClassDef();
7030 if (fcd==cd) // enum value is inside a class
7032 //printf("Inserting enum field %s in enum scope %s\n",
7033 // fmd->name().data(),md->name().data());
7034 md->insertEnumField(fmd); // add field def to list
7035 fmd->setEnumScope(md); // cross ref with enum name
7048 rootNav->releaseEntry();
7052 RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
7057 //----------------------------------------------------------------------
7058 // find the documentation blocks for the enumerations
7060 static void findEnumDocumentation(EntryNav *rootNav)
7062 if (rootNav->section()==Entry::ENUMDOC_SEC
7063 && !rootNav->name().isEmpty()
7064 && rootNav->name().at(0)!='@' // skip anonymous enums
7067 rootNav->loadEntry(g_storage);
7068 Entry *root = rootNav->entry();
7070 //printf("Found docs for enum with name `%s' in context %s\n",
7071 // root->name.data(),root->parent->name.data());
7075 if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
7077 name=root->name.right(root->name.length()-i-2); // extract name
7078 scope=root->name.left(i); // extract scope
7079 //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
7081 else // just the name
7085 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
7086 && !rootNav->parent()->name().isEmpty()
7087 ) // found enum docs inside a compound
7089 if (!scope.isEmpty()) scope.prepend("::");
7090 scope.prepend(rootNav->parent()->name());
7092 ClassDef *cd=getClass(scope);
7094 if (!name.isEmpty())
7099 //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
7100 QCString className=cd->name().copy();
7101 MemberName *mn=Doxygen::memberNameSDict->find(name);
7104 MemberNameIterator mni(*mn);
7106 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7108 ClassDef *cd=md->getClassDef();
7109 if (cd && cd->name()==className && md->isEnumerate())
7111 // documentation outside a compound overrides the documentation inside it
7113 if (!md->documentation() || rootNav->parent()->name().isEmpty())
7116 md->setDocumentation(root->doc,root->docFile,root->docLine);
7117 md->setDocsForDefinition(!root->proto);
7120 // brief descriptions inside a compound override the documentation
7123 if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
7126 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7129 if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
7131 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7134 if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
7136 md->setMemberGroupId(root->mGrpId);
7139 md->addSectionsToDefinition(root->anchors);
7140 md->setRefItems(root->sli);
7142 GroupDef *gd=md->getGroupDef();
7143 if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is
7145 addMemberToGroups(root,md);
7154 //printf("MemberName %s not found!\n",name.data());
7157 else // enum outside class
7159 //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
7160 MemberName *mn=Doxygen::functionNameSDict->find(name);
7163 MemberNameIterator mni(*mn);
7165 for (mni.toFirst();(md=mni.current()) && !found;++mni)
7167 if (md->isEnumerate())
7169 md->setDocumentation(root->doc,root->docFile,root->docLine);
7170 md->setDocsForDefinition(!root->proto);
7171 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7172 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7173 md->addSectionsToDefinition(root->anchors);
7174 md->setMemberGroupId(root->mGrpId);
7176 GroupDef *gd=md->getGroupDef();
7177 if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is
7179 addMemberToGroups(root,md);
7189 warn(root->fileName,root->startLine,
7190 "warning: Documentation for undefined enum `%s' found.",
7196 rootNav->releaseEntry();
7198 RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
7201 // search for each enum (member or function) in mnl if it has documented
7203 static void findDEV(const MemberNameSDict &mnsd)
7206 MemberNameSDict::Iterator mnli(mnsd);
7207 // for each member name
7208 for (mnli.toFirst();(mn=mnli.current());++mnli)
7211 MemberNameIterator mni(*mn);
7212 // for each member definition
7213 for (mni.toFirst();(md=mni.current());++mni)
7215 if (md->isEnumerate()) // member is an enum
7217 LockingPtr<MemberList> fmdl = md->enumFieldList();
7218 int documentedEnumValues=0;
7219 if (fmdl!=0) // enum has values
7221 MemberListIterator fmni(*fmdl);
7223 // for each enum value
7224 for (fmni.toFirst();(fmd=fmni.current());++fmni)
7226 if (fmd->isLinkableInProject()) documentedEnumValues++;
7229 // at least one enum value is documented
7230 if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7236 // search for each enum (member or function) if it has documented enum
7238 static void findDocumentedEnumValues()
7240 findDEV(*Doxygen::memberNameSDict);
7241 findDEV(*Doxygen::functionNameSDict);
7244 //----------------------------------------------------------------------
7246 static void addMembersToIndex()
7249 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7250 // for each member name
7251 for (mnli.toFirst();(mn=mnli.current());++mnli)
7254 MemberNameIterator mni(*mn);
7255 // for each member definition
7256 for (mni.toFirst();(md=mni.current());++mni)
7258 addClassMemberNameToIndex(md);
7261 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7262 // for each member name
7263 for (fnli.toFirst();(mn=fnli.current());++fnli)
7266 MemberNameIterator mni(*mn);
7267 // for each member definition
7268 for (mni.toFirst();(md=mni.current());++mni)
7270 if (md->getNamespaceDef())
7272 addNamespaceMemberNameToIndex(md);
7276 addFileMemberNameToIndex(md);
7282 //----------------------------------------------------------------------
7283 // computes the relation between all members. For each member `m'
7284 // the members that override the implementation of `m' are searched and
7285 // the member that `m' overrides is searched.
7287 static void computeMemberRelations()
7289 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7291 for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7293 MemberNameIterator mdi(*mn);
7295 for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7297 MemberDef *bmd = mn->first(); // for each other member with the same name
7300 ClassDef *mcd = md->getClassDef();
7301 if (mcd && mcd->baseClasses())
7303 ClassDef *bmcd = bmd->getClassDef();
7304 //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7305 // mcd->name().data(),md->name().data(),md,
7306 // bmcd->name().data(),bmd->name().data(),bmd
7308 if (md!=bmd && bmd->virtualness()!=Normal && md->isFunction() &&
7309 bmcd && mcd && mcd->isLinkable() && bmcd->isLinkable() &&
7310 bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE))
7312 //printf(" derived scope\n");
7313 LockingPtr<ArgumentList> bmdAl = bmd->argumentList();
7314 LockingPtr<ArgumentList> mdAl = md->argumentList();
7315 //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7316 // argListToString(bmdAl.pointer()).data(),
7317 // argListToString(mdAl.pointer()).data()
7320 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(),
7321 md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
7327 if ((rmd=md->reimplements())==0 ||
7328 minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7331 //printf("setting (new) reimplements member\n");
7332 md->setReimplements(bmd);
7334 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7335 bmd->insertReimplementedBy(md);
7346 //----------------------------------------------------------------------------
7347 //static void computeClassImplUsageRelations()
7350 // ClassSDict::Iterator cli(*Doxygen::classSDict);
7351 // for (;(cd=cli.current());++cli)
7353 // cd->determineImplUsageRelation();
7357 //----------------------------------------------------------------------------
7359 static void createTemplateInstanceMembers()
7361 ClassSDict::Iterator cli(*Doxygen::classSDict);
7364 for (cli.toFirst();(cd=cli.current());++cli)
7366 // that is a template
7367 QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7370 QDictIterator<ClassDef> qdi(*templInstances);
7372 // for each instance of the template
7373 for (qdi.toFirst();(tcd=qdi.current());++qdi)
7375 tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7381 //----------------------------------------------------------------------------
7383 static void mergeCategories()
7386 ClassSDict::Iterator cli(*Doxygen::classSDict);
7387 // merge members of categories into the class they extend
7388 for (cli.toFirst();(cd=cli.current());++cli)
7390 int i=cd->name().find('(');
7391 if (i!=-1) // it is an Objective-C category
7393 QCString baseName=cd->name().left(i);
7394 ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7397 //printf("*** merging members of category %s into %s\n",
7398 // cd->name().data(),baseClass->name().data());
7399 baseClass->mergeCategory(cd);
7405 // builds the list of all members for each class
7407 static void buildCompleteMemberLists()
7410 ClassSDict::Iterator cli(*Doxygen::classSDict);
7411 // merge the member list of base classes into the inherited classes.
7412 for (cli.toFirst();(cd=cli.current());++cli)
7414 if (// !cd->isReference() && // not an external class
7415 cd->subClasses()==0 && // is a root of the hierarchy
7416 cd->baseClasses()) // and has at least one base class
7418 //printf("*** merging members for %s\n",cd->name().data());
7422 // now sort the member list of all classes.
7423 for (cli.toFirst();(cd=cli.current());++cli)
7425 if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7429 //----------------------------------------------------------------------------
7431 static void generateFileSources()
7433 if (documentedHtmlFiles==0) return;
7434 if (Doxygen::inputNameList->count()>0)
7436 FileNameListIterator fnli(*Doxygen::inputNameList);
7438 for (;(fn=fnli.current());++fnli)
7440 FileNameIterator fni(*fn);
7442 for (;(fd=fni.current());++fni)
7444 if (fd->generateSourceFile()) // sources need to be shown in the output
7446 msg("Generating code for file %s...\n",fd->docName().data());
7447 fd->writeSource(*g_outputList);
7449 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7450 // we needed to parse the sources even if we do not show them
7452 msg("Parsing code for file %s...\n",fd->docName().data());
7460 //----------------------------------------------------------------------------
7462 static void generateFileDocs()
7464 if (documentedHtmlFiles==0) return;
7466 if (Doxygen::inputNameList->count()>0)
7468 FileNameListIterator fnli(*Doxygen::inputNameList);
7470 for (fnli.toFirst();(fn=fnli.current());++fnli)
7472 FileNameIterator fni(*fn);
7474 for (fni.toFirst();(fd=fni.current());++fni)
7476 bool doc = fd->isLinkableInProject();
7479 msg("Generating docs for file %s...\n",fd->docName().data());
7480 fd->writeDocumentation(*g_outputList);
7487 //----------------------------------------------------------------------------
7489 static void addSourceReferences()
7491 // add source references for class definitions
7492 ClassSDict::Iterator cli(*Doxygen::classSDict);
7494 for (cli.toFirst();(cd=cli.current());++cli)
7496 FileDef *fd=cd->getBodyDef();
7497 if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
7499 fd->addSourceRef(cd->getStartBodyLine(),cd,0);
7502 // add source references for namespace definitions
7503 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7505 for (nli.toFirst();(nd=nli.current());++nli)
7507 FileDef *fd=nd->getBodyDef();
7508 if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
7510 fd->addSourceRef(nd->getStartBodyLine(),nd,0);
7514 // add source references for member names
7515 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7517 for (mnli.toFirst();(mn=mnli.current());++mnli)
7519 MemberNameIterator mni(*mn);
7521 for (mni.toFirst();(md=mni.current());++mni)
7523 //printf("class member %s: def=%s body=%d link?=%d\n",
7524 // md->name().data(),
7525 // md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
7526 // md->getStartBodyLine(),md->isLinkableInProject());
7527 FileDef *fd=md->getBodyDef();
7529 md->getStartBodyLine()!=-1 &&
7530 md->isLinkableInProject() &&
7531 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7534 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7535 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
7536 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7540 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7541 for (fnli.toFirst();(mn=fnli.current());++fnli)
7543 MemberNameIterator mni(*mn);
7545 for (mni.toFirst();(md=mni.current());++mni)
7547 FileDef *fd=md->getBodyDef();
7548 //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
7549 // md->name().data(),
7550 // md->getStartBodyLine(),md->getEndBodyLine(),fd,
7551 // md->isLinkableInProject(),
7552 // Doxygen::parseSourcesNeeded);
7554 md->getStartBodyLine()!=-1 &&
7555 md->isLinkableInProject() &&
7556 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7559 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7560 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
7561 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7567 //----------------------------------------------------------------------------
7569 static void sortMemberLists()
7571 // sort class member lists
7572 ClassSDict::Iterator cli(*Doxygen::classSDict);
7574 for (cli.toFirst();(cd=cli.current());++cli)
7576 cd->sortMemberLists();
7579 // sort namespace member lists
7580 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7582 for (nli.toFirst();(nd=nli.current());++nli)
7584 nd->sortMemberLists();
7587 // sort file member lists
7588 FileNameListIterator fnli(*Doxygen::inputNameList);
7590 for (;(fn=fnli.current());++fnli)
7592 FileNameIterator fni(*fn);
7594 for (;(fd=fni.current());++fni)
7596 fd->sortMemberLists();
7600 // sort group member lists
7601 GroupSDict::Iterator gli(*Doxygen::groupSDict);
7603 for (gli.toFirst();(gd=gli.current());++gli)
7605 gd->sortMemberLists();
7609 //----------------------------------------------------------------------------
7610 // generate the documentation of all classes
7612 static void generateClassList(ClassSDict &classSDict)
7614 ClassSDict::Iterator cli(classSDict);
7615 for ( ; cli.current() ; ++cli )
7617 ClassDef *cd=cli.current();
7619 //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
7620 if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
7621 cd->getOuterScope()==Doxygen::globalScope // only look at global classes
7622 ) && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
7625 // skip external references, anonymous compounds and
7626 // template instances
7627 if ( cd->isLinkableInProject() && cd->templateMaster()==0)
7629 msg("Generating docs for compound %s...\n",cd->name().data());
7631 cd->writeDocumentation(*g_outputList);
7632 cd->writeMemberList(*g_outputList);
7634 // even for undocumented classes, the inner classes can be documented.
7635 cd->writeDocumentationForInnerClasses(*g_outputList);
7640 static void generateClassDocs()
7642 generateClassList(*Doxygen::classSDict);
7643 generateClassList(*Doxygen::hiddenClasses);
7646 //----------------------------------------------------------------------------
7648 static void inheritDocumentation()
7650 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7653 for (;(mn=mnli.current());++mnli)
7655 MemberNameIterator mni(*mn);
7657 for (;(md=mni.current());++mni)
7659 //printf("%04d Member `%s'\n",count++,md->name().data());
7660 if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
7661 { // no documentation yet
7662 MemberDef *bmd = md->reimplements();
7663 while (bmd && bmd->documentation().isEmpty() &&
7664 bmd->briefDescription().isEmpty()
7666 { // search up the inheritance tree for a documentation member
7667 //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
7668 bmd = bmd->reimplements();
7670 if (bmd) // copy the documentation from the reimplemented member
7672 md->setInheritsDocsFrom(bmd);
7673 md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
7674 md->setDocsForDefinition(bmd->isDocsForDefinition());
7675 md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
7676 md->copyArgumentNames(bmd);
7677 md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
7684 //----------------------------------------------------------------------------
7686 static void combineUsingRelations()
7689 FileNameListIterator fnli(*Doxygen::inputNameList);
7691 for (fnli.toFirst();(fn=fnli.current());++fnli)
7693 FileNameIterator fni(*fn);
7695 for (fni.toFirst();(fd=fni.current());++fni)
7700 for (fnli.toFirst();(fn=fnli.current());++fnli)
7702 FileNameIterator fni(*fn);
7704 for (fni.toFirst();(fd=fni.current());++fni)
7706 fd->combineUsingRelations();
7710 // for each namespace
7711 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7713 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
7717 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
7719 nd->combineUsingRelations();
7723 //----------------------------------------------------------------------------
7725 static void addMembersToMemberGroup()
7728 ClassSDict::Iterator cli(*Doxygen::classSDict);
7730 for ( ; (cd=cli.current()) ; ++cli )
7732 cd->addMembersToMemberGroup();
7735 FileName *fn=Doxygen::inputNameList->first();
7738 FileDef *fd=fn->first();
7741 fd->addMembersToMemberGroup();
7744 fn=Doxygen::inputNameList->next();
7746 // for each namespace
7747 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7749 for ( ; (nd=nli.current()) ; ++nli )
7751 nd->addMembersToMemberGroup();
7754 GroupSDict::Iterator gli(*Doxygen::groupSDict);
7756 for (gli.toFirst();(gd=gli.current());++gli)
7758 gd->addMembersToMemberGroup();
7762 //----------------------------------------------------------------------------
7764 static void distributeMemberGroupDocumentation()
7767 ClassSDict::Iterator cli(*Doxygen::classSDict);
7769 for ( ; (cd=cli.current()) ; ++cli )
7771 cd->distributeMemberGroupDocumentation();
7774 FileName *fn=Doxygen::inputNameList->first();
7777 FileDef *fd=fn->first();
7780 fd->distributeMemberGroupDocumentation();
7783 fn=Doxygen::inputNameList->next();
7785 // for each namespace
7786 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7788 for ( ; (nd=nli.current()) ; ++nli )
7790 nd->distributeMemberGroupDocumentation();
7793 GroupSDict::Iterator gli(*Doxygen::groupSDict);
7795 for (gli.toFirst();(gd=gli.current());++gli)
7797 gd->distributeMemberGroupDocumentation();
7801 //----------------------------------------------------------------------------
7803 static void findSectionsInDocumentation()
7806 ClassSDict::Iterator cli(*Doxygen::classSDict);
7808 for ( ; (cd=cli.current()) ; ++cli )
7810 cd->findSectionsInDocumentation();
7813 FileName *fn=Doxygen::inputNameList->first();
7816 FileDef *fd=fn->first();
7819 fd->findSectionsInDocumentation();
7822 fn=Doxygen::inputNameList->next();
7824 // for each namespace
7825 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7827 for ( ; (nd=nli.current()) ; ++nli )
7829 nd->findSectionsInDocumentation();
7832 GroupSDict::Iterator gli(*Doxygen::groupSDict);
7834 for (gli.toFirst();(gd=gli.current());++gli)
7836 gd->findSectionsInDocumentation();
7839 PageSDict::Iterator pdi(*Doxygen::pageSDict);
7841 for (pdi.toFirst();(pd=pdi.current());++pdi)
7843 pd->findSectionsInDocumentation();
7845 if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
7848 static void flushCachedTemplateRelations()
7850 // remove all references to classes from the cache
7851 // as there can be new template instances in the inheritance path
7852 // to this class. Optimization: only remove those classes that
7853 // have inheritance instances as direct or indirect sub classes.
7854 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
7856 for (ci.toFirst();(li=ci.current());++ci)
7860 Doxygen::lookupCache->remove(ci.currentKey());
7863 // remove all cached typedef resolutions whose target is a
7864 // template class as this may now be a template instance
7865 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7867 for (;(fn=fnli.current());++fnli) // for each global function name
7869 MemberNameIterator fni(*fn);
7871 for (;(fmd=fni.current());++fni) // for each function with that name
7873 if (fmd->isTypedefValCached())
7875 ClassDef *cd = fmd->getCachedTypedefVal();
7876 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
7880 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7881 for (;(fn=mnli.current());++mnli) // for each class method name
7883 MemberNameIterator mni(*fn);
7885 for (;(fmd=mni.current());++mni) // for each function with that name
7887 if (fmd->isTypedefValCached())
7889 ClassDef *cd = fmd->getCachedTypedefVal();
7890 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
7896 //----------------------------------------------------------------------------
7898 static void flushUnresolvedRelations()
7900 // Remove all unresolved references to classes from the cache.
7901 // This is needed before resolving the inheritance relations, since
7902 // it would otherwise not find the inheritance relation
7903 // for C in the example below, as B::I was already found to be unresolvable
7904 // (which is correct if you igore the inheritance relation between A and B).
7906 // class A { class I {} };
7907 // class B : public A {};
7908 // class C : public B::I {};
7910 QCacheIterator<LookupInfo> ci(*Doxygen::lookupCache);
7912 for (ci.toFirst();(li=ci.current());++ci)
7914 if (li->classDef==0 && li->typeDef==0)
7916 Doxygen::lookupCache->remove(ci.currentKey());
7920 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7922 for (;(fn=fnli.current());++fnli) // for each global function name
7924 MemberNameIterator fni(*fn);
7926 for (;(fmd=fni.current());++fni) // for each function with that name
7928 fmd->invalidateCachedArgumentTypes();
7931 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7932 for (;(fn=mnli.current());++mnli) // for each class method name
7934 MemberNameIterator mni(*fn);
7936 for (;(fmd=mni.current());++mni) // for each function with that name
7938 fmd->invalidateCachedArgumentTypes();
7944 //----------------------------------------------------------------------------
7946 static void findDefineDocumentation(EntryNav *rootNav)
7948 if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
7949 rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
7952 rootNav->loadEntry(g_storage);
7953 Entry *root = rootNav->entry();
7955 //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
7956 // root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
7958 if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
7960 MemberDef *md=new MemberDef("<tagfile>",1,
7961 "#define",root->name,root->args,0,
7962 Public,Normal,FALSE,Member,MemberDef::Define,0,0);
7963 md->setTagInfo(rootNav->tagInfo());
7964 md->setLanguage(root->lang);
7965 //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
7966 md->setFileDef(rootNav->parent()->fileDef());
7967 //printf("Adding member=%s\n",md->name().data());
7969 if ((mn=Doxygen::functionNameSDict->find(root->name)))
7975 mn = new MemberName(root->name);
7977 Doxygen::functionNameSDict->append(root->name,mn);
7980 MemberName *mn=Doxygen::functionNameSDict->find(root->name);
7984 MemberDef *md=mn->first();
7987 if (md->memberType()==MemberDef::Define) count++;
7995 if (md->memberType()==MemberDef::Define)
7997 md->setDocumentation(root->doc,root->docFile,root->docLine);
7998 md->setDocsForDefinition(!root->proto);
7999 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8000 if (md->inbodyDocumentation().isEmpty())
8002 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8004 md->setBodySegment(root->bodyLine,root->endBodyLine);
8005 md->setBodyDef(rootNav->fileDef());
8006 md->addSectionsToDefinition(root->anchors);
8007 md->setMaxInitLines(root->initLines);
8008 md->setRefItems(root->sli);
8009 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8010 addMemberToGroups(root,md);
8016 (!root->doc.isEmpty() ||
8017 !root->brief.isEmpty() ||
8021 // multiple defines don't know where to add docs
8022 // but maybe they are in different files together with their documentation
8027 if (md->memberType()==MemberDef::Define)
8029 FileDef *fd=md->getFileDef();
8030 if (fd && fd->absFilePath()==root->fileName)
8031 // doc and define in the same file assume they belong together.
8034 if (md->documentation().isEmpty())
8037 md->setDocumentation(root->doc,root->docFile,root->docLine);
8038 md->setDocsForDefinition(!root->proto);
8041 if (md->briefDescription().isEmpty())
8044 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8046 if (md->inbodyDocumentation().isEmpty())
8048 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
8050 md->setBodySegment(root->bodyLine,root->endBodyLine);
8051 md->setBodyDef(rootNav->fileDef());
8052 md->addSectionsToDefinition(root->anchors);
8053 md->setRefItems(root->sli);
8054 md->setLanguage(root->lang);
8055 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
8056 addMemberToGroups(root,md);
8061 //warn("warning: define %s found in the following files:\n",root->name.data());
8062 //warn("Cannot determine where to add the documentation found "
8063 // "at line %d of file %s. \n",
8064 // root->startLine,root->fileName.data());
8067 else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
8069 static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
8072 warn(root->fileName,root->startLine,
8073 "warning: documentation for unknown define %s found.\n",
8079 warn(root->fileName,root->startLine,
8080 "warning: found documented #define but ignoring it because "
8081 "ENABLE_PREPROCESSING is NO.\n",
8087 rootNav->releaseEntry();
8089 RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
8092 //----------------------------------------------------------------------------
8094 static void findDirDocumentation(EntryNav *rootNav)
8096 if (rootNav->section() == Entry::DIRDOC_SEC)
8098 rootNav->loadEntry(g_storage);
8099 Entry *root = rootNav->entry();
8101 QCString normalizedName = root->name;
8102 normalizedName = substitute(normalizedName,"\\","/");
8103 //printf("root->docFile=%s normalizedName=%s\n",
8104 // root->docFile.data(),normalizedName.data());
8105 if (root->docFile==normalizedName) // current dir?
8107 int lastSlashPos=normalizedName.findRev('/');
8108 if (lastSlashPos!=-1) // strip file name
8110 normalizedName=normalizedName.left(lastSlashPos);
8113 if (normalizedName.at(normalizedName.length()-1)!='/')
8115 normalizedName+='/';
8117 DirDef *dir,*matchingDir=0;
8118 SDict<DirDef>::Iterator sdi(*Doxygen::directories);
8119 for (sdi.toFirst();(dir=sdi.current());++sdi)
8121 //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
8122 if (dir->name().right(normalizedName.length())==normalizedName)
8126 warn(root->fileName,root->startLine,
8127 "warning: \\dir command matches multiple directories.\n"
8128 " Applying the command for directory %s\n"
8129 " Ignoring the command for directory %s\n",
8130 matchingDir->name().data(),dir->name().data()
8141 //printf("Match for with dir %s\n",matchingDir->name().data());
8142 matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8143 matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
8144 matchingDir->setRefItems(root->sli);
8145 addDirToGroups(root,matchingDir);
8149 warn(root->fileName,root->startLine,"warning: No matching "
8150 "directory found for command \\dir %s\n",normalizedName.data());
8152 rootNav->releaseEntry();
8154 RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
8158 //----------------------------------------------------------------------------
8159 // create a (sorted) list of separate documentation pages
8161 static void buildPageList(EntryNav *rootNav)
8163 if (rootNav->section() == Entry::PAGEDOC_SEC)
8165 rootNav->loadEntry(g_storage);
8166 Entry *root = rootNav->entry();
8168 if (!root->name.isEmpty())
8170 addRelatedPage(rootNav);
8173 rootNav->releaseEntry();
8175 else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8177 rootNav->loadEntry(g_storage);
8178 Entry *root = rootNav->entry();
8180 QCString title=root->args.stripWhiteSpace();
8181 if (title.isEmpty()) title=theTranslator->trMainPage();
8182 //QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8183 QCString name = "index";
8184 addRefItem(root->sli,
8192 rootNav->releaseEntry();
8194 RECURSE_ENTRYTREE(buildPageList,rootNav);
8197 static void findMainPage(EntryNav *rootNav)
8199 if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8201 rootNav->loadEntry(g_storage);
8202 Entry *root = rootNav->entry();
8204 if (Doxygen::mainPage==0)
8206 //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8207 QCString title=root->args.stripWhiteSpace();
8208 //QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8209 QCString indexName="index";
8210 Doxygen::mainPage = new PageDef(root->docFile,root->docLine,
8211 indexName, root->brief+root->doc+root->inbodyDocs,title);
8212 //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8213 Doxygen::mainPage->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8214 Doxygen::mainPage->setFileName(indexName);
8215 Doxygen::mainPage->setShowToc(root->stat);
8216 addPageToContext(Doxygen::mainPage,rootNav);
8218 // a page name is a label as well!
8219 SectionInfo *si=new SectionInfo(
8221 Doxygen::mainPage->name(),
8222 Doxygen::mainPage->title(),
8225 Doxygen::sectionDict.append(indexName,si);
8226 Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8230 warn(root->fileName,root->startLine,
8231 "warning: found more than one \\mainpage comment block! Skipping this "
8236 rootNav->releaseEntry();
8238 RECURSE_ENTRYTREE(findMainPage,rootNav);
8241 static void computePageRelations(EntryNav *rootNav)
8243 if ((rootNav->section()==Entry::PAGEDOC_SEC ||
8244 rootNav->section()==Entry::MAINPAGEDOC_SEC
8246 && !rootNav->name().isEmpty()
8249 rootNav->loadEntry(g_storage);
8250 Entry *root = rootNav->entry();
8252 PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8253 Doxygen::pageSDict->find(root->name) :
8257 QListIterator<BaseInfo> bii(*root->extends);
8259 for (bii.toFirst();(bi=bii.current());++bii)
8261 PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8264 pd->addInnerCompound(subPd);
8265 //printf("*** Added subpage relation: %s->%s\n",
8266 // pd->name().data(),subPd->name().data());
8271 rootNav->releaseEntry();
8273 RECURSE_ENTRYTREE(computePageRelations,rootNav);
8276 static void checkPageRelations()
8278 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8280 for (pdi.toFirst();(pd=pdi.current());++pdi)
8282 Definition *ppd = pd->getOuterScope();
8287 err("warning: page defined at line %d of file %s with label %s is a subpage "
8288 "of itself! Please remove this cyclic dependency.\n",
8289 pd->docLine(),pd->docFile().data(),pd->name().data());
8292 ppd=ppd->getOuterScope();
8297 //----------------------------------------------------------------------------
8299 static void resolveUserReferences()
8301 SDict<SectionInfo>::Iterator sdi(Doxygen::sectionDict);
8303 for (;(si=sdi.current());++sdi)
8305 //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8306 // si->label.data(),si->definition?si->definition->name().data():"<none>",
8307 // si->fileName.data());
8310 // hack: the items of a todo/test/bug/deprecated list are all fragments from
8311 // different files, so the resulting section's all have the wrong file
8312 // name (not from the todo/test/bug/deprecated list, but from the file in
8313 // which they are defined). We correct this here by looking at the
8314 // generated section labels!
8315 QDictIterator<RefList> rli(*Doxygen::xrefLists);
8317 for (rli.toFirst();(rl=rli.current());++rli)
8319 QCString label="_"+rl->listName(); // "_todo", "_test", ...
8320 if (si->label.left(label.length())==label)
8322 si->fileName=rl->listName();
8328 //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8331 // if this section is in a page and the page is in a group, then we
8332 // have to adjust the link file name to point to the group.
8333 if (!si->fileName.isEmpty() &&
8334 (pd=Doxygen::pageSDict->find(si->fileName)) &&
8337 si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8342 // TODO: there should be one function in Definition that returns
8343 // the file to link to, so we can avoid the following tests.
8345 if (si->definition->definitionType()==Definition::TypeMember)
8347 gd = ((MemberDef *)si->definition)->getGroupDef();
8352 si->fileName=gd->getOutputFileBase().copy();
8356 //si->fileName=si->definition->getOutputFileBase().copy();
8357 //printf("Setting si->fileName to %s\n",si->fileName.data());
8361 //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8367 //----------------------------------------------------------------------------
8368 // generate all separate documentation pages
8371 static void generatePageDocs()
8373 //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8374 if (documentedPages==0) return;
8375 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8377 for (pdi.toFirst();(pd=pdi.current());++pdi)
8379 if (!pd->getGroupDef() && !pd->isReference())
8381 msg("Generating docs for page %s...\n",pd->name().data());
8382 Doxygen::insideMainPage=TRUE;
8383 pd->writeDocumentation(*g_outputList);
8384 Doxygen::insideMainPage=FALSE;
8389 //----------------------------------------------------------------------------
8390 // create a (sorted) list & dictionary of example pages
8392 static void buildExampleList(EntryNav *rootNav)
8394 if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty())
8396 rootNav->loadEntry(g_storage);
8397 Entry *root = rootNav->entry();
8399 if (Doxygen::exampleSDict->find(root->name))
8401 warn(root->fileName,root->startLine,
8402 "warning: Example %s was already documented. Ignoring "
8403 "documentation found here.",
8409 PageDef *pd=new PageDef(root->fileName,root->startLine,
8410 root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8411 pd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
8412 pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
8413 pd->addSectionsToDefinition(root->anchors);
8414 pd->setLanguage(root->lang);
8415 //pi->addSections(root->anchors);
8417 Doxygen::exampleSDict->inSort(root->name,pd);
8418 //we don't add example to groups
8419 //addExampleToGroups(root,pd);
8422 rootNav->releaseEntry();
8424 RECURSE_ENTRYTREE(buildExampleList,rootNav);
8427 //----------------------------------------------------------------------------
8428 // prints the Entry tree (for debugging)
8430 void printNavTree(EntryNav *rootNav,int indent)
8433 indentStr.fill(' ',indent);
8434 msg("%s%s (sec=0x%x)\n",
8435 indentStr.isEmpty()?"":indentStr.data(),
8436 rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8437 rootNav->section());
8438 if (rootNav->children())
8440 EntryNavListIterator eli(*rootNav->children());
8441 for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8446 //----------------------------------------------------------------------------
8447 // generate the example documentation
8449 static void generateExampleDocs()
8451 g_outputList->disable(OutputGenerator::Man);
8452 PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8454 for (pdi.toFirst();(pd=pdi.current());++pdi)
8456 msg("Generating docs for example %s...\n",pd->name().data());
8457 resetCCodeParserState();
8458 QCString n=pd->getOutputFileBase();
8459 startFile(*g_outputList,n,n,pd->name());
8460 startTitle(*g_outputList,n);
8461 g_outputList->docify(pd->name());
8462 endTitle(*g_outputList,n,0);
8463 g_outputList->startContents();
8464 g_outputList->parseDoc(pd->docFile(), // file
8465 pd->docLine(), // startLine
8468 pd->documentation()+"\n\n\\include "+pd->name(), // docs
8469 TRUE, // index words
8473 endFile(*g_outputList); // contains g_outputList->endContents()
8475 g_outputList->enable(OutputGenerator::Man);
8478 //----------------------------------------------------------------------------
8479 // generate module pages
8481 static void generateGroupDocs()
8483 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8485 for (gli.toFirst();(gd=gli.current());++gli)
8487 if (!gd->isReference())
8489 gd->writeDocumentation(*g_outputList);
8494 //----------------------------------------------------------------------------
8496 //static void generatePackageDocs()
8498 // writePackageIndex(*g_outputList);
8500 // if (Doxygen::packageDict.count()>0)
8502 // PackageSDict::Iterator pdi(Doxygen::packageDict);
8504 // for (pdi.toFirst();(pd=pdi.current());++pdi)
8506 // pd->writeDocumentation(*g_outputList);
8511 //----------------------------------------------------------------------------
8512 // generate module pages
8514 static void generateNamespaceDocs()
8516 //writeNamespaceIndex(*g_outputList);
8518 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8520 // for each namespace...
8521 for (;(nd=nli.current());++nli)
8524 if (nd->isLinkableInProject())
8526 msg("Generating docs for namespace %s\n",nd->name().data());
8527 nd->writeDocumentation(*g_outputList);
8530 // for each class in the namespace...
8531 ClassSDict::Iterator cli(*nd->getClassSDict());
8532 for ( ; cli.current() ; ++cli )
8534 ClassDef *cd=cli.current();
8535 if ( ( cd->isLinkableInProject() &&
8536 cd->templateMaster()==0
8537 ) // skip external references, anonymous compounds and
8538 // template instances and nested classes
8539 && !cd->isHidden() && !cd->isEmbeddedInOuterScope()
8542 msg("Generating docs for compound %s...\n",cd->name().data());
8544 cd->writeDocumentation(*g_outputList);
8545 cd->writeMemberList(*g_outputList);
8547 cd->writeDocumentationForInnerClasses(*g_outputList);
8553 static QCString fixSlashes(QCString &s)
8557 for (i=0;i<s.length();i++)
8574 //----------------------------------------------------------------------------
8576 static bool openOutputFile(const char *outFile,QFile &f)
8578 bool fileOpened=FALSE;
8579 bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
8580 if (writeToStdout) // write to stdout
8582 fileOpened = f.open(IO_WriteOnly,stdout);
8584 else // write to file
8586 QFileInfo fi(outFile);
8587 if (fi.exists()) // create a backup
8590 QFileInfo backup(fi.fileName()+".bak");
8591 if (backup.exists()) // remove existing backup
8592 dir.remove(backup.fileName());
8593 dir.rename(fi.fileName(),fi.fileName()+".bak");
8596 fileOpened = f.open(IO_WriteOnly|IO_Translate);
8601 /*! Generate a template version of the configuration file.
8602 * If the \a shortList parameter is TRUE a configuration file without
8603 * comments will be generated.
8605 static void generateConfigFile(const char *configFile,bool shortList,
8606 bool updateOnly=FALSE)
8609 bool fileOpened=openOutputFile(configFile,f);
8610 bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
8614 Config::instance()->writeTemplate(t,shortList,updateOnly);
8619 msg("\n\nConfiguration file `%s' created.\n\n",configFile);
8620 msg("Now edit the configuration file and enter\n\n");
8621 if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile"))
8622 msg(" doxygen %s\n\n",configFile);
8624 msg(" doxygen\n\n");
8625 msg("to generate the documentation for your project\n\n");
8629 msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
8635 err("error: Cannot open file %s for writing\n",configFile);
8640 //----------------------------------------------------------------------------
8641 // read and parse a tag file
8643 //static bool readLineFromFile(QFile &f,QCString &s)
8647 // while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
8648 // return f.atEnd();
8651 //----------------------------------------------------------------------------
8653 static void readTagFile(Entry *root,const char *tl)
8655 QCString tagLine = tl;
8658 int eqPos = tagLine.find('=');
8659 if (eqPos!=-1) // tag command contains a destination
8661 fileName = tagLine.left(eqPos).stripWhiteSpace();
8662 destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
8663 QFileInfo fi(fileName);
8664 Doxygen::tagDestinationDict.insert(fi.fileName().utf8(),new QCString(destName));
8665 //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
8672 QFileInfo fi(fileName);
8673 if (!fi.exists() || !fi.isFile())
8675 err("error: Tag file `%s' does not exist or is not a file. Skipping it...\n",
8680 if (!destName.isEmpty())
8681 msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
8683 msg("Reading tag file `%s'...\n",fileName.data());
8685 parseTagFile(root,fi.absFilePath().utf8(),fi.fileName().utf8());
8688 //----------------------------------------------------------------------------
8689 static void copyStyleSheet()
8691 QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
8692 if (!htmlStyleSheet.isEmpty())
8694 QFileInfo fi(htmlStyleSheet);
8697 err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
8698 htmlStyleSheet.resize(0); // revert to the default
8702 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8703 copyFile(htmlStyleSheet,destFileName);
8706 QCString &htmlExtraStyleSheet = Config_getString("HTML_EXTRA_STYLESHEET");
8707 if (!htmlExtraStyleSheet.isEmpty())
8709 QFileInfo fi(htmlExtraStyleSheet);
8712 err("Style sheet '%s' specified by HTML_EXTRA_STYLESHEET does not exist!\n",htmlExtraStyleSheet.data());
8713 htmlExtraStyleSheet.resize(0); // revert to the default
8717 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8718 copyFile(htmlExtraStyleSheet,destFileName);
8724 static void copyLogo()
8726 QCString &projectLogo = Config_getString("PROJECT_LOGO");
8727 if (!projectLogo.isEmpty())
8729 QFileInfo fi(projectLogo);
8732 err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
8733 projectLogo.resize(0); // revert to the default
8737 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8738 copyFile(projectLogo,destFileName);
8739 Doxygen::indexList.addImageFile(fi.fileName().data());
8744 static void copyExtraFiles()
8746 QStrList files = Config_getList("HTML_EXTRA_FILES");
8748 for (i=0; i<files.count(); ++i)
8750 QCString fileName(files.at(i));
8752 if (!fileName.isEmpty())
8754 QFileInfo fi(fileName);
8757 err("Extra HTML file '%s' specified in HTML_EXTRA_FILES does not exist!\n", fileName.data());
8761 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8762 Doxygen::indexList.addImageFile(fi.fileName().data());
8763 copyFile(fileName, destFileName);
8769 //! parse the list of input files
8770 static void parseFiles(Entry *root,EntryNav *rootNav)
8772 QCString *s=g_inputFiles.first();
8775 QCString fileName=*s;
8777 int ei = fileName.findRev('.');
8778 if (ei!=-1) extension=fileName.right(fileName.length()-ei);
8779 ParserInterface *parser = Doxygen::parserManager->getParser(extension);
8781 QFileInfo fi(fileName);
8782 BufStr preBuf(fi.size()+4096);
8784 if (Config_getBool("ENABLE_PREPROCESSING") &&
8785 parser->needsPreprocessing(extension))
8787 BufStr inBuf(fi.size()+4096);
8788 msg("Preprocessing %s...\n",s->data());
8789 readInputFile(fileName,inBuf);
8790 preprocessFile(fileName,inBuf,preBuf);
8792 else // no preprocessing
8794 msg("Reading %s...\n",s->data());
8795 readInputFile(fileName,preBuf);
8798 BufStr convBuf(preBuf.curPos()+1024);
8800 // convert multi-line C++ comments to C style comments
8801 convertCppComments(&preBuf,&convBuf,fileName);
8803 convBuf.addChar('\0');
8805 // use language parse to parse the file
8806 parser->parseInput(fileName,convBuf.data(),root);
8808 // store the Entry tree in a file and create an index to
8809 // navigate/load entries
8811 FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig);
8813 //printf("root->createNavigationIndex for %s\n",fd->name().data());
8814 root->createNavigationIndex(rootNav,g_storage,fd);
8816 s=g_inputFiles.next();
8820 // resolves a path that may include symlinks, if a recursive symlink is
8821 // found an empty string is returned.
8822 static QCString resolveSymlink(QCString path)
8827 QDict<void> nonSymlinks;
8829 QCString result = path;
8830 QCString oldPrefix = "/";
8834 // UNC path, skip server and share name
8835 if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
8836 sepPos = result.find('/',2);
8838 sepPos = result.find('/',sepPos+1);
8840 sepPos = result.find('/',sepPos+1);
8842 QCString prefix = sepPos==-1 ? result : result.left(sepPos);
8843 if (nonSymlinks.find(prefix)==0)
8848 QString target = fi.readLink();
8849 bool isRelative = QFileInfo(target).isRelative();
8852 target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
8856 if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
8860 target+=result.mid(sepPos);
8862 result = QDir::cleanDirPath(target).data();
8864 if (known.find(result)) return QCString(); // recursive symlink!
8865 known.insert(result,(void*)0x8);
8870 else // link to absolute path
8878 nonSymlinks.insert(prefix,(void*)0x8);
8885 return QDir::cleanDirPath(result).data();
8888 static QDict<void> g_pathsVisited(1009);
8890 //----------------------------------------------------------------------------
8891 // Read all files matching at least one pattern in `patList' in the
8892 // directory represented by `fi'.
8893 // The directory is read iff the recusiveFlag is set.
8894 // The contents of all files is append to the input string
8896 int readDir(QFileInfo *fi,
8897 FileNameList *fnList,
8898 FileNameDict *fnDict,
8899 StringDict *exclDict,
8901 QStrList *exclPatList,
8902 StringList *resultList,
8903 StringDict *resultDict,
8904 bool errorIfNotExist,
8906 QDict<void> *killDict
8909 QCString dirName = fi->absFilePath().utf8();
8910 if (fi->isSymLink())
8912 dirName = resolveSymlink(dirName.data());
8913 if (dirName.isEmpty()) return 0; // recusive symlink
8914 if (g_pathsVisited.find(dirName)) return 0; // already visited path
8915 g_pathsVisited.insert(dirName,(void*)0x8);
8918 dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
8920 msg("Searching for files in directory %s\n", fi->absFilePath().data());
8921 //printf("killDict=%p count=%d\n",killDict,killDict->count());
8923 const QFileInfoList *list = dir.entryInfoList();
8926 QFileInfoListIterator it( *list );
8929 while ((cfi=it.current()))
8931 if (exclDict==0 || exclDict->find(cfi->absFilePath().utf8())==0)
8932 { // file should not be excluded
8933 //printf("killDict->find(%s)\n",cfi->absFilePath().data());
8934 if (!cfi->exists() || !cfi->isReadable())
8936 if (errorIfNotExist)
8938 err("warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
8941 else if (cfi->isFile() &&
8942 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
8943 (patList==0 || patternMatch(*cfi,patList)) &&
8944 !patternMatch(*cfi,exclPatList) &&
8945 (killDict==0 || killDict->find(cfi->absFilePath().utf8())==0)
8948 totalSize+=cfi->size()+cfi->absFilePath().length()+4;
8949 QCString name=convertToQCString(cfi->fileName());
8950 //printf("New file %s\n",name.data());
8953 FileDef *fd=new FileDef(cfi->dirPath().utf8()+"/",name);
8955 if (!name.isEmpty() && (fn=(*fnDict)[name]))
8961 fn = new FileName(cfi->absFilePath().utf8(),name);
8963 if (fnList) fnList->inSort(fn);
8964 fnDict->insert(name,fn);
8968 if (resultList || resultDict)
8970 rs=new QCString(cfi->absFilePath().utf8());
8972 if (resultList) resultList->append(rs);
8973 if (resultDict) resultDict->insert(cfi->absFilePath().utf8(),rs);
8974 if (killDict) killDict->insert(cfi->absFilePath().utf8(),(void *)0x8);
8976 else if (recursive &&
8977 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
8979 !patternMatch(*cfi,exclPatList) &&
8980 cfi->fileName().at(0)!='.') // skip "." ".." and ".dir"
8982 cfi->setFile(cfi->absFilePath());
8983 totalSize+=readDir(cfi,fnList,fnDict,exclDict,
8984 patList,exclPatList,resultList,resultDict,errorIfNotExist,
8985 recursive,killDict);
8995 //----------------------------------------------------------------------------
8996 // read a file or all files in a directory and append their contents to the
8997 // input string. The names of the files are appended to the `fiList' list.
8999 int readFileOrDirectory(const char *s,
9000 FileNameList *fnList,
9001 FileNameDict *fnDict,
9002 StringDict *exclDict,
9004 QStrList *exclPatList,
9005 StringList *resultList,
9006 StringDict *resultDict,
9008 bool errorIfNotExist,
9009 QDict<void> *killDict
9012 //printf("killDict=%p count=%d\n",killDict,killDict->count());
9013 // strip trailing slashes
9016 char lc = fs.at(fs.length()-1);
9017 if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
9020 //printf("readFileOrDirectory(%s)\n",s);
9023 if (exclDict==0 || exclDict->find(fi.absFilePath().utf8())==0)
9025 if (!fi.exists() || !fi.isReadable())
9027 if (errorIfNotExist)
9029 err("warning: source %s is not a readable file or directory... skipping.\n",s);
9032 else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
9036 //printf("killDict->find(%s)\n",fi.absFilePath().data());
9037 if (killDict==0 || killDict->find(fi.absFilePath().utf8())==0)
9039 totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input);
9040 //fiList->inSort(new FileInfo(fi));
9041 QCString name=convertToQCString(fi.fileName());
9042 //printf("New file %s\n",name.data());
9045 FileDef *fd=new FileDef(fi.dirPath(TRUE).utf8()+"/",name);
9047 if (!name.isEmpty() && (fn=(*fnDict)[name]))
9053 fn = new FileName(fi.absFilePath().utf8(),name);
9055 if (fnList) fnList->inSort(fn);
9056 fnDict->insert(name,fn);
9060 if (resultList || resultDict)
9062 rs=new QCString(fi.absFilePath().utf8());
9063 if (resultList) resultList->append(rs);
9064 if (resultDict) resultDict->insert(fi.absFilePath().utf8(),rs);
9067 if (killDict) killDict->insert(fi.absFilePath().utf8(),(void *)0x8);
9070 else if (fi.isDir()) // readable dir
9072 totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9073 exclPatList,resultList,resultDict,errorIfNotExist,
9074 recursive,killDict);
9082 //----------------------------------------------------------------------------
9084 void readFormulaRepository()
9086 QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
9087 if (f.open(IO_ReadOnly)) // open repository
9089 msg("Reading formula repository...\n");
9094 line=t.readLine().utf8();
9095 int se=line.find(':'); // find name and text separator.
9098 err("warning: formula.repository is corrupted!\n");
9103 QCString formName = line.left(se);
9104 QCString formText = line.right(line.length()-se-1);
9105 Formula *f=new Formula(formText);
9106 Doxygen::formulaList.append(f);
9107 Doxygen::formulaDict.insert(formText,f);
9108 Doxygen::formulaNameDict.insert(formName,f);
9114 //----------------------------------------------------------------------------
9116 static void expandAliases()
9118 QDictIterator<QCString> adi(Doxygen::aliasDict);
9120 for (adi.toFirst();(s=adi.current());++adi)
9122 *s = expandAlias(adi.currentKey(),*s);
9126 //----------------------------------------------------------------------------
9128 static void escapeAliases()
9130 QDictIterator<QCString> adi(Doxygen::aliasDict);
9132 for (adi.toFirst();(s=adi.current());++adi)
9134 QCString value=*s,newValue;
9136 // for each \n in the alias command value
9137 while ((in=value.find("\\n",p))!=-1)
9139 newValue+=value.mid(p,in-p);
9140 // expand \n's except if \n is part of a built-in command.
9141 if (value.mid(in,5)!="\\note" &&
9142 value.mid(in,5)!="\\name" &&
9143 value.mid(in,10)!="\\namespace" &&
9144 value.mid(in,14)!="\\nosubgrouping"
9147 newValue+="\\_linebr ";
9155 newValue+=value.mid(p,value.length()-p);
9157 //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9161 //----------------------------------------------------------------------------
9165 // add aliases to a dictionary
9166 Doxygen::aliasDict.setAutoDelete(TRUE);
9167 QStrList &aliasList = Config_getList("ALIASES");
9168 const char *s=aliasList.first();
9171 if (Doxygen::aliasDict[s]==0)
9174 int i=alias.find('=');
9177 QCString name=alias.left(i).stripWhiteSpace();
9178 QCString value=alias.right(alias.length()-i-1);
9179 //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
9180 if (!name.isEmpty())
9182 QCString *dn=Doxygen::aliasDict[name];
9183 if (dn==0) // insert new alias
9185 Doxygen::aliasDict.insert(name,new QCString(value));
9187 else // overwrite previous alias
9200 //----------------------------------------------------------------------------
9202 static void dumpSymbol(FTextStream &t,Definition *d)
9205 if (d->definitionType()==Definition::TypeMember)
9207 MemberDef *md = (MemberDef *)d;
9208 anchor=":"+md->anchor();
9211 if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope)
9213 scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
9215 t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9216 << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9218 << d->name() << "','"
9219 << d->getDefFileName() << "','"
9224 static void dumpSymbolMap()
9226 QFile f("symbols.sql");
9227 if (f.open(IO_WriteOnly))
9230 QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9231 DefinitionIntf *intf;
9232 for (;(intf=di.current());++di)
9234 if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9236 DefinitionListIterator dli(*(DefinitionList*)intf);
9239 for (dli.toFirst();(d=dli.current());++dli)
9244 else // single symbol
9246 Definition *d = (Definition *)intf;
9247 if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9253 //----------------------------------------------------------------------------
9255 void dumpConfigAsXML()
9257 QFile f("config.xml");
9258 if (f.open(IO_WriteOnly))
9261 Config::instance()->writeXML(t);
9265 //----------------------------------------------------------------------------
9266 // print the usage of doxygen
9268 static void usage(const char *name)
9270 msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2012\n\n",versionString);
9271 msg("You can use doxygen in a number of ways:\n\n");
9272 msg("1) Use doxygen to generate a template configuration file:\n");
9273 msg(" %s [-s] -g [configName]\n\n",name);
9274 msg(" If - is used for configName doxygen will write to standard output.\n\n");
9275 msg("2) Use doxygen to update an old configuration file:\n");
9276 msg(" %s [-s] -u [configName]\n\n",name);
9277 msg("3) Use doxygen to generate documentation using an existing ");
9278 msg("configuration file:\n");
9279 msg(" %s [configName]\n\n",name);
9280 msg(" If - is used for configName doxygen will read from standard input.\n\n");
9281 msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9282 msg(" generated documentation:\n");
9283 msg(" %s -l layoutFileName.xml\n\n",name);
9284 msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9285 msg(" RTF: %s -w rtf styleSheetFile\n",name);
9286 msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9287 msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9288 msg("6) Use doxygen to generate an rtf extensions file\n");
9289 msg(" RTF: %s -e rtf extensionsFile\n\n",name);
9290 msg("If -s is specified the comments in the config file will be omitted.\n");
9291 msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9295 //----------------------------------------------------------------------------
9296 // read the argument of option `c' from the comment argument list and
9297 // update the option index `optind'.
9299 static const char *getArg(int argc,char **argv,int &optind)
9302 if (strlen(&argv[optind][2])>0)
9304 else if (optind+1<argc && argv[optind+1][0]!='-')
9309 //----------------------------------------------------------------------------
9313 const char *lang = portable_getenv("LC_ALL");
9314 if (lang) portable_setenv("LANG",lang);
9315 setlocale(LC_ALL,"");
9316 setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
9317 setlocale(LC_NUMERIC,"C");
9319 //Doxygen::symbolMap->setAutoDelete(TRUE);
9321 Doxygen::runningTime.start();
9324 Doxygen::parserManager = new ParserManager;
9325 Doxygen::parserManager->registerParser("c", new CLanguageScanner, TRUE);
9326 Doxygen::parserManager->registerParser("python", new PythonLanguageScanner);
9327 Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
9328 Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner);
9329 Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
9330 Doxygen::parserManager->registerParser("tcl", new TclLanguageScanner);
9331 Doxygen::parserManager->registerParser("md", new MarkdownFileParser);
9333 // register any additional parsers here...
9335 initDefaultExtensionMapping();
9336 initClassMemberIndices();
9337 initNamespaceMemberIndices();
9338 initFileMemberIndices();
9340 Doxygen::symbolMap = new QDict<DefinitionIntf>(1000);
9341 Doxygen::inputNameList = new FileNameList;
9342 Doxygen::inputNameList->setAutoDelete(TRUE);
9343 Doxygen::memberNameSDict = new MemberNameSDict(10000);
9344 Doxygen::memberNameSDict->setAutoDelete(TRUE);
9345 Doxygen::functionNameSDict = new MemberNameSDict(10000);
9346 Doxygen::functionNameSDict->setAutoDelete(TRUE);
9347 Doxygen::groupSDict = new GroupSDict(17);
9348 Doxygen::groupSDict->setAutoDelete(TRUE);
9349 Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>");
9350 Doxygen::namespaceSDict = new NamespaceSDict(20);
9351 Doxygen::namespaceSDict->setAutoDelete(TRUE);
9352 Doxygen::classSDict = new ClassSDict(1009);
9353 Doxygen::classSDict->setAutoDelete(TRUE);
9354 Doxygen::hiddenClasses = new ClassSDict(257);
9355 Doxygen::hiddenClasses->setAutoDelete(TRUE);
9356 Doxygen::directories = new DirSDict(17);
9357 Doxygen::directories->setAutoDelete(TRUE);
9358 Doxygen::pageSDict = new PageSDict(1009); // all doc pages
9359 Doxygen::pageSDict->setAutoDelete(TRUE);
9360 Doxygen::exampleSDict = new PageSDict(1009); // all examples
9361 Doxygen::exampleSDict->setAutoDelete(TRUE);
9362 Doxygen::inputNameDict = new FileNameDict(10007);
9363 Doxygen::includeNameDict = new FileNameDict(10007);
9364 Doxygen::exampleNameDict = new FileNameDict(1009);
9365 Doxygen::exampleNameDict->setAutoDelete(TRUE);
9366 Doxygen::imageNameDict = new FileNameDict(257);
9367 Doxygen::dotFileNameDict = new FileNameDict(257);
9368 Doxygen::mscFileNameDict = new FileNameDict(257);
9369 Doxygen::sectionDict.setAutoDelete(TRUE);
9370 Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
9371 Doxygen::tagDestinationDict.setAutoDelete(TRUE);
9372 Doxygen::dirRelations.setAutoDelete(TRUE);
9373 Doxygen::citeDict = new CiteDict(257);
9376 void cleanUpDoxygen()
9378 delete Doxygen::inputNameDict;
9379 delete Doxygen::includeNameDict;
9380 delete Doxygen::exampleNameDict;
9381 delete Doxygen::imageNameDict;
9382 delete Doxygen::dotFileNameDict;
9383 delete Doxygen::mscFileNameDict;
9384 delete Doxygen::mainPage;
9385 delete Doxygen::pageSDict;
9386 delete Doxygen::exampleSDict;
9387 delete Doxygen::globalScope;
9388 delete Doxygen::xrefLists;
9389 delete Doxygen::parserManager;
9390 cleanUpPreprocessor();
9391 delete theTranslator;
9392 delete g_outputList;
9393 Mappers::freeMappers();
9396 if (Doxygen::symbolMap)
9398 // iterate through Doxygen::symbolMap and delete all
9399 // DefinitionList objects, since they have no owner
9400 QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
9402 for (dli.toFirst();(di=dli.current());)
9404 if (di->definitionType()==DefinitionIntf::TypeSymbolList)
9406 DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
9407 delete (DefinitionList *)tmp;
9416 delete Doxygen::inputNameList;
9417 delete Doxygen::memberNameSDict;
9418 delete Doxygen::functionNameSDict;
9419 delete Doxygen::groupSDict;
9420 delete Doxygen::classSDict;
9421 delete Doxygen::hiddenClasses;
9422 delete Doxygen::namespaceSDict;
9423 delete Doxygen::directories;
9425 //delete Doxygen::symbolMap; <- we cannot do this unless all static lists
9426 // (such as Doxygen::namespaceSDict)
9427 // with objects based on Definition are made
9431 static int computeIdealCacheParam(uint v)
9433 //printf("computeIdealCacheParam(v=%u)\n",v);
9436 while (v!=0) v>>=1,r++;
9439 // convert to a valid cache size value
9440 return QMAX(0,QMIN(r-16,9));
9443 void readConfiguration(int argc, char **argv)
9445 /**************************************************************************
9446 * Handle arguments *
9447 **************************************************************************/
9450 const char *configName=0;
9451 const char *layoutName=0;
9452 const char *debugLabel;
9453 const char *formatName;
9454 bool genConfig=FALSE;
9455 bool shortList=FALSE;
9456 bool updateConfig=FALSE;
9457 bool genLayout=FALSE;
9458 while (optind<argc && argv[optind][0]=='-' &&
9459 (isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
9460 argv[optind][1]=='-')
9463 switch(argv[optind][1])
9467 configName=getArg(argc,argv,optind);
9468 if (strcmp(argv[optind+1],"-")==0)
9469 { configName="-"; optind++; }
9471 { configName="Doxyfile"; }
9475 layoutName=getArg(argc,argv,optind);
9477 { layoutName="DoxygenLayout.xml"; }
9480 debugLabel=getArg(argc,argv,optind);
9481 Debug::setFlag(debugLabel);
9490 formatName=getArg(argc,argv,optind);
9493 err("error: option -e is missing format specifier rtf.\n");
9497 if (stricmp(formatName,"rtf")==0)
9501 err("error: option \"-e rtf\" is missing an extensions file name\n");
9506 if (openOutputFile(argv[optind+1],f))
9508 RTFGenerator::writeExtensionsFile(f);
9513 err("error: option \"-e\" has invalid format specifier.\n");
9518 formatName=getArg(argc,argv,optind);
9521 err("error: option -w is missing format specifier rtf, html or latex\n");
9525 if (stricmp(formatName,"rtf")==0)
9529 err("error: option \"-w rtf\" is missing a style sheet file name\n");
9534 if (openOutputFile(argv[optind+1],f))
9536 RTFGenerator::writeStyleSheetFile(f);
9541 else if (stricmp(formatName,"html")==0)
9543 if (optind+4<argc || QFileInfo("Doxyfile").exists())
9545 QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
9546 if (!Config::instance()->parse(df))
9548 err("error opening or reading configuration file %s!\n",argv[optind+4]);
9552 Config::instance()->substituteEnvironmentVars();
9553 Config::instance()->convertStrToVal();
9554 // avoid bootstrapping issues when the config file already
9555 // refers to the files that we are supposed to parse.
9556 Config_getString("HTML_HEADER")="";
9557 Config_getString("HTML_FOOTER")="";
9558 Config::instance()->check();
9562 Config::instance()->init();
9566 err("error: option \"-w html\" does not have enough arguments\n");
9571 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
9572 if (!setTranslator(outputLanguage))
9574 err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
9578 if (openOutputFile(argv[optind+1],f))
9580 HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
9583 if (openOutputFile(argv[optind+2],f))
9585 HtmlGenerator::writeFooterFile(f);
9588 if (openOutputFile(argv[optind+3],f))
9590 HtmlGenerator::writeStyleSheetFile(f);
9595 else if (stricmp(formatName,"latex")==0)
9597 if (optind+4<argc) // use config file to get settings
9599 if (!Config::instance()->parse(argv[optind+4]))
9601 err("error opening or reading configuration file %s!\n",argv[optind+4]);
9604 Config::instance()->substituteEnvironmentVars();
9605 Config::instance()->convertStrToVal();
9606 Config_getString("LATEX_HEADER")="";
9607 Config::instance()->check();
9609 else // use default config
9611 Config::instance()->init();
9615 err("error: option \"-w latex\" does not have enough arguments\n");
9620 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
9621 if (!setTranslator(outputLanguage))
9623 err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
9627 if (openOutputFile(argv[optind+1],f))
9629 LatexGenerator::writeHeaderFile(f);
9632 if (openOutputFile(argv[optind+2],f))
9634 LatexGenerator::writeFooterFile(f);
9637 if (openOutputFile(argv[optind+3],f))
9639 LatexGenerator::writeStyleSheetFile(f);
9646 err("error: Illegal format specifier %s: should be one of rtf, html, latex, or bst\n",formatName);
9652 g_dumpSymbolMap = TRUE;
9655 g_dumpConfigAsXML = TRUE;
9658 if (strcmp(&argv[optind][2],"help")==0)
9662 else if (strcmp(&argv[optind][2],"version")==0)
9664 msg("%s\n",versionString);
9670 setvbuf(stdout,NULL,_IONBF,0);
9671 Doxygen::outputToWizard=TRUE;
9678 err("Unknown option -%c\n",argv[optind][1]);
9684 /**************************************************************************
9685 * Parse or generate the config file *
9686 **************************************************************************/
9688 Config::instance()->init();
9692 if (g_dumpConfigAsXML)
9694 checkConfiguration();
9695 generateConfigFile(configName,shortList);
9701 generateConfigFile(configName,shortList);
9708 writeDefaultLayoutFile(layoutName);
9713 QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
9716 if (configFileInfo1.exists())
9718 configName="Doxyfile";
9720 else if (configFileInfo2.exists())
9722 configName="doxyfile";
9726 err("Doxyfile not found and no input file specified!\n");
9732 QFileInfo fi(argv[optind]);
9733 if (fi.exists() || strcmp(argv[optind],"-")==0)
9735 configName=argv[optind];
9739 err("error: configuration file %s not found!\n",argv[optind]);
9745 if (!Config::instance()->parse(configName))
9747 err("error: could not open or read configuration file %s!\n",configName);
9754 generateConfigFile(configName,shortList,TRUE);
9759 /* Perlmod wants to know the path to the config file.*/
9760 QFileInfo configFileInfo(configName);
9761 setPerlModDoxyfile(configFileInfo.absFilePath().data());
9765 /** check and resolve config options */
9766 void checkConfiguration()
9769 Config::instance()->substituteEnvironmentVars();
9770 Config::instance()->convertStrToVal();
9771 Config::instance()->check();
9773 initWarningFormat();
9776 /** adjust globals that depend on configuration settings. */
9777 void adjustConfiguration()
9779 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
9780 if (!setTranslator(outputLanguage))
9782 err("warning: Output language %s not supported! Using English instead.\n",
9783 outputLanguage.data());
9785 QStrList &includePath = Config_getList("INCLUDE_PATH");
9786 char *s=includePath.first();
9790 addSearchDir(fi.absFilePath().utf8());
9791 s=includePath.next();
9794 /* Set the global html file extension. */
9795 Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
9798 Doxygen::xrefLists->setAutoDelete(TRUE);
9800 Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") ||
9801 Config_getBool("CALLER_GRAPH") ||
9802 Config_getBool("REFERENCES_RELATION") ||
9803 Config_getBool("REFERENCED_BY_RELATION");
9805 Doxygen::markdownSupport = Config_getBool("MARKDOWN_SUPPORT");
9807 /**************************************************************************
9808 * Add custom extension mappings
9809 **************************************************************************/
9811 QStrList &extMaps = Config_getList("EXTENSION_MAPPING");
9812 char *mapping = extMaps.first();
9815 QCString mapStr = mapping;
9817 if ((i=mapStr.find('='))!=-1)
9819 QCString ext=mapStr.left(i).stripWhiteSpace().lower();
9820 QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
9821 if (!updateLanguageMapping(ext,language))
9823 err("Failed to map file extension '%s' to unsupported language '%s'.\n"
9824 "Check the EXTENSION_MAPPING setting in the config file.\n",
9825 ext.data(),language.data());
9829 msg("Adding custom extension mapping: .%s will be treated as language %s\n",
9830 ext.data(),language.data());
9833 mapping = extMaps.next();
9837 // add predefined macro name to a dictionary
9838 QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
9839 s=expandAsDefinedList.first();
9842 if (Doxygen::expandAsDefinedDict[s]==0)
9844 Doxygen::expandAsDefinedDict.insert(s,(void *)666);
9846 s=expandAsDefinedList.next();
9849 // read aliases and store them in a dictionary
9852 // store number of spaces in a tab into Doxygen::spaces
9853 int &tabSize = Config_getInt("TAB_SIZE");
9854 Doxygen::spaces.resize(tabSize+1);
9855 int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
9856 Doxygen::spaces.at(tabSize)='\0';
9860 static void stopDoxygen(int)
9863 msg("Cleaning up...\n");
9864 if (!Doxygen::entryDBFileName.isEmpty())
9866 thisDir.remove(Doxygen::entryDBFileName);
9868 if (!Doxygen::objDBFileName.isEmpty())
9870 thisDir.remove(Doxygen::objDBFileName);
9876 static void exitDoxygen()
9878 if (!g_successfulRun) // premature exit
9881 msg("Exiting...\n");
9882 if (!Doxygen::entryDBFileName.isEmpty())
9884 thisDir.remove(Doxygen::entryDBFileName);
9886 if (!Doxygen::objDBFileName.isEmpty())
9888 thisDir.remove(Doxygen::objDBFileName);
9893 static QCString createOutputDirectory(const QCString &baseDirName,
9894 const char *formatDirOption,
9895 const char *defaultDirName)
9897 // Note the & on the next line, we modify the formatDirOption!
9898 QCString &formatDirName = Config_getString(formatDirOption);
9899 if (formatDirName.isEmpty())
9901 formatDirName = baseDirName + defaultDirName;
9903 else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
9905 formatDirName.prepend(baseDirName+'/');
9907 QDir formatDir(formatDirName);
9908 if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
9910 err("Could not create output directory %s\n", formatDirName.data());
9914 return formatDirName;
9917 static QCString getQchFileName()
9919 QCString const & qchFile = Config_getString("QCH_FILE");
9920 if (!qchFile.isEmpty())
9925 QCString const & projectName = Config_getString("PROJECT_NAME");
9926 QCString const & versionText = Config_getString("PROJECT_NUMBER");
9928 return QCString("../qch/")
9929 + (projectName.isEmpty() ? QCString("index") : projectName)
9930 + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
9934 void searchInputFiles(StringList &inputFiles)
9936 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
9937 bool alwaysRecursive = Config_getBool("RECURSIVE");
9938 StringDict excludeNameDict(1009);
9939 excludeNameDict.setAutoDelete(TRUE);
9941 // gather names of all files in the include path
9942 msg("Searching for include files...\n");
9943 QStrList &includePathList = Config_getList("INCLUDE_PATH");
9944 char *s=includePathList.first();
9947 QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
9950 pl = Config_getList("FILE_PATTERNS");
9952 readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
9955 s=includePathList.next();
9958 msg("Searching for example files...\n");
9959 QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
9960 s=examplePathList.first();
9963 readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
9964 &Config_getList("EXAMPLE_PATTERNS"),
9966 (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
9967 s=examplePathList.next();
9970 msg("Searching for images...\n");
9971 QStrList &imagePathList=Config_getList("IMAGE_PATH");
9972 s=imagePathList.first();
9975 readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
9978 s=imagePathList.next();
9981 msg("Searching for dot files...\n");
9982 QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
9983 s=dotFileList.first();
9986 readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
9989 s=dotFileList.next();
9992 msg("Searching for msc files...\n");
9993 QStrList &mscFileList=Config_getList("MSCFILE_DIRS");
9994 s=mscFileList.first();
9997 readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
10000 s=mscFileList.next();
10004 msg("Searching for files to exclude\n");
10005 QStrList &excludeList = Config_getList("EXCLUDE");
10006 s=excludeList.first();
10009 readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
10010 0,0,&excludeNameDict,
10013 s=excludeList.next();
10016 /**************************************************************************
10017 * Determine Input Files *
10018 **************************************************************************/
10020 msg("Searching for files to process...\n");
10021 QDict<void> *killDict = new QDict<void>(10007);
10023 QStrList &inputList=Config_getList("INPUT");
10024 inputFiles.setAutoDelete(TRUE);
10025 s=inputList.first();
10029 uint l = path.length();
10030 // strip trailing slashes
10031 if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
10033 inputSize+=readFileOrDirectory(
10035 Doxygen::inputNameList,
10036 Doxygen::inputNameDict,
10038 &Config_getList("FILE_PATTERNS"),
10044 s=inputList.next();
10052 atexit(exitDoxygen);
10055 /**************************************************************************
10056 * Make sure the output directory exists
10057 **************************************************************************/
10058 QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
10059 if (outputDirectory.isEmpty())
10061 outputDirectory=QDir::currentDirPath().utf8();
10065 QDir dir(outputDirectory);
10068 dir.setPath(QDir::currentDirPath());
10069 if (!dir.mkdir(outputDirectory))
10071 err("error: tag OUTPUT_DIRECTORY: Output directory `%s' does not "
10072 "exist and cannot be created\n",outputDirectory.data());
10076 else if (!Config_getBool("QUIET"))
10078 err("Notice: Output directory `%s' does not exist. "
10079 "I have created it for you.\n", outputDirectory.data());
10081 dir.cd(outputDirectory);
10083 outputDirectory=dir.absPath().utf8();
10086 /**************************************************************************
10087 * Initialize global lists and dictionaries
10088 **************************************************************************/
10090 int cacheSize = Config_getInt("SYMBOL_CACHE_SIZE");
10091 if (cacheSize<0) cacheSize=0;
10092 if (cacheSize>9) cacheSize=9;
10093 Doxygen::symbolCache = new ObjCache(16+cacheSize); // 16 -> room for 65536 elements,
10094 // ~2.0 MByte "overhead"
10095 //Doxygen::symbolCache = new ObjCache(1); // only to stress test cache behaviour
10096 Doxygen::symbolStorage = new Store;
10098 // also scale lookup cache with SYMBOL_CACHE_SIZE
10099 cacheSize = Config_getInt("LOOKUP_CACHE_SIZE");
10100 if (cacheSize<0) cacheSize=0;
10101 if (cacheSize>9) cacheSize=9;
10102 uint lookupSize = 65536 << cacheSize;
10103 Doxygen::lookupCache = new QCache<LookupInfo>(lookupSize,lookupSize);
10104 Doxygen::lookupCache->setAutoDelete(TRUE);
10107 signal(SIGINT, stopDoxygen);
10110 uint pid = portable_pid();
10111 Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10112 Doxygen::objDBFileName.prepend(outputDirectory+"/");
10113 Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10114 Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10116 if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10118 err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10123 /**************************************************************************
10124 * Initialize some global constants
10125 **************************************************************************/
10127 g_compoundKeywordDict.insert("template class",(void *)8);
10128 g_compoundKeywordDict.insert("template struct",(void *)8);
10129 g_compoundKeywordDict.insert("class",(void *)8);
10130 g_compoundKeywordDict.insert("struct",(void *)8);
10131 g_compoundKeywordDict.insert("union",(void *)8);
10132 g_compoundKeywordDict.insert("interface",(void *)8);
10133 g_compoundKeywordDict.insert("exception",(void *)8);
10136 /**************************************************************************
10137 * Check/create output directorties *
10138 **************************************************************************/
10140 QCString htmlOutput;
10141 bool &generateHtml = Config_getBool("GENERATE_HTML");
10143 htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");
10145 QCString xmlOutput;
10146 bool &generateXml = Config_getBool("GENERATE_XML");
10148 xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");
10150 QCString latexOutput;
10151 bool &generateLatex = Config_getBool("GENERATE_LATEX");
10153 latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");
10155 QCString rtfOutput;
10156 bool &generateRtf = Config_getBool("GENERATE_RTF");
10158 rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");
10160 QCString manOutput;
10161 bool &generateMan = Config_getBool("GENERATE_MAN");
10163 manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");
10166 if (Config_getBool("HAVE_DOT"))
10168 QCString curFontPath = Config_getString("DOT_FONTPATH");
10169 if (curFontPath.isEmpty())
10171 portable_getenv("DOTFONTPATH");
10172 QCString newFontPath = ".";
10173 if (!curFontPath.isEmpty())
10175 newFontPath+=portable_pathListSeparator();
10176 newFontPath+=curFontPath;
10178 portable_setenv("DOTFONTPATH",newFontPath);
10182 portable_setenv("DOTFONTPATH",curFontPath);
10188 /**************************************************************************
10189 * Handle layout file *
10190 **************************************************************************/
10192 LayoutDocManager::instance().init();
10193 QCString &layoutFileName = Config_getString("LAYOUT_FILE");
10194 bool defaultLayoutUsed = FALSE;
10195 if (layoutFileName.isEmpty())
10197 layoutFileName = "DoxygenLayout.xml";
10198 defaultLayoutUsed = TRUE;
10201 QFile layoutFile(layoutFileName);
10202 if (layoutFile.open(IO_ReadOnly))
10204 msg("Parsing layout file %s...\n",layoutFileName.data());
10205 QTextStream t(&layoutFile);
10206 t.setEncoding(QTextStream::Latin1);
10207 LayoutDocManager::instance().parse(t,layoutFileName);
10209 else if (!defaultLayoutUsed)
10211 err("warning: failed to open layout file '%s' for reading!\n",layoutFileName.data());
10214 /**************************************************************************
10215 * Read and preprocess input *
10216 **************************************************************************/
10218 // prevent search in the output directories
10219 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10220 if (generateHtml) exclPatterns.append(htmlOutput);
10221 if (generateXml) exclPatterns.append(xmlOutput);
10222 if (generateLatex) exclPatterns.append(latexOutput);
10223 if (generateRtf) exclPatterns.append(rtfOutput);
10224 if (generateMan) exclPatterns.append(manOutput);
10227 searchInputFiles(g_inputFiles);
10229 // Notice: the order of the function calls below is very important!
10231 if (Config_getBool("GENERATE_HTML"))
10233 readFormulaRepository();
10236 /**************************************************************************
10237 * Handle Tag Files *
10238 **************************************************************************/
10240 g_storage = new FileStorage;
10241 g_storage->setName(Doxygen::entryDBFileName);
10242 if (!g_storage->open(IO_WriteOnly))
10244 err("Failed to create temporary storage file %s\n",
10245 Doxygen::entryDBFileName.data());
10248 Entry *root=new Entry;
10249 EntryNav *rootNav = new EntryNav(0,root);
10250 rootNav->setEntry(root);
10251 msg("Reading and parsing tag files\n");
10253 QStrList &tagFileList = Config_getList("TAGFILES");
10254 char *s=tagFileList.first();
10257 readTagFile(root,s);
10258 root->createNavigationIndex(rootNav,g_storage,0);
10259 s=tagFileList.next();
10262 /**************************************************************************
10263 * Parse source files *
10264 **************************************************************************/
10266 if (Config_getBool("BUILTIN_STL_SUPPORT"))
10268 addSTLClasses(rootNav);
10271 parseFiles(root,rootNav);
10272 g_storage->close();
10274 // we are done with input scanning now, so free up the buffers used by flex
10275 // (can be around 4MB)
10278 pyscanFreeScanner();
10280 if (!g_storage->open(IO_ReadOnly))
10282 err("Failed to open temporary storage file %s for reading",
10283 Doxygen::entryDBFileName.data());
10287 /**************************************************************************
10288 * Gather information *
10289 **************************************************************************/
10291 msg("Building group list...\n");
10292 buildGroupList(rootNav);
10293 organizeSubGroups(rootNav);
10295 msg("Building directory list...\n");
10296 buildDirectories();
10297 findDirDocumentation(rootNav);
10299 msg("Building namespace list...\n");
10300 buildNamespaceList(rootNav);
10301 findUsingDirectives(rootNav);
10303 msg("Building file list...\n");
10304 buildFileList(rootNav);
10305 //generateFileTree();
10307 msg("Building class list...\n");
10308 buildClassList(rootNav);
10310 msg("Associating documentation with classes...\n");
10311 buildClassDocList(rootNav);
10313 // build list of using declarations here (global list)
10314 buildListOfUsingDecls(rootNav);
10316 msg("Computing nesting relations for classes...\n");
10317 resolveClassNestingRelations();
10318 distributeClassGroupRelations();
10320 // calling buildClassList may result in cached relations that
10321 // become invalid after resolveClassNestingRelations(), that's why
10322 // we need to clear the cache here
10323 Doxygen::lookupCache->clear();
10324 // we don't need the list of using declaration anymore
10325 g_usingDeclarations.clear();
10327 msg("Building example list...\n");
10328 buildExampleList(rootNav);
10330 msg("Searching for enumerations...\n");
10331 findEnums(rootNav);
10333 // Since buildVarList calls isVarWithConstructor
10334 // and this calls getResolvedClass we need to process
10335 // typedefs first so the relations between classes via typedefs
10336 // are properly resolved. See bug 536385 for an example.
10337 msg("Searching for documented typedefs...\n");
10338 buildTypedefList(rootNav);
10340 msg("Searching for members imported via using declarations...\n");
10341 findUsingDeclImports(rootNav);
10342 // this should be after buildTypedefList in order to properly import
10344 findUsingDeclarations(rootNav);
10346 msg("Searching for included using directives...\n");
10347 findIncludedUsingDirectives();
10349 msg("Searching for documented variables...\n");
10350 buildVarList(rootNav);
10352 msg("Building member list...\n"); // using class info only !
10353 buildFunctionList(rootNav);
10355 msg("Searching for friends...\n");
10358 msg("Searching for documented defines...\n");
10359 findDefineDocumentation(rootNav);
10361 findClassEntries(rootNav);
10362 msg("Computing class inheritance relations...\n");
10363 findInheritedTemplateInstances();
10364 msg("Computing class usage relations...\n");
10365 findUsedTemplateInstances();
10366 if (Config_getBool("INLINE_SIMPLE_STRUCTS"))
10368 msg("Searching for tag less structs...\n");
10369 findTagLessClasses();
10372 msg("Flushing cached template relations that have become invalid...\n");
10373 flushCachedTemplateRelations();
10375 msg("Creating members for template instances...\n");
10376 createTemplateInstanceMembers();
10378 msg("Computing class relations...\n");
10379 computeTemplateClassRelations();
10380 flushUnresolvedRelations();
10381 if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
10383 VhdlDocGen::computeVhdlComponentRelations();
10385 computeClassRelations();
10386 g_classEntries.clear();
10388 msg("Add enum values to enums...\n");
10389 addEnumValuesToEnums(rootNav);
10390 findEnumDocumentation(rootNav);
10392 msg("Searching for member function documentation...\n");
10393 findObjCMethodDefinitions(rootNav);
10394 findMemberDocumentation(rootNav); // may introduce new members !
10396 transferRelatedFunctionDocumentation();
10397 transferFunctionDocumentation();
10399 msg("Building page list...\n");
10400 buildPageList(rootNav);
10402 msg("Search for main page...\n");
10403 findMainPage(rootNav);
10405 msg("Computing page relations...\n");
10406 computePageRelations(rootNav);
10407 checkPageRelations();
10409 msg("Determining the scope of groups...\n");
10410 findGroupScope(rootNav);
10412 msg("Sorting lists...\n");
10413 Doxygen::memberNameSDict->sort();
10414 Doxygen::functionNameSDict->sort();
10415 Doxygen::hiddenClasses->sort();
10416 Doxygen::classSDict->sort();
10418 msg("Freeing entry tree\n");
10420 g_storage->close();
10425 thisDir.remove(Doxygen::entryDBFileName);
10427 msg("Determining which enums are documented\n");
10428 findDocumentedEnumValues();
10430 msg("Computing member relations...\n");
10432 computeMemberRelations();
10434 msg("Building full member lists recursively...\n");
10435 buildCompleteMemberLists();
10437 msg("Adding members to member groups.\n");
10438 addMembersToMemberGroup();
10440 if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
10442 msg("Distributing member group documentation.\n");
10443 distributeMemberGroupDocumentation();
10446 msg("Computing member references...\n");
10447 computeMemberReferences();
10449 if (Config_getBool("INHERIT_DOCS"))
10451 msg("Inheriting documentation...\n");
10452 inheritDocumentation();
10455 // compute the shortest possible names of all files
10456 // without losing the uniqueness of the file names.
10457 msg("Generating disk names...\n");
10458 Doxygen::inputNameList->generateDiskNames();
10460 msg("Adding source references...\n");
10461 addSourceReferences();
10463 msg("Adding xrefitems...\n");
10464 addListReferences();
10465 generateXRefPages();
10467 msg("Sorting member lists...\n");
10470 if (Config_getBool("DIRECTORY_GRAPH"))
10472 msg("Computing dependencies between directories...\n");
10473 computeDirDependencies();
10476 //msg("Resolving citations...\n");
10477 //Doxygen::citeDict->resolve();
10479 msg("Generating citations page...\n");
10480 Doxygen::citeDict->generatePage();
10482 msg("Counting data structures...\n");
10483 countDataStructures();
10485 msg("Resolving user defined references...\n");
10486 resolveUserReferences();
10488 msg("Finding anchors and sections in the documentation...\n");
10489 findSectionsInDocumentation();
10491 transferFunctionReferences();
10493 msg("Combining using relations...\n");
10494 combineUsingRelations();
10496 msg("Adding members to index pages...\n");
10497 addMembersToIndex();
10499 if (Config_getBool("OPTIMIZE_OUTPUT_VHDL") &&
10500 Config_getBool("HAVE_DOT") &&
10501 Config_getEnum("DOT_IMAGE_FORMAT")=="svg")
10503 VhdlDocGen::writeOverview();
10507 void generateOutput()
10509 /**************************************************************************
10510 * Initialize output generators *
10511 **************************************************************************/
10513 //// dump all symbols
10514 if (g_dumpSymbolMap)
10520 initSearchIndexer();
10522 bool generateHtml = Config_getBool("GENERATE_HTML");
10523 bool generateLatex = Config_getBool("GENERATE_LATEX");
10524 bool generateMan = Config_getBool("GENERATE_MAN");
10525 bool generateRtf = Config_getBool("GENERATE_RTF");
10528 g_outputList = new OutputList(TRUE);
10531 g_outputList->add(new HtmlGenerator);
10532 HtmlGenerator::init();
10534 // add HTML indexers that are enabled
10535 bool generateHtmlHelp = Config_getBool("GENERATE_HTMLHELP");
10536 bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");
10537 bool generateQhp = Config_getBool("GENERATE_QHP");
10538 bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
10539 bool generateDocSet = Config_getBool("GENERATE_DOCSET");
10540 if (generateEclipseHelp) Doxygen::indexList.addIndex(new EclipseHelp);
10541 if (generateHtmlHelp) Doxygen::indexList.addIndex(new HtmlHelp);
10542 if (generateQhp) Doxygen::indexList.addIndex(new Qhp);
10543 if (generateTreeView) Doxygen::indexList.addIndex(new FTVHelp(TRUE));
10544 if (generateDocSet) Doxygen::indexList.addIndex(new DocSets);
10545 Doxygen::indexList.initialize();
10546 HtmlGenerator::writeTabData();
10548 // copy static stuff
10552 FTVHelp::generateTreeViewImages();
10556 g_outputList->add(new LatexGenerator);
10557 LatexGenerator::init();
10561 g_outputList->add(new ManGenerator);
10562 ManGenerator::init();
10566 g_outputList->add(new RTFGenerator);
10567 RTFGenerator::init();
10570 if (Config_getBool("USE_HTAGS"))
10572 Htags::useHtags = TRUE;
10573 QCString htmldir = Config_getString("HTML_OUTPUT");
10574 if (!Htags::execute(htmldir))
10575 err("error: USE_HTAGS is YES but htags(1) failed. \n");
10576 if (!Htags::loadFilemap(htmldir))
10577 err("error: htags(1) ended normally but failed to load the filemap. \n");
10580 /**************************************************************************
10581 * Generate documentation *
10582 **************************************************************************/
10585 QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
10586 if (!generateTagFile.isEmpty())
10588 tag=new QFile(generateTagFile);
10589 if (!tag->open(IO_WriteOnly))
10591 err("error: cannot open tag file %s for writing\n",
10592 generateTagFile.data()
10597 Doxygen::tagFile.setDevice(tag);
10598 Doxygen::tagFile << "<?xml version='1.0' encoding='UTF-8' standalone='yes' ?>" << endl;
10599 Doxygen::tagFile << "<tagfile>" << endl;
10602 if (generateHtml) writeDoxFont(Config_getString("HTML_OUTPUT"));
10603 if (generateLatex) writeDoxFont(Config_getString("LATEX_OUTPUT"));
10604 if (generateRtf) writeDoxFont(Config_getString("RTF_OUTPUT"));
10606 msg("Generating style sheet...\n");
10607 //printf("writing style info\n");
10608 QCString genString =
10609 theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME"));
10610 g_outputList->writeStyleInfo(0); // write first part
10611 g_outputList->disableAllBut(OutputGenerator::Latex);
10612 g_outputList->parseText(genString);
10613 g_outputList->writeStyleInfo(1); // write second part
10614 //parseText(*g_outputList,theTranslator->trWrittenBy());
10615 g_outputList->writeStyleInfo(2); // write third part
10616 g_outputList->parseText(genString);
10617 g_outputList->writeStyleInfo(3); // write fourth part
10618 //parseText(*g_outputList,theTranslator->trWrittenBy());
10619 g_outputList->writeStyleInfo(4); // write last part
10620 g_outputList->enableAll();
10622 static bool searchEngine = Config_getBool("SEARCHENGINE");
10623 static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
10625 // generate search indices (need to do this before writing other HTML
10626 // pages as these contain a drop down menu with options depending on
10627 // what categories we find in this function.
10628 if (generateHtml && searchEngine)
10630 msg("Generating search indices...\n");
10631 QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
10632 QDir searchDir(searchDirName);
10633 if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
10635 err("error: Could not create search results directory '%s' $PWD='%s'\n",
10636 searchDirName.data(),QDir::currentDirPath().data());
10639 HtmlGenerator::writeSearchData(searchDirName);
10640 if (!serverBasedSearch) // client side search index
10642 writeJavascriptSearchIndex();
10646 msg("Generating example documentation...\n");
10647 generateExampleDocs();
10649 msg("Generating file sources...\n");
10650 if (!Htags::useHtags)
10652 generateFileSources();
10655 msg("Generating file documentation...\n");
10656 generateFileDocs();
10658 msg("Generating page documentation...\n");
10659 generatePageDocs();
10661 msg("Generating group documentation...\n");
10662 generateGroupDocs();
10664 msg("Generating class documentation...\n");
10665 generateClassDocs();
10667 msg("Generating namespace index...\n");
10668 generateNamespaceDocs();
10670 if (Config_getBool("GENERATE_LEGEND"))
10672 msg("Generating graph info page...\n");
10673 writeGraphInfo(*g_outputList);
10676 msg("Generating directory documentation...\n");
10677 generateDirDocs(*g_outputList);
10679 if (Doxygen::formulaList.count()>0 && generateHtml
10680 && !Config_getBool("USE_MATHJAX"))
10682 msg("Generating bitmaps for formulas in HTML...\n");
10683 Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT"));
10686 writeMainPageTagFileData();
10688 if (g_outputList->count()>0)
10690 writeIndexHierarchy(*g_outputList);
10693 msg("finalizing index lists...\n");
10694 Doxygen::indexList.finalize();
10696 if (!generateTagFile.isEmpty())
10698 Doxygen::tagFile << "</tagfile>" << endl;
10702 if (Config_getBool("DOT_CLEANUP"))
10705 removeDoxFont(Config_getString("HTML_OUTPUT"));
10707 removeDoxFont(Config_getString("RTF_OUTPUT"));
10709 removeDoxFont(Config_getString("LATEX_OUTPUT"));
10712 if (Config_getBool("GENERATE_XML"))
10714 msg("Generating XML output...\n");
10715 Doxygen::generatingXmlOutput=TRUE;
10717 Doxygen::generatingXmlOutput=FALSE;
10719 if (Config_getBool("GENERATE_AUTOGEN_DEF"))
10721 msg("Generating AutoGen DEF output...\n");
10724 if (Config_getBool("GENERATE_PERLMOD"))
10726 msg("Generating Perl module output...\n");
10729 if (generateHtml && searchEngine && serverBasedSearch)
10731 msg("Generating search index\n");
10732 if (Doxygen::searchIndex->kind()==SearchIndexIntf::Internal) // write own search index
10734 HtmlGenerator::writeSearchPage();
10735 Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");
10737 else // write data for external search index
10739 Doxygen::searchIndex->write(Config_getString("OUTPUT_DIRECTORY")+"/searchdata.xml");
10745 msg("Combining RTF output...\n");
10746 if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
10748 err("An error occurred during post-processing the RTF files!\n");
10752 if (Config_getBool("HAVE_DOT"))
10754 DotManager::instance()->run();
10757 if (generateHtml &&
10758 Config_getBool("GENERATE_HTMLHELP") &&
10759 !Config_getString("HHC_LOCATION").isEmpty())
10761 msg("Running html help compiler...\n");
10762 QString oldDir = QDir::currentDirPath();
10763 QDir::setCurrent(Config_getString("HTML_OUTPUT"));
10764 portable_sysTimerStart();
10765 if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
10767 err("error: failed to run html help compiler on index.hhp\n");
10769 portable_sysTimerStop();
10770 QDir::setCurrent(oldDir);
10772 if ( generateHtml &&
10773 Config_getBool("GENERATE_QHP") &&
10774 !Config_getString("QHG_LOCATION").isEmpty())
10776 msg("Running qhelpgenerator...\n");
10777 QCString const qhpFileName = Qhp::getQhpFileName();
10778 QCString const qchFileName = getQchFileName();
10780 QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
10781 QString const oldDir = QDir::currentDirPath();
10782 QDir::setCurrent(Config_getString("HTML_OUTPUT"));
10783 portable_sysTimerStart();
10784 if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))
10786 err("error: failed to run qhelpgenerator on index.qhp\n");
10788 portable_sysTimerStop();
10789 QDir::setCurrent(oldDir);
10793 msg("symbol cache used %d/%d hits=%d misses=%d\n",
10794 Doxygen::symbolCache->count(),
10795 Doxygen::symbolCache->size(),
10796 Doxygen::symbolCache->hits(),
10797 Doxygen::symbolCache->misses());
10798 cacheParam = computeIdealCacheParam(Doxygen::symbolCache->misses());
10799 if (cacheParam>Config_getInt("SYMBOL_CACHE_SIZE"))
10801 msg("Note: based on cache misses the ideal setting for SYMBOL_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
10803 msg("lookup cache used %d/%d hits=%d misses=%d\n",
10804 Doxygen::lookupCache->count(),
10805 Doxygen::lookupCache->size(),
10806 Doxygen::lookupCache->hits(),
10807 Doxygen::lookupCache->misses());
10808 cacheParam = computeIdealCacheParam(Doxygen::lookupCache->misses()*2/3); // part of the cache is flushed, hence the 2/3 correction factor
10809 if (cacheParam>Config_getInt("LOOKUP_CACHE_SIZE"))
10811 msg("Note: based on cache misses the ideal setting for LOOKUP_CACHE_SIZE is %d at the cost of higher memory usage.\n",cacheParam);
10814 if (Debug::isFlagSet(Debug::Time))
10816 msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
10817 ((double)Doxygen::runningTime.elapsed())/1000.0,
10818 portable_getSysElapsedTime()
10823 msg("finished...\n");
10826 /**************************************************************************
10827 * Start cleaning up *
10828 **************************************************************************/
10832 finializeSearchIndexer();
10833 Doxygen::symbolStorage->close();
10835 thisDir.remove(Doxygen::objDBFileName);
10836 Config::deleteInstance();
10837 QTextCodec::deleteAllCodecs();
10838 delete Doxygen::symbolCache;
10839 delete Doxygen::symbolMap;
10840 delete Doxygen::symbolStorage;
10841 g_successfulRun=TRUE;