Chameleon

Chameleon Svn Source Tree

Root/branches/xZenu/src/util/doxygen/src/doxygen.cpp

Source at commit 1322 created 12 years 8 months ago.
By meklort, Add doxygen to utils folder
1/******************************************************************************
2 *
3 * Copyright (C) 1997-2011 by Dimitri van Heesch.
4 *
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.
10 *
11 * Documents produced by Doxygen are derivative works derived from the
12 * input used in their production; they are not affected by this license.
13 *
14 */
15
16#include "qtbc.h"
17#include <qfileinfo.h>
18#include <qfile.h>
19#include <qdir.h>
20#include <qdict.h>
21#include <qregexp.h>
22#include <qstrlist.h>
23#include <stdio.h>
24#include <stdlib.h>
25#include <sys/stat.h>
26#include <qtextcodec.h>
27#include <unistd.h>
28#include <errno.h>
29
30#include "version.h"
31#include "doxygen.h"
32#include "scanner.h"
33#include "entry.h"
34#include "index.h"
35#include "logos.h"
36#include "instdox.h"
37#include "message.h"
38#include "config.h"
39#include "util.h"
40#include "pre.h"
41#include "tagreader.h"
42#include "dot.h"
43#include "msc.h"
44#include "docparser.h"
45#include "dirdef.h"
46#include "outputlist.h"
47#include "declinfo.h"
48#include "htmlgen.h"
49#include "latexgen.h"
50#include "mangen.h"
51#include "language.h"
52#include "debug.h"
53#include "htmlhelp.h"
54#include "qhp.h"
55#include "indexlog.h"
56#include "ftvhelp.h"
57#include "defargs.h"
58#include "rtfgen.h"
59#include "xmlgen.h"
60#include "defgen.h"
61#include "perlmodgen.h"
62#include "reflist.h"
63#include "pagedef.h"
64#include "bufstr.h"
65#include "commentcnv.h"
66#include "cmdmapper.h"
67#include "searchindex.h"
68#include "parserintf.h"
69#include "htags.h"
70#include "pyscanner.h"
71#include "fortranscanner.h"
72#include "dbusxmlscanner.h"
73#include "code.h"
74#include "objcache.h"
75#include "store.h"
76#include "marshal.h"
77#include "portable.h"
78#include "vhdlscanner.h"
79#include "vhdldocgen.h"
80#include "eclipsehelp.h"
81
82#include "layout.h"
83
84#define RECURSE_ENTRYTREE(func,var) \
85 do { if (var->children()) { \
86 EntryNavListIterator eli(*var->children()); \
87 for (;eli.current();++eli) func(eli.current()); \
88 } } while(0)
89
90
91#if !defined(_WIN32) || defined(__CYGWIN__)
92#include <signal.h>
93#define HAS_SIGNALS
94#endif
95
96// globally accessible variables
97ClassSDict *Doxygen::classSDict = 0;
98ClassSDict *Doxygen::hiddenClasses = 0;
99NamespaceSDict *Doxygen::namespaceSDict = 0;
100MemberNameSDict *Doxygen::memberNameSDict = 0;
101MemberNameSDict *Doxygen::functionNameSDict = 0;
102FileNameList *Doxygen::inputNameList = 0; // all input files
103FileNameDict *Doxygen::inputNameDict = 0;
104GroupSDict *Doxygen::groupSDict = 0;
105FormulaList Doxygen::formulaList; // all formulas
106FormulaDict Doxygen::formulaDict(1009); // all formulas
107FormulaDict Doxygen::formulaNameDict(1009); // the label name of all formulas
108PageSDict *Doxygen::pageSDict = 0;
109PageSDict *Doxygen::exampleSDict = 0;
110SectionDict Doxygen::sectionDict(257); // all page sections
111StringDict Doxygen::aliasDict(257); // aliases
112FileNameDict *Doxygen::includeNameDict = 0; // include names
113FileNameDict *Doxygen::exampleNameDict = 0; // examples
114FileNameDict *Doxygen::imageNameDict = 0; // images
115FileNameDict *Doxygen::dotFileNameDict = 0; // dot files
116FileNameDict *Doxygen::mscFileNameDict = 0; // dot files
117StringDict Doxygen::namespaceAliasDict(257); // all namespace aliases
118StringDict Doxygen::tagDestinationDict(257); // all tag locations
119QDict<void> Doxygen::expandAsDefinedDict(257); // all macros that should be expanded
120QIntDict<MemberGroupInfo> Doxygen::memGrpInfoDict(1009); // dictionary of the member groups heading
121PageDef *Doxygen::mainPage = 0;
122bool Doxygen::insideMainPage = FALSE; // are we generating docs for the main page?
123FTextStream Doxygen::tagFile;
124NamespaceDef *Doxygen::globalScope = 0;
125QDict<RefList> *Doxygen::xrefLists = new QDict<RefList>; // dictionary of cross-referenced item lists
126bool Doxygen::parseSourcesNeeded = FALSE;
127QTime Doxygen::runningTime;
128SearchIndex * Doxygen::searchIndex=0;
129QDict<DefinitionIntf> *Doxygen::symbolMap;
130bool Doxygen::outputToWizard=FALSE;
131QDict<int> * Doxygen::htmlDirMap = 0;
132QCache<LookupInfo> Doxygen::lookupCache(50000,50000);
133DirSDict *Doxygen::directories;
134SDict<DirRelation> Doxygen::dirRelations(257);
135ParserManager *Doxygen::parserManager = 0;
136QCString Doxygen::htmlFileExtension;
137bool Doxygen::suppressDocWarnings = FALSE;
138ObjCache *Doxygen::symbolCache = 0;
139Store *Doxygen::symbolStorage;
140QCString Doxygen::objDBFileName;
141QCString Doxygen::entryDBFileName;
142bool Doxygen::gatherDefines = TRUE;
143IndexList Doxygen::indexList;
144int Doxygen::subpageNestingLevel = 0;
145bool Doxygen::userComments = FALSE;
146QCString Doxygen::spaces;
147
148// locally accessible globals
149static QDict<EntryNav> g_classEntries(1009);
150static StringList g_inputFiles;
151static QDict<void> g_compoundKeywordDict(7); // keywords recognised as compounds
152static OutputList *g_outputList = 0; // list of output generating objects
153static QDict<FileDef> g_usingDeclarations(1009); // used classes
154static FileStorage *g_storage = 0;
155static bool g_successfulRun = FALSE;
156static bool g_dumpSymbolMap = FALSE;
157static bool g_dumpConfigAsXML = FALSE;
158
159
160
161void clearAll()
162{
163 g_inputFiles.clear();
164 //g_excludeNameDict.clear();
165 //delete g_outputList; g_outputList=0;
166
167 Doxygen::classSDict->clear();
168 Doxygen::namespaceSDict->clear();
169 Doxygen::pageSDict->clear();
170 Doxygen::exampleSDict->clear();
171 Doxygen::inputNameList->clear();
172 Doxygen::formulaList.clear();
173 Doxygen::sectionDict.clear();
174 Doxygen::inputNameDict->clear();
175 Doxygen::includeNameDict->clear();
176 Doxygen::exampleNameDict->clear();
177 Doxygen::imageNameDict->clear();
178 Doxygen::dotFileNameDict->clear();
179 Doxygen::mscFileNameDict->clear();
180 Doxygen::formulaDict.clear();
181 Doxygen::formulaNameDict.clear();
182 Doxygen::tagDestinationDict.clear();
183 delete Doxygen::mainPage; Doxygen::mainPage=0;
184}
185
186void statistics()
187{
188 fprintf(stderr,"--- inputNameDict stats ----\n");
189 Doxygen::inputNameDict->statistics();
190 fprintf(stderr,"--- includeNameDict stats ----\n");
191 Doxygen::includeNameDict->statistics();
192 fprintf(stderr,"--- exampleNameDict stats ----\n");
193 Doxygen::exampleNameDict->statistics();
194 fprintf(stderr,"--- imageNameDict stats ----\n");
195 Doxygen::imageNameDict->statistics();
196 fprintf(stderr,"--- dotFileNameDict stats ----\n");
197 Doxygen::dotFileNameDict->statistics();
198 fprintf(stderr,"--- mscFileNameDict stats ----\n");
199 Doxygen::mscFileNameDict->statistics();
200 //fprintf(stderr,"--- g_excludeNameDict stats ----\n");
201 //g_excludeNameDict.statistics();
202 fprintf(stderr,"--- aliasDict stats ----\n");
203 Doxygen::aliasDict.statistics();
204 fprintf(stderr,"--- typedefDict stats ----\n");
205 fprintf(stderr,"--- namespaceAliasDict stats ----\n");
206 Doxygen::namespaceAliasDict.statistics();
207 fprintf(stderr,"--- formulaDict stats ----\n");
208 Doxygen::formulaDict.statistics();
209 fprintf(stderr,"--- formulaNameDict stats ----\n");
210 Doxygen::formulaNameDict.statistics();
211 fprintf(stderr,"--- tagDestinationDict stats ----\n");
212 Doxygen::tagDestinationDict.statistics();
213 fprintf(stderr,"--- g_compoundKeywordDict stats ----\n");
214 g_compoundKeywordDict.statistics();
215 fprintf(stderr,"--- expandAsDefinedDict stats ----\n");
216 Doxygen::expandAsDefinedDict.statistics();
217 fprintf(stderr,"--- memGrpInfoDict stats ----\n");
218 Doxygen::memGrpInfoDict.statistics();
219}
220
221
222
223static void addMemberDocs(EntryNav *rootNav,MemberDef *md, const char *funcDecl,
224 ArgumentList *al,bool over_load,NamespaceSDict *nl=0);
225static void findMember(EntryNav *rootNav,
226 QCString funcDecl,
227 bool overloaded,
228 bool isFunc
229 );
230
231
232struct STLInfo
233{
234 const char *className;
235 const char *baseClass1;
236 const char *baseClass2;
237 const char *templType1;
238 const char *templName1;
239 const char *templType2;
240 const char *templName2;
241 bool virtualInheritance;
242 bool iterators;
243};
244
245static STLInfo g_stlinfo[] =
246{
247 // className baseClass1 baseClass2 templType1 templName1 templType2 templName2 virtInheritance // iterators
248 { "allocator", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
249 { "auto_ptr", 0, 0, "T", "ptr", 0, 0, FALSE, FALSE },
250 { "ios_base", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
251 { "basic_ios", "ios_base", 0, "Char", 0, 0, 0, FALSE, FALSE },
252 { "basic_istream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
253 { "basic_ostream", "basic_ios<Char>", 0, "Char", 0, 0, 0, TRUE, FALSE },
254 { "basic_iostream", "basic_istream<Char>", "basic_ostream<Char>", "Char", 0, 0, 0, FALSE, FALSE },
255 { "basic_ifstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
256 { "basic_ofstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
257 { "basic_fstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
258 { "basic_istringstream", "basic_istream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
259 { "basic_ostringstream", "basic_ostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
260 { "basic_stringstream", "basic_iostream<Char>", 0, "Char", 0, 0, 0, FALSE, FALSE },
261 { "ios", "basic_ios<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
262 { "wios", "basic_ios<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
263 { "istream", "basic_istream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
264 { "wistream", "basic_istream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
265 { "ostream", "basic_ostream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
266 { "wostream", "basic_ostream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
267 { "ifstream", "basic_ifstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
268 { "wifstream", "basic_ifstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
269 { "ofstream", "basic_ofstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
270 { "wofstream", "basic_ofstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
271 { "fstream", "basic_fstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
272 { "wfstream", "basic_fstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
273 { "istringstream", "basic_istringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
274 { "wistringstream", "basic_istringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
275 { "ostringstream", "basic_ostringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
276 { "wostringstream", "basic_ostringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
277 { "stringstream", "basic_stringstream<char>", 0, 0, 0, 0, 0, FALSE, FALSE },
278 { "wstringstream", "basic_stringstream<wchar_t>", 0, 0, 0, 0, 0, FALSE, FALSE },
279 { "basic_string", 0, 0, "Char", 0, 0, 0, FALSE, TRUE },
280 { "string", "basic_string<char>", 0, 0, 0, 0, 0, FALSE, TRUE },
281 { "wstring", "basic_string<wchar_t>", 0, 0, 0, 0, 0, FALSE, TRUE },
282 { "complex", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
283 { "bitset", 0, 0, "Bits", 0, 0, 0, FALSE, FALSE },
284 { "deque", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
285 { "list", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
286 { "map", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
287 { "multimap", 0, 0, "K", "keys", "T", "elements", FALSE, TRUE },
288 { "set", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
289 { "multiset", 0, 0, "K", "keys", 0, 0, FALSE, TRUE },
290 { "vector", 0, 0, "T", "elements", 0, 0, FALSE, TRUE },
291 { "queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
292 { "priority_queue", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
293 { "stack", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
294 { "valarray", 0, 0, "T", "elements", 0, 0, FALSE, FALSE },
295 { "exception", 0, 0, 0, 0, 0, 0, FALSE, FALSE },
296 { "bad_alloc", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
297 { "bad_cast", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
298 { "bad_typeid", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
299 { "logic_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
300 { "ios_base::failure", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
301 { "runtime_error", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
302 { "bad_exception", "exception", 0, 0, 0, 0, 0, FALSE, FALSE },
303 { "domain_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
304 { "invalid_argument", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
305 { "length_error", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
306 { "out_of_range", "logic_error", 0, 0, 0, 0, 0, FALSE, FALSE },
307 { "range_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
308 { "overflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
309 { "underflow_error", "runtime_error", 0, 0, 0, 0, 0, FALSE, FALSE },
310 { 0, 0, 0, 0, 0, 0, 0, FALSE, FALSE }
311};
312
313static void addSTLMember(EntryNav *rootNav,const char *type,const char *name)
314{
315 Entry *memEntry = new Entry;
316 memEntry->name = name;
317 memEntry->type = type;
318 memEntry->protection = Private;
319 memEntry->section = Entry::VARIABLE_SEC;
320 memEntry->brief = "STL member";
321 memEntry->hidden = FALSE;
322 memEntry->artificial = TRUE;
323 //memEntry->parent = root;
324 //root->addSubEntry(memEntry);
325 EntryNav *memEntryNav = new EntryNav(rootNav,memEntry);
326 memEntryNav->setEntry(memEntry);
327 rootNav->addChild(memEntryNav);
328}
329
330static void addSTLIterator(EntryNav *classEntryNav,const char *name)
331{
332 Entry *iteratorClassEntry = new Entry;
333 iteratorClassEntry->fileName = "[STL]";
334 iteratorClassEntry->startLine = 1;
335 iteratorClassEntry->name = name;
336 iteratorClassEntry->section = Entry::CLASS_SEC;
337 iteratorClassEntry->brief = "STL iterator class";
338 iteratorClassEntry->hidden = FALSE;
339 iteratorClassEntry->artificial= TRUE;
340 EntryNav *iteratorClassEntryNav = new EntryNav(classEntryNav,iteratorClassEntry);
341 iteratorClassEntryNav->setEntry(iteratorClassEntry);
342 classEntryNav->addChild(iteratorClassEntryNav);
343}
344
345
346static void addSTLClasses(EntryNav *rootNav)
347{
348 Entry *namespaceEntry = new Entry;
349 namespaceEntry->fileName = "[STL]";
350 namespaceEntry->startLine = 1;
351 //namespaceEntry->parent = rootNav->entry();
352 namespaceEntry->name = "std";
353 namespaceEntry->section = Entry::NAMESPACE_SEC;
354 namespaceEntry->brief = "STL namespace";
355 namespaceEntry->hidden = FALSE;
356 namespaceEntry->artificial= TRUE;
357 //root->addSubEntry(namespaceEntry);
358 EntryNav *namespaceEntryNav = new EntryNav(rootNav,namespaceEntry);
359 namespaceEntryNav->setEntry(namespaceEntry);
360 rootNav->addChild(namespaceEntryNav);
361
362 STLInfo *info = g_stlinfo;
363 while (info->className)
364 {
365 //printf("Adding STL class %s\n",info->className);
366 QCString fullName = info->className;
367 fullName.prepend("std::");
368
369 // add fake Entry for the class
370 Entry *classEntry = new Entry;
371 classEntry->fileName = "[STL]";
372 classEntry->startLine = 1;
373 classEntry->name = fullName;
374 //classEntry->parent = namespaceEntry;
375 classEntry->section = Entry::CLASS_SEC;
376 classEntry->brief = "STL class";
377 classEntry->hidden = FALSE;
378 classEntry->artificial= TRUE;
379 //namespaceEntry->addSubEntry(classEntry);
380 EntryNav *classEntryNav = new EntryNav(namespaceEntryNav,classEntry);
381 classEntryNav->setEntry(classEntry);
382 namespaceEntryNav->addChild(classEntryNav);
383
384 // add template arguments to class
385 if (info->templType1)
386 {
387 ArgumentList *al = new ArgumentList;
388 Argument *a=new Argument;
389 a->type="typename";
390 a->name=info->templType1;
391 al->append(a);
392 if (info->templType2) // another template argument
393 {
394 a=new Argument;
395 a->type="typename";
396 a->name=info->templType2;
397 al->append(a);
398 }
399 classEntry->tArgLists = new QList<ArgumentList>;
400 classEntry->tArgLists->setAutoDelete(TRUE);
401 classEntry->tArgLists->append(al);
402 }
403 // add member variables
404 if (info->templName1)
405 {
406 addSTLMember(classEntryNav,info->templType1,info->templName1);
407 }
408 if (info->templName2)
409 {
410 addSTLMember(classEntryNav,info->templType2,info->templName2);
411 }
412 if (info->baseClass1)
413 {
414 classEntry->extends->append(new BaseInfo(info->baseClass1,Public,info->virtualInheritance?Virtual:Normal));
415 }
416 if (info->baseClass2)
417 {
418 classEntry->extends->append(new BaseInfo(info->baseClass2,Public,info->virtualInheritance?Virtual:Normal));
419 }
420 if (info->iterators)
421 {
422 // add iterator class
423 addSTLIterator(classEntryNav,fullName+"::iterator");
424 addSTLIterator(classEntryNav,fullName+"::const_iterator");
425 addSTLIterator(classEntryNav,fullName+"::reverse_iterator");
426 addSTLIterator(classEntryNav,fullName+"::const_reverse_iterator");
427 }
428 info++;
429 }
430}
431
432//----------------------------------------------------------------------------
433
434static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
435 FileDef *fileScope=0);
436
437static void addPageToContext(PageDef *pd,EntryNav *rootNav)
438{
439 if (rootNav->parent()) // add the page to it's scope
440 {
441 QCString scope = rootNav->parent()->name();
442 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
443 {
444 scope=substitute(scope,".","::");
445 }
446 scope = stripAnonymousNamespaceScope(scope);
447 scope+="::"+pd->name();
448 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
449 if (d)
450 {
451 pd->setPageScope(d);
452 }
453 }
454}
455
456static void addRelatedPage(EntryNav *rootNav)
457{
458 Entry *root = rootNav->entry();
459 GroupDef *gd=0;
460 QListIterator<Grouping> gli(*root->groups);
461 Grouping *g;
462 for (;(g=gli.current());++gli)
463 {
464 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname))) break;
465 }
466 //printf("---> addRelatedPage() %s gd=%p\n",root->name.data(),gd);
467 QCString doc;
468 if (root->brief.isEmpty())
469 {
470 doc=root->doc+root->inbodyDocs;
471 }
472 else
473 {
474 doc=root->brief+"\n\n"+root->doc+root->inbodyDocs;
475 }
476 PageDef *pd = addRelatedPage(root->name,root->args,doc,root->anchors,
477 root->fileName,root->startLine,
478 root->sli,
479 gd,rootNav->tagInfo()
480 );
481 if (pd)
482 {
483 pd->addSectionsToDefinition(root->anchors);
484 addPageToContext(pd,rootNav);
485 }
486}
487
488static void buildGroupListFiltered(EntryNav *rootNav,bool additional, bool includeExternal)
489{
490 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
491 ((!includeExternal && rootNav->tagInfo()==0) ||
492 ( includeExternal && rootNav->tagInfo()!=0))
493 )
494 {
495 rootNav->loadEntry(g_storage);
496 Entry *root = rootNav->entry();
497
498 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
499 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
500 {
501 GroupDef *gd = Doxygen::groupSDict->find(root->name);
502 //printf("Processing group '%s': add=%d ext=%d gd=%p\n",
503 // root->type.data(),additional,includeExternal,gd);
504
505 if (gd)
506 {
507 if ( !gd->hasGroupTitle() )
508 {
509 gd->setGroupTitle( root->type );
510 }
511 else if ( root->type.length() > 0 && root->name != root->type && gd->groupTitle() != root->type )
512 {
513 warn( root->fileName,root->startLine,
514 "group %s: ignoring title \"%s\" that does not match old title \"%s\"\n",
515 qPrint(root->name), qPrint(root->type), qPrint(gd->groupTitle()) );
516 }
517 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
518 gd->setDocumentation( root->doc, root->docFile, root->docLine );
519 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
520 gd->addSectionsToDefinition(root->anchors);
521 gd->setRefItems(root->sli);
522 }
523 else
524 {
525 if (rootNav->tagInfo())
526 {
527 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type,rootNav->tagInfo()->fileName);
528 gd->setReference(rootNav->tagInfo()->tagName);
529 }
530 else
531 {
532 gd = new GroupDef(root->fileName,root->startLine,root->name,root->type);
533 }
534 gd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
535 gd->setDocumentation(root->doc,root->docFile,root->docLine);
536 gd->setInbodyDocumentation( root->inbodyDocs, root->inbodyFile, root->inbodyLine );
537 gd->addSectionsToDefinition(root->anchors);
538 Doxygen::groupSDict->append(root->name,gd);
539 gd->setRefItems(root->sli);
540 }
541 }
542
543 rootNav->releaseEntry();
544 }
545 if (rootNav->children())
546 {
547 EntryNavListIterator eli(*rootNav->children());
548 EntryNav *e;
549 for (;(e=eli.current());++eli)
550 {
551 buildGroupListFiltered(e,additional,includeExternal);
552 }
553 }
554}
555
556static void buildGroupList(EntryNav *rootNav)
557{
558 // --- first process only local groups
559 // first process the @defgroups blocks
560 buildGroupListFiltered(rootNav,FALSE,FALSE);
561 // then process the @addtogroup, @weakgroup blocks
562 buildGroupListFiltered(rootNav,TRUE,FALSE);
563
564 // --- then also process external groups
565 // first process the @defgroups blocks
566 buildGroupListFiltered(rootNav,FALSE,TRUE);
567 // then process the @addtogroup, @weakgroup blocks
568 buildGroupListFiltered(rootNav,TRUE,TRUE);
569}
570
571static void findGroupScope(EntryNav *rootNav)
572{
573 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty() &&
574 rootNav->parent() && !rootNav->parent()->name().isEmpty())
575 {
576 GroupDef *gd;
577 if ((gd=Doxygen::groupSDict->find(rootNav->name())))
578 {
579 QCString scope = rootNav->parent()->name();
580 if (rootNav->parent()->section()==Entry::PACKAGEDOC_SEC)
581 {
582 scope=substitute(scope,".","::");
583 }
584 scope = stripAnonymousNamespaceScope(scope);
585 scope+="::"+gd->name();
586 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,scope);
587 if (d)
588 {
589 gd->setGroupScope(d);
590 }
591 }
592 }
593 RECURSE_ENTRYTREE(findGroupScope,rootNav);
594}
595
596static void organizeSubGroupsFiltered(EntryNav *rootNav,bool additional)
597{
598 if (rootNav->section()==Entry::GROUPDOC_SEC && !rootNav->name().isEmpty())
599 {
600 rootNav->loadEntry(g_storage);
601 Entry *root = rootNav->entry();
602
603 if ((root->groupDocType==Entry::GROUPDOC_NORMAL && !additional) ||
604 (root->groupDocType!=Entry::GROUPDOC_NORMAL && additional))
605 {
606 GroupDef *gd;
607 if ((gd=Doxygen::groupSDict->find(root->name)))
608 {
609 //printf("adding %s to group %s\n",root->name.data(),gd->name().data());
610 addGroupToGroups(root,gd);
611 }
612 }
613
614 rootNav->releaseEntry();
615 }
616 if (rootNav->children())
617 {
618 EntryNavListIterator eli(*rootNav->children());
619 EntryNav *e;
620 for (;(e=eli.current());++eli)
621 {
622 organizeSubGroupsFiltered(e,additional);
623 }
624 }
625}
626
627static void organizeSubGroups(EntryNav *rootNav)
628{
629 //printf("Defining groups\n");
630 // first process the @defgroups blocks
631 organizeSubGroupsFiltered(rootNav,FALSE);
632 //printf("Additional groups\n");
633 // then process the @addtogroup, @weakgroup blocks
634 organizeSubGroupsFiltered(rootNav,TRUE);
635}
636
637//----------------------------------------------------------------------
638
639static void buildFileList(EntryNav *rootNav)
640{
641 if (((rootNav->section()==Entry::FILEDOC_SEC) ||
642 ((rootNav->section() & Entry::FILE_MASK) && Config_getBool("EXTRACT_ALL"))) &&
643 !rootNav->name().isEmpty() && !rootNav->tagInfo() // skip any file coming from tag files
644 )
645 {
646 rootNav->loadEntry(g_storage);
647 Entry *root = rootNav->entry();
648
649 bool ambig;
650 FileDef *fd=findFileDef(Doxygen::inputNameDict,root->name,ambig);
651 //printf("**************** root->name=%s fd=%p\n",root->name.data(),fd);
652 if (fd && !ambig)
653 {
654#if 0
655 if ((!root->doc.isEmpty() && !fd->documentation().isEmpty()) ||
656 (!root->brief.isEmpty() && !fd->briefDescription().isEmpty()))
657 {
658 warn(
659 root->fileName,root->startLine,
660 "warning: file %s already documented. "
661 "Skipping documentation.",
662 root->name.data()
663 );
664 }
665 else
666#endif
667 {
668 //printf("Adding documentation!\n");
669 // using FALSE in setDocumentation is small hack to make sure a file
670 // is documented even if a \file command is used without further
671 // documentation
672 fd->setDocumentation(root->doc,root->docFile,root->docLine,FALSE);
673 fd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
674 fd->addSectionsToDefinition(root->anchors);
675 fd->setRefItems(root->sli);
676 QListIterator<Grouping> gli(*root->groups);
677 Grouping *g;
678 for (;(g=gli.current());++gli)
679 {
680 GroupDef *gd=0;
681 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
682 {
683 gd->addFile(fd);
684 fd->makePartOfGroup(gd);
685 //printf("File %s: in group %s\n",fd->name().data(),s->data());
686 }
687 }
688 }
689 }
690 else
691 {
692 const char *fn = root->fileName.data();
693 QCString text;
694 text.sprintf("warning: the name `%s' supplied as "
695 "the second argument in the \\file statement ",
696 qPrint(root->name)
697 );
698 if (ambig) // name is ambiguous
699 {
700 text+="matches the following input files:\n";
701 text+=showFileDefMatches(Doxygen::inputNameDict,root->name);
702 text+="Please use a more specific name by "
703 "including a (larger) part of the path!";
704 }
705 else // name is not an input file
706 {
707 text+="is not an input file";
708 }
709 warn(fn,root->startLine,text);
710 }
711
712 rootNav->releaseEntry();
713 }
714 RECURSE_ENTRYTREE(buildFileList,rootNav);
715}
716
717static void addIncludeFile(ClassDef *cd,FileDef *ifd,Entry *root)
718{
719 if (
720 (!root->doc.stripWhiteSpace().isEmpty() ||
721 !root->brief.stripWhiteSpace().isEmpty() ||
722 Config_getBool("EXTRACT_ALL")
723 ) && root->protection!=Private
724 )
725 {
726 //printf(">>>>>> includeFile=%s\n",root->includeFile.data());
727
728 bool local=Config_getBool("FORCE_LOCAL_INCLUDES");
729 QCString includeFile = root->includeFile;
730 if (!includeFile.isEmpty() && includeFile.at(0)=='"')
731 {
732 local = TRUE;
733 includeFile=includeFile.mid(1,includeFile.length()-2);
734 }
735 else if (!includeFile.isEmpty() && includeFile.at(0)=='<')
736 {
737 local = FALSE;
738 includeFile=includeFile.mid(1,includeFile.length()-2);
739 }
740
741 bool ambig;
742 FileDef *fd=0;
743 // see if we need to include a verbatim copy of the header file
744 //printf("root->includeFile=%s\n",root->includeFile.data());
745 if (!includeFile.isEmpty() &&
746 (fd=findFileDef(Doxygen::inputNameDict,includeFile,ambig))==0
747 )
748 { // explicit request
749 QCString text;
750 text.sprintf("warning: the name `%s' supplied as "
751 "the argument of the \\class, \\struct, \\union, or \\include command ",
752 qPrint(includeFile)
753 );
754 if (ambig) // name is ambiguous
755 {
756 text+="matches the following input files:\n";
757 text+=showFileDefMatches(Doxygen::inputNameDict,root->includeFile);
758 text+="Please use a more specific name by "
759 "including a (larger) part of the path!";
760 }
761 else // name is not an input file
762 {
763 text+="is not an input file";
764 }
765 warn(root->fileName,root->startLine,text);
766 }
767 else if (includeFile.isEmpty() && ifd &&
768 // see if the file extension makes sense
769 guessSection(ifd->name())==Entry::HEADER_SEC)
770 { // implicit assumption
771 fd=ifd;
772 }
773
774 // if a file is found, we mark it as a source file.
775 if (fd)
776 {
777 QCString iName = !root->includeName.isEmpty() ?
778 root->includeName : includeFile;
779 if (!iName.isEmpty()) // user specified include file
780 {
781 if (iName.at(0)=='<') local=FALSE; // explicit override
782 if (iName.at(0)=='"' || iName.at(0)=='<')
783 {
784 iName=iName.mid(1,iName.length()-2); // strip quotes or brackets
785 }
786 if (iName.isEmpty())
787 {
788 iName=fd->name();
789 }
790 }
791 else if (!Config_getList("STRIP_FROM_INC_PATH").isEmpty())
792 {
793 iName=stripFromIncludePath(fd->absFilePath());
794 }
795 else // use name of the file containing the class definition
796 {
797 iName=fd->name();
798 }
799 if (fd->generateSourceFile()) // generate code for header
800 {
801 cd->setIncludeFile(fd,iName,local,!root->includeName.isEmpty());
802 }
803 else // put #include in the class documentation without link
804 {
805 cd->setIncludeFile(0,iName,local,TRUE);
806 }
807 }
808 }
809}
810
811#if 0
812static bool addNamespace(Entry *root,ClassDef *cd)
813{
814 // see if this class is defined inside a namespace
815 if (root->section & Entry::COMPOUND_MASK)
816 {
817 Entry *e = root->parent;
818 while (e)
819 {
820 if (e->section==Entry::NAMESPACE_SEC)
821 {
822 NamespaceDef *nd=0;
823 QCString nsName = stripAnonymousNamespaceScope(e->name);
824 //printf("addNameSpace() trying: %s\n",nsName.data());
825 if (!nsName.isEmpty() && nsName.at(0)!='@' &&
826 (nd=getResolvedNamespace(nsName))
827 )
828 {
829 cd->setNamespace(nd);
830 cd->setOuterScope(nd);
831 nd->insertClass(cd);
832 return TRUE;
833 }
834 }
835 e=e->parent;
836 }
837 }
838 return FALSE;
839}
840#endif
841
842#if 0
843static Definition *findScope(Entry *root,int level=0)
844{
845 if (root==0) return 0;
846 //printf("start findScope name=%s\n",root->name.data());
847 Definition *result=0;
848 if (root->section&Entry::SCOPE_MASK)
849 {
850 result = findScope(root->parent,level+1); // traverse to the root of the tree
851 if (result)
852 {
853 //printf("Found %s inside %s at level %d\n",root->name.data(),result->name().data(),level);
854 // TODO: look at template arguments
855 result = result->findInnerCompound(root->name);
856 }
857 else // reached the global scope
858 {
859 // TODO: look at template arguments
860 result = Doxygen::globalScope->findInnerCompound(root->name);
861 //printf("Found in globalScope %s at level %d\n",result->name().data(),level);
862 }
863 }
864 //printf("end findScope(%s,%d)=%s\n",root->name.data(),
865 // level,result==0 ? "<none>" : result->name().data());
866 return result;
867}
868#endif
869
870/*! returns the Definition object belonging to the first \a level levels of
871 * full qualified name \a name. Creates an artificial scope if the scope is
872 * not found and set the parent/child scope relation if the scope is found.
873 */
874static Definition *buildScopeFromQualifiedName(const QCString name,int level)
875{
876 int i=0;
877 int p=0,l;
878 Definition *prevScope=Doxygen::globalScope;
879 QCString fullScope;
880 while (i<level)
881 {
882 int idx=getScopeFragment(name,p,&l);
883 QCString nsName = name.mid(idx,l);
884 if (nsName.isEmpty()) return prevScope;
885 if (!fullScope.isEmpty()) fullScope+="::";
886 fullScope+=nsName;
887 NamespaceDef *nd=Doxygen::namespaceSDict->find(fullScope);
888 Definition *innerScope = nd;
889 ClassDef *cd=0;
890 if (nd==0) cd = getClass(fullScope);
891 if (nd==0 && cd) // scope is a class
892 {
893 innerScope = cd;
894 }
895 else if (nd==0 && cd==0) // scope is not known!
896 {
897 // introduce bogus namespace
898 //printf("++ adding dummy namespace %s to %s\n",nsName.data(),prevScope->name().data());
899 nd=new NamespaceDef(
900 "[generated]",1,fullScope);
901
902 // add namespace to the list
903 Doxygen::namespaceSDict->inSort(fullScope,nd);
904 innerScope = nd;
905 }
906 else // scope is a namespace
907 {
908 }
909 // make the parent/child scope relation
910 prevScope->addInnerCompound(innerScope);
911 innerScope->setOuterScope(prevScope);
912 // proceed to the next scope fragment
913 p=idx+l+2;
914 prevScope=innerScope;
915 i++;
916 }
917 return prevScope;
918}
919
920static Definition *findScopeFromQualifiedName(Definition *startScope,const QCString &n,
921 FileDef *fileScope)
922{
923 //printf("<findScopeFromQualifiedName(%s,%s)\n",startScope ? startScope->name().data() : 0, n.data());
924 Definition *resultScope=startScope;
925 if (resultScope==0) resultScope=Doxygen::globalScope;
926 QCString scope=stripTemplateSpecifiersFromScope(n,FALSE);
927 int l1=0,i1;
928 i1=getScopeFragment(scope,0,&l1);
929 if (i1==-1)
930 {
931 //printf(">no fragments!\n");
932 return resultScope;
933 }
934 int p=i1+l1,l2=0,i2;
935 while ((i2=getScopeFragment(scope,p,&l2))!=-1)
936 {
937 QCString nestedNameSpecifier = scope.mid(i1,l1);
938 Definition *orgScope = resultScope;
939 //printf(" nestedNameSpecifier=%s\n",nestedNameSpecifier.data());
940 resultScope = resultScope->findInnerCompound(nestedNameSpecifier);
941 //printf(" resultScope=%p\n",resultScope);
942 if (resultScope==0)
943 {
944 NamespaceSDict *usedNamespaces;
945 if (orgScope==Doxygen::globalScope && fileScope &&
946 (usedNamespaces = fileScope->getUsedNamespaces()))
947 // also search for used namespaces
948 {
949 NamespaceSDict::Iterator ni(*usedNamespaces);
950 NamespaceDef *nd;
951 for (ni.toFirst();((nd=ni.current()) && resultScope==0);++ni)
952 {
953 // restart search within the used namespace
954 resultScope = findScopeFromQualifiedName(nd,n,fileScope);
955 }
956 if (resultScope)
957 {
958 // for a nested class A::I in used namespace N, we get
959 // N::A::I while looking for A, so we should compare
960 // resultScope->name() against scope.left(i2+l2)
961 //printf(" -> result=%s scope=%s\n",resultScope->name().data(),scope.data());
962 if (rightScopeMatch(resultScope->name(),scope.left(i2+l2)))
963 {
964 break;
965 }
966 goto nextFragment;
967 }
968 }
969
970 // also search for used classes. Complication: we haven't been able
971 // to put them in the right scope yet, because we are still resolving
972 // the scope relations!
973 // Therefore loop through all used classes and see if there is a right
974 // scope match between the used class and nestedNameSpecifier.
975 QDictIterator<FileDef> ui(g_usingDeclarations);
976 FileDef *usedFd;
977 for (ui.toFirst();(usedFd=ui.current());++ui)
978 {
979 //printf("Checking using class %s\n",ui.currentKey());
980 if (rightScopeMatch(ui.currentKey(),nestedNameSpecifier))
981 {
982 // ui.currentKey() is the fully qualified name of nestedNameSpecifier
983 // so use this instead.
984 QCString fqn = QCString(ui.currentKey())+
985 scope.right(scope.length()-p);
986 resultScope = buildScopeFromQualifiedName(fqn,fqn.contains("::"));
987 //printf("Creating scope from fqn=%s result %p\n",fqn.data(),resultScope);
988 if (resultScope)
989 {
990 //printf("> Match! resultScope=%s\n",resultScope->name().data());
991 return resultScope;
992 }
993 }
994 }
995
996 //printf("> name %s not found in scope %s\n",nestedNameSpecifier.data(),orgScope->name().data());
997 return 0;
998 }
999 nextFragment:
1000 i1=i2;
1001 l1=l2;
1002 p=i2+l2;
1003 }
1004 //printf(">findScopeFromQualifiedName scope %s\n",resultScope->name().data());
1005 return resultScope;
1006}
1007
1008ArgumentList *getTemplateArgumentsFromName(
1009 const QCString &name,
1010 const QList<ArgumentList> *tArgLists)
1011{
1012 if (tArgLists==0) return 0;
1013
1014 QListIterator<ArgumentList> ali(*tArgLists);
1015 // for each scope fragment, check if it is a template and advance through
1016 // the list if so.
1017 int i,p=0;
1018 while ((i=name.find("::",p))!=-1)
1019 {
1020 NamespaceDef *nd = Doxygen::namespaceSDict->find(name.left(i));
1021 if (nd==0)
1022 {
1023 ClassDef *cd = getClass(name.left(i));
1024 if (cd)
1025 {
1026 if (cd->templateArguments())
1027 {
1028 ++ali;
1029 }
1030 }
1031 }
1032 p=i+2;
1033 }
1034 return ali.current();
1035}
1036
1037static ClassDef::CompoundType convertToCompoundType(int section,int specifier)
1038{
1039 ClassDef::CompoundType sec=ClassDef::Class;
1040 if (specifier&Entry::Struct)
1041 sec=ClassDef::Struct;
1042 else if (specifier&Entry::Union)
1043 sec=ClassDef::Union;
1044 else if (specifier&Entry::Interface)
1045 sec=ClassDef::Interface;
1046 else if (specifier&Entry::Protocol)
1047 sec=ClassDef::Protocol;
1048 else if (specifier&Entry::Category)
1049 sec=ClassDef::Category;
1050 else if (specifier&Entry::Exception)
1051 sec=ClassDef::Exception;
1052
1053 switch(section)
1054 {
1055 //case Entry::UNION_SEC:
1056 case Entry::UNIONDOC_SEC:
1057 sec=ClassDef::Union;
1058 break;
1059 //case Entry::STRUCT_SEC:
1060 case Entry::STRUCTDOC_SEC:
1061 sec=ClassDef::Struct;
1062 break;
1063 //case Entry::INTERFACE_SEC:
1064 case Entry::INTERFACEDOC_SEC:
1065 sec=ClassDef::Interface;
1066 break;
1067 //case Entry::PROTOCOL_SEC:
1068 case Entry::PROTOCOLDOC_SEC:
1069 sec=ClassDef::Protocol;
1070 break;
1071 //case Entry::CATEGORY_SEC:
1072 case Entry::CATEGORYDOC_SEC:
1073 sec=ClassDef::Category;
1074 break;
1075 //case Entry::EXCEPTION_SEC:
1076 case Entry::EXCEPTIONDOC_SEC:
1077 sec=ClassDef::Exception;
1078 break;
1079 }
1080 return sec;
1081}
1082
1083
1084static void addClassToContext(EntryNav *rootNav)
1085{
1086 //printf("Loading entry for rootNav=%p name=%s\n",rootNav,rootNav->name().data());
1087 rootNav->loadEntry(g_storage);
1088 Entry *root = rootNav->entry();
1089
1090 //NamespaceDef *nd = 0;
1091 FileDef *fd = rootNav->fileDef();
1092
1093 QCString scName;
1094 if (rootNav->parent()->section()&Entry::SCOPE_MASK)
1095 {
1096 scName=rootNav->parent()->name();
1097 }
1098 // name without parent's scope
1099 QCString fullName = root->name;
1100
1101 // strip off any template parameters (but not those for specializations)
1102 fullName=stripTemplateSpecifiersFromScope(fullName);
1103
1104 // name with scope (if not present already)
1105 QCString qualifiedName = fullName;
1106 if (!scName.isEmpty() && !leftScopeMatch(fullName,scName))
1107 {
1108 qualifiedName.prepend(scName+"::");
1109 }
1110
1111 // see if we already found the class before
1112 ClassDef *cd = getClass(qualifiedName);
1113
1114 Debug::print(Debug::Classes,0, " Found class with name %s (qualifiedName=%s -> cd=%p)\n",
1115 cd ? cd->name().data() : root->name.data(), qualifiedName.data(),cd);
1116
1117 if (cd)
1118 {
1119 fullName=cd->name();
1120 Debug::print(Debug::Classes,0," Existing class %s!\n",cd->name().data());
1121 //if (cd->templateArguments()==0)
1122 //{
1123 // //printf("existing ClassDef tempArgList=%p specScope=%s\n",root->tArgList,root->scopeSpec.data());
1124 // cd->setTemplateArguments(tArgList);
1125 //}
1126
1127 cd->setDocumentation(root->doc,root->docFile,root->docLine);
1128 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1129
1130 if (root->bodyLine!=-1 && cd->getStartBodyLine()==-1)
1131 {
1132 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1133 cd->setBodyDef(fd);
1134 }
1135 //cd->setName(fullName); // change name to match docs
1136
1137 if (cd->templateArguments()==0)
1138 {
1139 // this happens if a template class declared with @class is found
1140 // before the actual definition.
1141 ArgumentList *tArgList =
1142 getTemplateArgumentsFromName(cd->name(),root->tArgLists);
1143 cd->setTemplateArguments(tArgList);
1144 }
1145
1146 cd->setCompoundType(convertToCompoundType(root->section,root->spec));
1147 }
1148 else // new class
1149 {
1150 ClassDef::CompoundType sec = convertToCompoundType(root->section,root->spec);
1151
1152 QCString className;
1153 QCString namespaceName;
1154 extractNamespaceName(fullName,className,namespaceName);
1155
1156 //printf("New class: fullname %s namespace `%s' name=`%s' brief=`%s' docs=`%s'\n",
1157 // fullName.data(),namespaceName.data(),className.data(),root->brief.data(),root->doc.data());
1158
1159 QCString tagName;
1160 QCString refFileName;
1161 if (rootNav->tagInfo())
1162 {
1163 tagName = rootNav->tagInfo()->tagName;
1164 refFileName = rootNav->tagInfo()->fileName;
1165 }
1166 cd=new ClassDef(root->fileName,root->startLine,fullName,sec,
1167 tagName,refFileName);
1168 Debug::print(Debug::Classes,0," New class `%s' (sec=0x%08x)! #tArgLists=%d\n",
1169 fullName.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
1170 cd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1171 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1172 cd->setLanguage(root->lang);
1173 cd->setHidden(root->hidden);
1174 cd->setArtificial(root->artificial);
1175 cd->setTypeConstraints(root->typeConstr);
1176 //printf("new ClassDef %s tempArgList=%p specScope=%s\n",fullName.data(),root->tArgList,root->scopeSpec.data());
1177
1178 ArgumentList *tArgList =
1179 getTemplateArgumentsFromName(fullName,root->tArgLists);
1180 //printf("class %s template args=%s\n",fullName.data(),
1181 // tArgList ? tempArgListToString(tArgList).data() : "<none>");
1182 cd->setTemplateArguments(tArgList);
1183 cd->setProtection(root->protection);
1184 cd->setIsStatic(root->stat);
1185
1186 // file definition containing the class cd
1187 cd->setBodySegment(root->bodyLine,root->endBodyLine);
1188 cd->setBodyDef(fd);
1189
1190 // see if the class is found inside a namespace
1191 //bool found=addNamespace(root,cd);
1192
1193
1194 // the empty string test is needed for extract all case
1195 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1196 cd->insertUsedFile(root->fileName);
1197
1198 // add class to the list
1199 //printf("ClassDict.insert(%s)\n",resolveDefines(fullName).data());
1200 Doxygen::classSDict->append(fullName,cd);
1201
1202 }
1203
1204 cd->addSectionsToDefinition(root->anchors);
1205 if (!root->subGrouping) cd->setSubGrouping(FALSE);
1206 if (cd->hasDocumentation())
1207 {
1208 addIncludeFile(cd,fd,root);
1209 }
1210 if (fd && (root->section & Entry::COMPOUND_MASK))
1211 {
1212 //printf(">> Inserting class `%s' in file `%s' (root->fileName=`%s')\n",
1213 // cd->name().data(),
1214 // fd->name().data(),
1215 // root->fileName.data()
1216 // );
1217 cd->setFileDef(fd);
1218 fd->insertClass(cd);
1219 }
1220 addClassToGroups(root,cd);
1221 cd->setRefItems(root->sli);
1222
1223 rootNav->releaseEntry();
1224}
1225
1226//----------------------------------------------------------------------
1227// build a list of all classes mentioned in the documentation
1228// and all classes that have a documentation block before their definition.
1229static void buildClassList(EntryNav *rootNav)
1230{
1231 if (
1232 ((rootNav->section() & Entry::COMPOUND_MASK) ||
1233 rootNav->section()==Entry::OBJCIMPL_SEC) && !rootNav->name().isEmpty()
1234 )
1235 {
1236 addClassToContext(rootNav);
1237 }
1238 RECURSE_ENTRYTREE(buildClassList,rootNav);
1239}
1240
1241static void buildClassDocList(EntryNav *rootNav)
1242{
1243 if (
1244 (rootNav->section() & Entry::COMPOUNDDOC_MASK) && !rootNav->name().isEmpty()
1245 )
1246 {
1247 addClassToContext(rootNav);
1248 }
1249 RECURSE_ENTRYTREE(buildClassDocList,rootNav);
1250}
1251
1252static void resolveClassNestingRelations()
1253{
1254 ClassSDict::Iterator cli(*Doxygen::classSDict);
1255 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1256
1257 bool done=FALSE;
1258 int iteration=0;
1259 while (!done)
1260 {
1261 done=TRUE;
1262 ++iteration;
1263 ClassDef *cd=0;
1264 for (cli.toFirst();(cd=cli.current());++cli)
1265 {
1266 if (!cd->visited)
1267 {
1268 QCString name = stripAnonymousNamespaceScope(cd->name());
1269 //printf("processing=%s, iteration=%d\n",cd->name().data(),iteration);
1270 // also add class to the correct structural context
1271 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,
1272 name,cd->getFileDef());
1273 if (d)
1274 {
1275 //printf("****** adding %s to scope %s in iteration %d\n",cd->name().data(),d->name().data(),iteration);
1276 d->addInnerCompound(cd);
1277 cd->setOuterScope(d);
1278 cd->visited=TRUE;
1279 done=FALSE;
1280 }
1281 //else
1282 //{
1283 // printf("****** ignoring %s: scope not (yet) found in iteration %d\n",cd->name().data(),iteration);
1284 //}
1285 }
1286 }
1287 }
1288
1289 //give warnings for unresolved compounds
1290 ClassDef *cd=0;
1291 for (cli.toFirst();(cd=cli.current());++cli)
1292 {
1293 if (!cd->visited)
1294 {
1295 QCString name = stripAnonymousNamespaceScope(cd->name());
1296 //printf("processing unresolved=%s, iteration=%d\n",cd->name().data(),iteration);
1297 /// create the scope artificially
1298 // anyway, so we can at least relate scopes properly.
1299 Definition *d = buildScopeFromQualifiedName(name,name.contains("::"));
1300 if (d!=cd && !cd->getDefFileName().isEmpty())
1301 // avoid recursion in case of redundant scopes, i.e: namespace N { class N::C {}; }
1302 // for this case doxygen assumes the exitance of a namespace N::N in which C is to be found!
1303 // also avoid warning for stuff imported via a tagfile.
1304 {
1305 d->addInnerCompound(cd);
1306 cd->setOuterScope(d);
1307 warn(cd->getDefFileName(),cd->getDefLine(),
1308 "warning: Internal inconsistency: scope for class %s not "
1309 "found!",name.data()
1310 );
1311 }
1312 }
1313 }
1314}
1315
1316void distributeClassGroupRelations()
1317{
1318 static bool inlineGroupedClasses = Config_getBool("INLINE_GROUPED_CLASSES");
1319 if (!inlineGroupedClasses) return;
1320 //printf("** distributeClassGroupRelations()\n");
1321
1322 ClassSDict::Iterator cli(*Doxygen::classSDict);
1323 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
1324
1325 ClassDef *cd;
1326 for (cli.toFirst();(cd=cli.current());++cli)
1327 {
1328 //printf("Checking %s\n",cd->name().data());
1329 // distribute the group to nested classes as well
1330 if (!cd->visited && cd->partOfGroups()!=0 && cd->getInnerClasses())
1331 {
1332 //printf(" Candidate for merging\n");
1333 ClassSDict::Iterator ncli(*cd->getInnerClasses());
1334 ClassDef *ncd;
1335 GroupDef *gd = cd->partOfGroups()->at(0);
1336 for (ncli.toFirst();(ncd=ncli.current());++ncli)
1337 {
1338 if (ncd->partOfGroups()==0)
1339 {
1340 //printf(" Adding %s to group '%s'\n",ncd->name().data(),
1341 // gd->groupTitle());
1342 ncd->makePartOfGroup(gd);
1343 gd->addClass(ncd);
1344 }
1345 }
1346 cd->visited=TRUE; // only visit every class once
1347 }
1348 }
1349}
1350
1351//----------------------------------------------------------------------
1352// build a list of all namespaces mentioned in the documentation
1353// and all namespaces that have a documentation block before their definition.
1354static void buildNamespaceList(EntryNav *rootNav)
1355{
1356 if (
1357 (rootNav->section()==Entry::NAMESPACE_SEC ||
1358 rootNav->section()==Entry::NAMESPACEDOC_SEC ||
1359 rootNav->section()==Entry::PACKAGEDOC_SEC
1360 ) &&
1361 !rootNav->name().isEmpty()
1362 )
1363 {
1364 rootNav->loadEntry(g_storage);
1365 Entry *root = rootNav->entry();
1366
1367 //printf("** buildNamespaceList(%s)\n",root->name.data());
1368
1369 QCString fName = root->name;
1370 if (root->section==Entry::PACKAGEDOC_SEC)
1371 {
1372 fName=substitute(fName,".","::");
1373 }
1374
1375 QCString fullName = stripAnonymousNamespaceScope(fName);
1376 if (!fullName.isEmpty())
1377 {
1378 //printf("Found namespace %s in %s at line %d\n",root->name.data(),
1379 // root->fileName.data(), root->startLine);
1380 NamespaceDef *nd;
1381 if ((nd=Doxygen::namespaceSDict->find(fullName))) // existing namespace
1382 {
1383#if 0
1384 if (!root->doc.isEmpty() || !root->brief.isEmpty()) // block contains docs
1385 {
1386 if (nd->documentation().isEmpty() && !root->doc.isEmpty())
1387 {
1388#endif
1389 nd->setDocumentation(root->doc,root->docFile,root->docLine);
1390 nd->setName(fullName); // change name to match docs
1391 nd->addSectionsToDefinition(root->anchors);
1392#if 0
1393 }
1394 else if (!nd->documentation().isEmpty() && !root->doc.isEmpty())
1395 {
1396 warn(
1397 root->fileName,root->startLine,
1398 "warning: namespace %s already has a detailed description found in file %s at line %d. "
1399 "Skipping the documentation found here.",
1400 fullName.data(),nd->docFile().data(),nd->docLine());
1401 }
1402 if (nd->briefDescription().isEmpty() && !root->brief.isEmpty())
1403 {
1404#endif
1405 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1406#if 0
1407 nd->setName(fullName); // change name to match docs
1408 }
1409 else if (!nd->briefDescription().isEmpty() && !root->brief.isEmpty())
1410 {
1411 warn(root->fileName,root->startLine,
1412 "warning: namespace %s already has a brief description found in file %s at line %d. "
1413 "Skipping the documentation found here.",
1414 fullName.data(),nd->docFile().data(),nd->docLine()
1415 );
1416 }
1417 }
1418#endif
1419
1420 // file definition containing the namespace nd
1421 FileDef *fd=rootNav->fileDef();
1422 // insert the namespace in the file definition
1423 if (fd) fd->insertNamespace(nd);
1424 addNamespaceToGroups(root,nd);
1425 nd->setRefItems(root->sli);
1426 }
1427 else // fresh namespace
1428 {
1429 QCString tagName;
1430 QCString tagFileName;
1431 if (rootNav->tagInfo())
1432 {
1433 tagName=rootNav->tagInfo()->tagName;
1434 tagFileName=rootNav->tagInfo()->fileName;
1435 }
1436 //printf("++ new namespace %s\n",fullName.data());
1437 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,fullName,tagName,tagFileName);
1438 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1439 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1440 nd->addSectionsToDefinition(root->anchors);
1441 nd->setHidden(root->hidden);
1442 nd->setArtificial(root->artificial);
1443
1444 //printf("Adding namespace to group\n");
1445 addNamespaceToGroups(root,nd);
1446 nd->setRefItems(root->sli);
1447
1448 // file definition containing the namespace nd
1449 FileDef *fd=rootNav->fileDef();
1450 // insert the namespace in the file definition
1451 if (fd) fd->insertNamespace(nd);
1452
1453 // the empty string test is needed for extract all case
1454 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1455 nd->insertUsedFile(root->fileName);
1456 nd->setBodySegment(root->bodyLine,root->endBodyLine);
1457 nd->setBodyDef(fd);
1458 // add class to the list
1459 Doxygen::namespaceSDict->inSort(fullName,nd);
1460
1461 // also add namespace to the correct structural context
1462 Definition *d = findScopeFromQualifiedName(Doxygen::globalScope,fullName);
1463 //printf("adding namespace %s to context %s\n",nd->name().data(),d?d->name().data():"<none>");
1464 if (d==0) // we didn't find anything, create the scope artificially
1465 // anyway, so we can at least relate scopes properly.
1466 {
1467 Definition *d = buildScopeFromQualifiedName(fullName,fullName.contains("::"));
1468 d->addInnerCompound(nd);
1469 nd->setOuterScope(d);
1470 // TODO: Due to the order in which the tag file is written
1471 // a nested class can be found before its parent!
1472 }
1473 else
1474 {
1475 d->addInnerCompound(nd);
1476 nd->setOuterScope(d);
1477 }
1478 }
1479 }
1480
1481 rootNav->releaseEntry();
1482 }
1483 RECURSE_ENTRYTREE(buildNamespaceList,rootNav);
1484}
1485
1486//----------------------------------------------------------------------
1487
1488static NamespaceDef *findUsedNamespace(NamespaceSDict *unl,
1489 const QCString &name)
1490{
1491 NamespaceDef *usingNd =0;
1492 if (unl)
1493 {
1494 //printf("Found namespace dict %d\n",unl->count());
1495 NamespaceSDict::Iterator unli(*unl);
1496 NamespaceDef *und;
1497 for (unli.toFirst();(und=unli.current());++unli)
1498 {
1499 QCString uScope=und->name()+"::";
1500 usingNd = getResolvedNamespace(uScope+name);
1501 //printf("Also trying with scope=`%s' usingNd=%p\n",(uScope+name).data(),usingNd);
1502 }
1503 }
1504 return usingNd;
1505}
1506
1507static void findUsingDirectives(EntryNav *rootNav)
1508{
1509 if (rootNav->section()==Entry::USINGDIR_SEC)
1510 {
1511 rootNav->loadEntry(g_storage);
1512 Entry *root = rootNav->entry();
1513
1514 //printf("Found using directive %s at line %d of %s\n",
1515 // root->name.data(),root->startLine,root->fileName.data());
1516 QCString name=substitute(root->name,".","::");
1517 if (!name.isEmpty())
1518 {
1519 NamespaceDef *usingNd = 0;
1520 NamespaceDef *nd = 0;
1521 FileDef *fd = rootNav->fileDef();
1522 QCString nsName;
1523
1524 // see if the using statement was found inside a namespace or inside
1525 // the global file scope.
1526 if (rootNav->parent() && rootNav->parent()->section()==Entry::NAMESPACE_SEC &&
1527 (fd==0 || !fd->isJava()) // not a .java file
1528 )
1529 {
1530 nsName=stripAnonymousNamespaceScope(rootNav->parent()->name());
1531 if (!nsName.isEmpty())
1532 {
1533 nd = getResolvedNamespace(nsName);
1534 }
1535 }
1536
1537 // find the scope in which the `using' namespace is defined by prepending
1538 // the possible scopes in which the using statement was found, starting
1539 // with the most inner scope and going to the most outer scope (i.e.
1540 // file scope).
1541 int scopeOffset = nsName.length();
1542 do
1543 {
1544 QCString scope=scopeOffset>0 ?
1545 nsName.left(scopeOffset)+"::" : QCString();
1546 usingNd = getResolvedNamespace(scope+name);
1547 //printf("Trying with scope=`%s' usingNd=%p\n",(scope+name).data(),usingNd);
1548 if (scopeOffset==0)
1549 {
1550 scopeOffset=-1;
1551 }
1552 else if ((scopeOffset=nsName.findRev("::",scopeOffset-1))==-1)
1553 {
1554 scopeOffset=0;
1555 }
1556 } while (scopeOffset>=0 && usingNd==0);
1557
1558 if (usingNd==0 && nd) // not found, try used namespaces in this scope
1559 // or in one of the parent namespace scopes
1560 {
1561 NamespaceDef *pnd = nd;
1562 while (pnd && usingNd==0)
1563 {
1564 // also try with one of the used namespaces found earlier
1565 usingNd = findUsedNamespace(pnd->getUsedNamespaces(),name);
1566
1567 // goto the parent
1568 Definition *s = pnd->getOuterScope();
1569 if (s && s->definitionType()==Definition::TypeNamespace)
1570 {
1571 pnd = (NamespaceDef*)s;
1572 }
1573 else
1574 {
1575 pnd = 0;
1576 }
1577 }
1578 }
1579 if (usingNd==0 && fd) // still nothing, also try used namespace in the
1580 // global scope
1581 {
1582 usingNd = findUsedNamespace(fd->getUsedNamespaces(),name);
1583 }
1584
1585 //printf("%s -> %s\n",name.data(),usingNd?usingNd->name().data():"<none>");
1586
1587 // add the namespace the correct scope
1588 if (usingNd)
1589 {
1590 //printf("using fd=%p nd=%p\n",fd,nd);
1591 if (nd)
1592 {
1593 //printf("Inside namespace %s\n",nd->name().data());
1594 nd->addUsingDirective(usingNd);
1595 }
1596 else if (fd)
1597 {
1598 //printf("Inside file %s\n",fd->name().data());
1599 fd->addUsingDirective(usingNd);
1600 }
1601 }
1602 else // unknown namespace, but add it anyway.
1603 {
1604 //printf("++ new unknown namespace %s\n",name.data());
1605 NamespaceDef *nd=new NamespaceDef(root->fileName,root->startLine,name);
1606 nd->setDocumentation(root->doc,root->docFile,root->docLine); // copy docs to definition
1607 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1608 nd->addSectionsToDefinition(root->anchors);
1609 //printf("** Adding namespace %s hidden=%d\n",name.data(),root->hidden);
1610 nd->setHidden(root->hidden);
1611 nd->setArtificial(TRUE);
1612
1613 QListIterator<Grouping> gli(*root->groups);
1614 Grouping *g;
1615 for (;(g=gli.current());++gli)
1616 {
1617 GroupDef *gd=0;
1618 if (!g->groupname.isEmpty() && (gd=Doxygen::groupSDict->find(g->groupname)))
1619 gd->addNamespace(nd);
1620 }
1621
1622 // insert the namespace in the file definition
1623 if (fd)
1624 {
1625 fd->insertNamespace(nd);
1626 fd->addUsingDirective(nd);
1627 }
1628
1629 // the empty string test is needed for extract all case
1630 nd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1631 nd->insertUsedFile(root->fileName);
1632 // add class to the list
1633 Doxygen::namespaceSDict->inSort(name,nd);
1634 nd->setRefItems(root->sli);
1635 }
1636 }
1637
1638 rootNav->releaseEntry();
1639 }
1640 RECURSE_ENTRYTREE(findUsingDirectives,rootNav);
1641}
1642
1643//----------------------------------------------------------------------
1644
1645static void buildListOfUsingDecls(EntryNav *rootNav)
1646{
1647 if (rootNav->section()==Entry::USINGDECL_SEC &&
1648 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1649 )
1650 {
1651 rootNav->loadEntry(g_storage);
1652 Entry *root = rootNav->entry();
1653
1654 QCString name = substitute(root->name,".","::");
1655 if (g_usingDeclarations.find(name)==0)
1656 {
1657 FileDef *fd = rootNav->fileDef();
1658 if (fd)
1659 {
1660 g_usingDeclarations.insert(name,fd);
1661 }
1662 }
1663
1664 rootNav->releaseEntry();
1665 }
1666 RECURSE_ENTRYTREE(buildListOfUsingDecls,rootNav);
1667}
1668
1669
1670static void findUsingDeclarations(EntryNav *rootNav)
1671{
1672 if (rootNav->section()==Entry::USINGDECL_SEC &&
1673 !(rootNav->parent()->section()&Entry::COMPOUND_MASK) // not a class/struct member
1674 )
1675 {
1676 rootNav->loadEntry(g_storage);
1677 Entry *root = rootNav->entry();
1678
1679 //printf("Found using declaration %s at line %d of %s inside section %x\n",
1680 // root->name.data(),root->startLine,root->fileName.data(),
1681 // rootNav->parent()->section());
1682 if (!root->name.isEmpty())
1683 {
1684 ClassDef *usingCd = 0;
1685 NamespaceDef *nd = 0;
1686 FileDef *fd = rootNav->fileDef();
1687 QCString scName;
1688
1689 // see if the using statement was found inside a namespace or inside
1690 // the global file scope.
1691 if (rootNav->parent()->section() == Entry::NAMESPACE_SEC)
1692 {
1693 scName=rootNav->parent()->name();
1694 if (!scName.isEmpty())
1695 {
1696 nd = getResolvedNamespace(scName);
1697 }
1698 }
1699
1700 // Assume the using statement was used to import a class.
1701 // Find the scope in which the `using' namespace is defined by prepending
1702 // the possible scopes in which the using statement was found, starting
1703 // with the most inner scope and going to the most outer scope (i.e.
1704 // file scope).
1705
1706 QCString name = substitute(root->name,".","::"); //Java/C# scope->internal
1707 usingCd = getClass(name);
1708 if (usingCd==0)
1709 {
1710 usingCd = Doxygen::hiddenClasses->find(name);
1711 }
1712
1713 //printf("%s -> %p\n",root->name.data(),usingCd);
1714 if (usingCd==0) // definition not in the input => add an artificial class
1715 {
1716 Debug::print(Debug::Classes,0," New using class `%s' (sec=0x%08x)! #tArgLists=%d\n",
1717 name.data(),root->section,root->tArgLists ? (int)root->tArgLists->count() : -1);
1718 usingCd = new ClassDef(
1719 "<using>",1,
1720 name,ClassDef::Class);
1721 Doxygen::hiddenClasses->append(root->name,usingCd);
1722 usingCd->setArtificial(TRUE);
1723 }
1724 else
1725 {
1726 Debug::print(Debug::Classes,0," Found used class %s in scope=%s\n",
1727 usingCd->name().data(),nd?nd->name().data():fd->name().data());
1728 }
1729
1730 if (usingCd) // add the class to the correct scope
1731 {
1732 if (nd)
1733 {
1734 //printf("Inside namespace %s\n",nd->name().data());
1735 nd->addUsingDeclaration(usingCd);
1736 }
1737 else if (fd)
1738 {
1739 //printf("Inside file %s\n",fd->name().data());
1740 fd->addUsingDeclaration(usingCd);
1741 }
1742 }
1743 }
1744
1745 rootNav->releaseEntry();
1746 }
1747 RECURSE_ENTRYTREE(findUsingDeclarations,rootNav);
1748}
1749
1750//----------------------------------------------------------------------
1751
1752static void findUsingDeclImports(EntryNav *rootNav)
1753{
1754 if (rootNav->section()==Entry::USINGDECL_SEC &&
1755 (rootNav->parent()->section()&Entry::COMPOUND_MASK) // in a class/struct member
1756 )
1757 {
1758 //printf("Found using declaration %s at line %d of %s inside section %x\n",
1759 // root->name.data(),root->startLine,root->fileName.data(),
1760 // root->parent->section);
1761 QCString fullName=removeRedundantWhiteSpace(rootNav->parent()->name());
1762 fullName=stripAnonymousNamespaceScope(fullName);
1763 fullName=stripTemplateSpecifiersFromScope(fullName);
1764 ClassDef *cd = getClass(fullName);
1765 if (cd)
1766 {
1767 //printf("found class %s\n",cd->name().data());
1768 int i=rootNav->name().find("::");
1769 if (i!=-1)
1770 {
1771 QCString scope=rootNav->name().left(i);
1772 QCString memName=rootNav->name().right(rootNav->name().length()-i-2);
1773 ClassDef *bcd = getResolvedClass(cd,0,scope); // todo: file in fileScope parameter
1774 if (bcd)
1775 {
1776 //printf("found class %s\n",bcd->name().data());
1777 MemberNameInfoSDict *mndict=bcd->memberNameInfoSDict();
1778 if (mndict)
1779 {
1780 MemberNameInfo *mni = mndict->find(memName);
1781 if (mni)
1782 {
1783 MemberNameInfoIterator mnii(*mni);
1784 MemberInfo *mi;
1785 for ( ; (mi=mnii.current()) ; ++mnii )
1786 {
1787 MemberDef *md = mi->memberDef;
1788 if (md && md->protection()!=Private)
1789 {
1790
1791 rootNav->loadEntry(g_storage);
1792 Entry *root = rootNav->entry();
1793
1794 //printf("found member %s\n",mni->memberName());
1795 MemberDef *newMd = 0;
1796 {
1797 LockingPtr<ArgumentList> templAl = md->templateArguments();
1798 LockingPtr<ArgumentList> al = md->templateArguments();
1799 newMd = new MemberDef(
1800 root->fileName,root->startLine,
1801 md->typeString(),memName,md->argsString(),
1802 md->excpString(),root->protection,root->virt,
1803 md->isStatic(),Member,md->memberType(),
1804 templAl.pointer(),al.pointer()
1805 );
1806 }
1807 newMd->setMemberClass(cd);
1808 cd->insertMember(newMd);
1809 if (!root->doc.isEmpty() || !root->brief.isEmpty())
1810 {
1811 newMd->setDocumentation(root->doc,root->docFile,root->docLine);
1812 newMd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1813 newMd->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
1814 }
1815 else
1816 {
1817 newMd->setDocumentation(md->documentation(),md->docFile(),md->docLine());
1818 newMd->setBriefDescription(md->briefDescription(),md->briefFile(),md->briefLine());
1819 newMd->setInbodyDocumentation(md->inbodyDocumentation(),md->inbodyFile(),md->inbodyLine());
1820 }
1821 newMd->setDefinition(md->definition());
1822 newMd->enableCallGraph(root->callGraph);
1823 newMd->enableCallerGraph(root->callerGraph);
1824 newMd->setBitfields(md->bitfieldString());
1825 newMd->addSectionsToDefinition(root->anchors);
1826 newMd->setBodySegment(md->getStartBodyLine(),md->getEndBodyLine());
1827 newMd->setBodyDef(md->getBodyDef());
1828 newMd->setInitializer(md->initializer());
1829 newMd->setMaxInitLines(md->initializerLines());
1830 newMd->setMemberGroupId(root->mGrpId);
1831 newMd->setMemberSpecifiers(md->getMemberSpecifiers());
1832
1833 rootNav->releaseEntry();
1834 }
1835 }
1836 }
1837 }
1838 }
1839 }
1840 }
1841
1842 }
1843 RECURSE_ENTRYTREE(findUsingDeclImports,rootNav);
1844}
1845
1846//----------------------------------------------------------------------
1847
1848static void findIncludedUsingDirectives()
1849{
1850 // first mark all files as not visited
1851 FileNameListIterator fnli(*Doxygen::inputNameList);
1852 FileName *fn;
1853 for (fnli.toFirst();(fn=fnli.current());++fnli)
1854 {
1855 FileNameIterator fni(*fn);
1856 FileDef *fd;
1857 for (;(fd=fni.current());++fni)
1858 {
1859 fd->visited=FALSE;
1860 }
1861 }
1862 // then recursively add using directives found in #include files
1863 // to files that have not been visited.
1864 for (fnli.toFirst();(fn=fnli.current());++fnli)
1865 {
1866 FileNameIterator fni(*fn);
1867 FileDef *fd;
1868 for (fni.toFirst();(fd=fni.current());++fni)
1869 {
1870 if (!fd->visited)
1871 {
1872 //printf("----- adding using directives for file %s\n",fd->name().data());
1873 fd->addIncludedUsingDirectives();
1874 }
1875 }
1876 }
1877}
1878
1879//----------------------------------------------------------------------
1880
1881static MemberDef *addVariableToClass(
1882 EntryNav *rootNav,
1883 ClassDef *cd,
1884 MemberDef::MemberType mtype,
1885 const QCString &name,
1886 bool fromAnnScope,
1887 MemberDef *fromAnnMemb,
1888 Protection prot,
1889 Relationship related)
1890{
1891 Entry *root = rootNav->entry();
1892
1893 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
1894 QCString scopeSeparator="::";
1895 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
1896 {
1897 qualScope = substitute(qualScope,"::",".");
1898 scopeSeparator=".";
1899 }
1900 Debug::print(Debug::Variables,0,
1901 " class variable:\n"
1902 " `%s' `%s'::`%s' `%s' prot=`%d ann=%d init=`%s'\n",
1903 root->type.data(),
1904 qualScope.data(),
1905 name.data(),
1906 root->args.data(),
1907 root->protection,
1908 fromAnnScope,
1909 root->initializer.data()
1910 );
1911
1912 QCString def;
1913 if (!root->type.isEmpty())
1914 {
1915 if (related || mtype==MemberDef::Friend || Config_getBool("HIDE_SCOPE_NAMES"))
1916 {
1917 def=root->type+" "+name+root->args;
1918 }
1919 else
1920 {
1921 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
1922 }
1923 }
1924 else
1925 {
1926 if (Config_getBool("HIDE_SCOPE_NAMES"))
1927 {
1928 def=name+root->args;
1929 }
1930 else
1931 {
1932 def=qualScope+scopeSeparator+name+root->args;
1933 }
1934 }
1935 def.stripPrefix("static ");
1936
1937 // see if the member is already found in the same scope
1938 // (this may be the case for a static member that is initialized
1939 // outside the class)
1940 MemberName *mn=Doxygen::memberNameSDict->find(name);
1941 if (mn)
1942 {
1943 MemberNameIterator mni(*mn);
1944 MemberDef *md;
1945 for (mni.toFirst();(md=mni.current());++mni)
1946 {
1947 //printf("md->getClassDef()=%p cd=%p type=[%s] md->typeString()=[%s]\n",
1948 // md->getClassDef(),cd,root->type.data(),md->typeString());
1949 if (md->getClassDef()==cd &&
1950 removeRedundantWhiteSpace(root->type)==md->typeString())
1951 // member already in the scope
1952 {
1953
1954 if (root->lang==SrcLangExt_ObjC &&
1955 root->mtype==Property &&
1956 md->memberType()==MemberDef::Variable)
1957 { // Objective-C 2.0 property
1958 // turn variable into a property
1959 md->setProtection(root->protection);
1960 cd->reclassifyMember(md,MemberDef::Property);
1961 }
1962 addMemberDocs(rootNav,md,def,0,FALSE);
1963 //printf(" Member already found!\n");
1964 return md;
1965 }
1966 }
1967 }
1968
1969 // new member variable, typedef or enum value
1970 MemberDef *md=new MemberDef(
1971 root->fileName,root->startLine,
1972 root->type,name,root->args,0,
1973 prot,Normal,root->stat,related,
1974 mtype,0,0);
1975 md->setTagInfo(rootNav->tagInfo());
1976 md->setMemberClass(cd); // also sets outer scope (i.e. getOuterScope())
1977 //md->setDefFile(root->fileName);
1978 //md->setDefLine(root->startLine);
1979 md->setDocumentation(root->doc,root->docFile,root->docLine);
1980 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
1981 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
1982 md->setDefinition(def);
1983 md->setBitfields(root->bitfields);
1984 md->addSectionsToDefinition(root->anchors);
1985 md->setFromAnonymousScope(fromAnnScope);
1986 md->setFromAnonymousMember(fromAnnMemb);
1987 //md->setIndentDepth(indentDepth);
1988 md->setBodySegment(root->bodyLine,root->endBodyLine);
1989 md->setInitializer(root->initializer);
1990 md->setMaxInitLines(root->initLines);
1991 md->setMemberGroupId(root->mGrpId);
1992 md->setMemberSpecifiers(root->spec);
1993 md->setReadAccessor(root->read);
1994 md->setWriteAccessor(root->write);
1995 md->enableCallGraph(root->callGraph);
1996 md->enableCallerGraph(root->callerGraph);
1997 md->setHidden(root->hidden);
1998 md->setArtificial(root->artificial);
1999 addMemberToGroups(root,md);
2000 //if (root->mGrpId!=-1)
2001 //{
2002 // printf("memberdef %s in memberGroup %d\n",name.data(),root->mGrpId);
2003 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
2004 //
2005 md->setBodyDef(rootNav->fileDef());
2006
2007 //printf(" Adding member=%s\n",md->name().data());
2008 // add the member to the global list
2009 if (mn)
2010 {
2011 mn->append(md);
2012 }
2013 else // new variable name
2014 {
2015 mn = new MemberName(name);
2016 mn->append(md);
2017 //printf("Adding memberName=%s\n",mn->memberName());
2018 //Doxygen::memberNameDict.insert(name,mn);
2019 //Doxygen::memberNameList.append(mn);
2020 Doxygen::memberNameSDict->append(name,mn);
2021 // add the member to the class
2022 }
2023 //printf(" New member adding to %s (%p)!\n",cd->name().data(),cd);
2024 cd->insertMember(md);
2025 md->setRefItems(root->sli);
2026
2027 //TODO: insert FileDef instead of filename strings.
2028 cd->insertUsedFile(root->fileName);
2029 rootNav->changeSection(Entry::EMPTY_SEC);
2030 return md;
2031}
2032
2033//----------------------------------------------------------------------
2034
2035static MemberDef *addVariableToFile(
2036 EntryNav *rootNav,
2037 MemberDef::MemberType mtype,
2038 const QCString &scope,
2039 const QCString &name,
2040 bool fromAnnScope,
2041 /*int indentDepth,*/
2042 MemberDef *fromAnnMemb)
2043{
2044 Entry *root = rootNav->entry();
2045 Debug::print(Debug::Variables,0,
2046 " global variable:\n"
2047 " type=`%s' scope=`%s' name=`%s' args=`%s' prot=`%d mtype=%d\n",
2048 root->type.data(),
2049 scope.data(),
2050 name.data(),
2051 root->args.data(),
2052 root->protection,
2053 mtype
2054 );
2055
2056 FileDef *fd = rootNav->fileDef();
2057
2058 // see if we have a typedef that should hide a struct or union
2059 if (mtype==MemberDef::Typedef && Config_getBool("TYPEDEF_HIDES_STRUCT"))
2060 {
2061 QCString type = root->type;
2062 type.stripPrefix("typedef ");
2063 if (type.left(7)=="struct " || type.left(6)=="union ")
2064 {
2065 type.stripPrefix("struct ");
2066 type.stripPrefix("union ");
2067 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9]*");
2068 int l,s;
2069 s = re.match(type,0,&l);
2070 if (s>=0)
2071 {
2072 QCString typeValue = type.mid(s,l);
2073 ClassDef *cd = getClass(typeValue);
2074 if (cd)
2075 {
2076 // this typedef should hide compound name cd, so we
2077 // change the name that is displayed from cd.
2078 cd->setClassName(name);
2079 cd->setDocumentation(root->doc,root->docFile,root->docLine);
2080 cd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2081 return 0;
2082 }
2083 }
2084 }
2085 }
2086
2087 // see if the function is inside a namespace
2088 NamespaceDef *nd = 0;
2089 QCString nscope;
2090 if (!scope.isEmpty())
2091 {
2092 if (scope.find('@')!=-1) return 0; // anonymous scope!
2093 //nscope=removeAnonymousScopes(scope);
2094 //if (!nscope.isEmpty())
2095 //{
2096 nd = getResolvedNamespace(scope);
2097 //}
2098 }
2099 QCString def;
2100
2101 // determine the definition of the global variable
2102 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@' &&
2103 !Config_getBool("HIDE_SCOPE_NAMES")
2104 )
2105 // variable is inside a namespace, so put the scope before the name
2106 {
2107 static bool optimizeForJava = Config_getBool("OPTIMIZE_OUTPUT_JAVA");
2108 QCString sep="::";
2109 if (optimizeForJava) sep=".";
2110
2111 if (!root->type.isEmpty())
2112 {
2113 def=root->type+" "+nd->name()+sep+name+root->args;
2114 }
2115 else
2116 {
2117 def=nd->name()+sep+name+root->args;
2118 }
2119 }
2120 else
2121 {
2122 if (!root->type.isEmpty() && !root->name.isEmpty())
2123 {
2124 if (name.at(0)=='@') // dummy variable representing anonymous union
2125 def=root->type;
2126 else
2127 def=root->type+" "+name+root->args;
2128 }
2129 else
2130 {
2131 def=name+root->args;
2132 }
2133 }
2134 def.stripPrefix("static ");
2135
2136 MemberName *mn=Doxygen::functionNameSDict->find(name);
2137 if (mn)
2138 {
2139 //QCString nscope=removeAnonymousScopes(scope);
2140 //NamespaceDef *nd=0;
2141 //if (!nscope.isEmpty())
2142 if (!scope.isEmpty())
2143 {
2144 nd = getResolvedNamespace(scope);
2145 }
2146 MemberNameIterator mni(*mn);
2147 MemberDef *md;
2148 for (mni.toFirst();(md=mni.current());++mni)
2149 {
2150 if (
2151 ((nd==0 && md->getNamespaceDef()==0 && md->getFileDef() &&
2152 root->fileName==md->getFileDef()->absFilePath()
2153 ) // both variable names in the same file
2154 || (nd!=0 && md->getNamespaceDef()==nd) // both in same namespace
2155 )
2156 && !md->isDefine() // function style #define's can be "overloaded" by typedefs or variables
2157 && !md->isEnumerate() // in C# an enum value and enum can have the same name
2158 )
2159 // variable already in the scope
2160 {
2161 if (md->getFileDef() &&
2162 ! // not a php array
2163 (
2164 (getLanguageFromFileName(md->getFileDef()->name())==SrcLangExt_PHP) &&
2165 (md->argsString()!=root->args && root->args.find('[')!=-1)
2166 )
2167 )
2168 // not a php array variable
2169 {
2170
2171 Debug::print(Debug::Variables,0,
2172 " variable already found: scope=%s\n",md->getOuterScope()->name().data());
2173 addMemberDocs(rootNav,md,def,0,FALSE);
2174 md->setRefItems(root->sli);
2175 return md;
2176 }
2177 }
2178 }
2179 }
2180 Debug::print(Debug::Variables,0,
2181 " new variable, nd=%s!\n",nd?nd->name().data():"<global>");
2182 // new global variable, enum value or typedef
2183 MemberDef *md=new MemberDef(
2184 root->fileName,root->startLine,
2185 root->type,name,root->args,0,
2186 Public, Normal,root->stat,Member,
2187 mtype,0,0);
2188 md->setTagInfo(rootNav->tagInfo());
2189 md->setDocumentation(root->doc,root->docFile,root->docLine);
2190 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2191 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2192 md->addSectionsToDefinition(root->anchors);
2193 md->setFromAnonymousScope(fromAnnScope);
2194 md->setFromAnonymousMember(fromAnnMemb);
2195 md->setInitializer(root->initializer);
2196 md->setMaxInitLines(root->initLines);
2197 md->setMemberGroupId(root->mGrpId);
2198 md->setDefinition(def);
2199 md->enableCallGraph(root->callGraph);
2200 md->enableCallerGraph(root->callerGraph);
2201 md->setExplicitExternal(root->explicitExternal);
2202 //md->setOuterScope(fd);
2203 if (!root->explicitExternal)
2204 {
2205 md->setBodySegment(root->bodyLine,root->endBodyLine);
2206 md->setBodyDef(fd);
2207 }
2208 addMemberToGroups(root,md);
2209
2210 md->setRefItems(root->sli);
2211 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
2212 {
2213 md->setNamespace(nd);
2214 nd->insertMember(md);
2215 }
2216
2217 // add member to the file (we do this even if we have already inserted
2218 // it into the namespace.
2219 if (fd)
2220 {
2221 md->setFileDef(fd);
2222 fd->insertMember(md);
2223 }
2224
2225 // add member definition to the list of globals
2226 if (mn)
2227 {
2228 mn->append(md);
2229 }
2230 else
2231 {
2232 mn = new MemberName(name);
2233 mn->append(md);
2234 Doxygen::functionNameSDict->append(name,mn);
2235 }
2236 rootNav->changeSection(Entry::EMPTY_SEC);
2237 return md;
2238}
2239
2240/*! See if the return type string \a type is that of a function pointer
2241 * \returns -1 if this is not a function pointer variable or
2242 * the index at which the brace of (...*name) was found.
2243 */
2244static int findFunctionPtr(const QCString &type,int lang, int *pLength=0)
2245{
2246 if (lang == SrcLangExt_F90) return -1; // Fortran does not have function pointers
2247 static const QRegExp re("([^)]*[\\*\\^][^)]*)");
2248 int i=-1,l;
2249 if (!type.isEmpty() && // return type is non-empty
2250 (i=re.match(type,0,&l))!=-1 && // contains (...*...)
2251 type.find("operator")==-1 && // not an operator
2252 (type.find(")(")==-1 || type.find("typedef ")!=-1)
2253 // not a function pointer return type
2254 )
2255 {
2256 if (pLength) *pLength=l;
2257 //printf("findFunctionPtr=%d\n",i);
2258 return i;
2259 }
2260 else
2261 {
2262 //printf("findFunctionPtr=%d\n",-1);
2263 return -1;
2264 }
2265}
2266
2267
2268/*! Returns TRUE iff \a type is a class within scope \a context.
2269 * Used to detect variable declarations that look like function prototypes.
2270 */
2271static bool isVarWithConstructor(EntryNav *rootNav)
2272{
2273 static QRegExp initChars("[0-9\"'&*!^]+");
2274 static QRegExp idChars("[a-z_A-Z][a-z_A-Z0-9]*");
2275 bool result=FALSE;
2276 bool typeIsClass;
2277 QCString type;
2278 Definition *ctx = 0;
2279 FileDef *fd = 0;
2280 int ti;
2281
2282 //printf("isVarWithConstructor(%s)\n",rootNav->name().data());
2283 rootNav->loadEntry(g_storage);
2284 Entry *root = rootNav->entry();
2285
2286 if (rootNav->parent()->section() & Entry::COMPOUND_MASK)
2287 { // inside a class
2288 result=FALSE;
2289 goto done;
2290 }
2291 else if ((fd = rootNav->fileDef()) &&
2292 (fd->name().right(2)==".c" || fd->name().right(2)==".h")
2293 )
2294 { // inside a .c file
2295 result=FALSE;
2296 goto done;
2297 }
2298 if (root->type.isEmpty())
2299 {
2300 result=FALSE;
2301 goto done;
2302 }
2303 if (!rootNav->parent()->name().isEmpty())
2304 {
2305 ctx=Doxygen::namespaceSDict->find(rootNav->parent()->name());
2306 }
2307 type = root->type;
2308 // remove qualifiers
2309 findAndRemoveWord(type,"const");
2310 findAndRemoveWord(type,"static");
2311 findAndRemoveWord(type,"volatile");
2312 //if (type.left(6)=="const ") type=type.right(type.length()-6);
2313 typeIsClass=getResolvedClass(ctx,fd,type)!=0;
2314 if (!typeIsClass && (ti=type.find('<'))!=-1)
2315 {
2316 typeIsClass=getResolvedClass(ctx,fd,type.left(ti))!=0;
2317 }
2318 if (typeIsClass) // now we still have to check if the arguments are
2319 // types or values. Since we do not have complete type info
2320 // we need to rely on heuristics :-(
2321 {
2322 //printf("typeIsClass\n");
2323 ArgumentList *al = root->argList;
2324 if (al==0 || al->isEmpty())
2325 {
2326 result=FALSE; // empty arg list -> function prototype.
2327 goto done;
2328 }
2329 ArgumentListIterator ali(*al);
2330 Argument *a;
2331 for (ali.toFirst();(a=ali.current());++ali)
2332 {
2333 if (!a->name.isEmpty() || !a->defval.isEmpty())
2334 {
2335 if (a->name.find(initChars)==0)
2336 {
2337 result=TRUE;
2338 }
2339 else
2340 {
2341 result=FALSE; // arg has (type,name) pair -> function prototype
2342 }
2343 goto done;
2344 }
2345 if (a->type.isEmpty() || getResolvedClass(ctx,fd,a->type)!=0)
2346 {
2347 result=FALSE; // arg type is a known type
2348 goto done;
2349 }
2350 if (checkIfTypedef(ctx,fd,a->type))
2351 {
2352 //printf("%s:%d: false (arg is typedef)\n",__FILE__,__LINE__);
2353 result=FALSE; // argument is a typedef
2354 goto done;
2355 }
2356 if (a->type.at(a->type.length()-1)=='*' ||
2357 a->type.at(a->type.length()-1)=='&')
2358 // type ends with * or & => pointer or reference
2359 {
2360 result=FALSE;
2361 goto done;
2362 }
2363 if (a->type.find(initChars)==0)
2364 {
2365 result=TRUE; // argument type starts with typical initializer char
2366 goto done;
2367 }
2368 QCString resType=resolveTypeDef(ctx,a->type);
2369 if (resType.isEmpty()) resType=a->type;
2370 int len;
2371 if (idChars.match(resType,0,&len)==0) // resType starts with identifier
2372 {
2373 resType=resType.left(len);
2374 //printf("resType=%s\n",resType.data());
2375 if (resType=="int" || resType=="long" || resType=="float" ||
2376 resType=="double" || resType=="char" || resType=="signed" ||
2377 resType=="const" || resType=="unsigned" || resType=="void")
2378 {
2379 result=FALSE; // type keyword -> function prototype
2380 goto done;
2381 }
2382 }
2383 }
2384 result=TRUE;
2385 }
2386
2387done:
2388 //printf("isVarWithConstructor(%s,%s)=%d\n",rootNav->parent()->name().data(),
2389 // root->type.data(),result);
2390 rootNav->releaseEntry();
2391 return result;
2392}
2393
2394static void addVariable(EntryNav *rootNav,int isFuncPtr=-1)
2395{
2396 rootNav->loadEntry(g_storage);
2397 Entry *root = rootNav->entry();
2398
2399 Debug::print(Debug::Variables,0,
2400 "VARIABLE_SEC: \n"
2401 " type=`%s' name=`%s' args=`%s' bodyLine=`%d' mGrpId=%d\n",
2402 root->type.data(),
2403 root->name.data(),
2404 root->args.data(),
2405 root->bodyLine,
2406 root->mGrpId
2407 );
2408 //printf("root->parent->name=%s\n",root->parent->name.data());
2409
2410 if (root->type.isEmpty() && root->name.find("operator")==-1 &&
2411 (root->name.find('*')!=-1 || root->name.find('&')!=-1))
2412 {
2413 // recover from parse error caused by redundant braces
2414 // like in "int *(var[10]);", which is parsed as
2415 // type="" name="int *" args="(var[10])"
2416
2417 root->type=root->name;
2418 static const QRegExp reName("[a-z_A-Z][a-z_A-Z0-9]*");
2419 int l;
2420 int i=root->args.isEmpty() ? -1 : reName.match(root->args,0,&l);
2421 root->name=root->args.mid(i,l);
2422 root->args=root->args.mid(i+l,root->args.find(')',i+l)-i-l);
2423 //printf("new: type=`%s' name=`%s' args=`%s'\n",
2424 // root->type.data(),root->name.data(),root->args.data());
2425 }
2426 else
2427 {
2428 int i=isFuncPtr;
2429 if (i==-1) i=findFunctionPtr(root->type,root->lang); // for typedefs isFuncPtr is not yet set
2430 if (i!=-1) // function pointer
2431 {
2432 int ai = root->type.find('[',i);
2433 if (ai>i) // function pointer array
2434 {
2435 root->args.prepend(root->type.right(root->type.length()-ai));
2436 root->type=root->type.left(ai);
2437 }
2438 else if (root->type.find(')',i)!=-1) // function ptr, not variable like "int (*bla)[10]"
2439 {
2440 root->type=root->type.left(root->type.length()-1);
2441 root->args.prepend(")");
2442 //printf("root->type=%s root->args=%s\n",root->type.data(),root->args.data());
2443 }
2444 }
2445 else if (root->type.find("typedef ")!=-1 && root->type.right(2)=="()") // typedef void (func)(int)
2446 {
2447 root->type=root->type.left(root->type.length()-1);
2448 root->args.prepend(")");
2449 }
2450 }
2451
2452 QCString scope,name=removeRedundantWhiteSpace(root->name);
2453
2454 // find the scope of this variable
2455 EntryNav *p = rootNav->parent();
2456 while ((p->section() & Entry::SCOPE_MASK))
2457 {
2458 QCString scopeName = p->name();
2459 if (!scopeName.isEmpty())
2460 {
2461 scope.prepend(scopeName);
2462 break;
2463 }
2464 p=p->parent();
2465 }
2466
2467 MemberDef::MemberType mtype;
2468 QCString type=root->type.stripWhiteSpace();
2469 ClassDef *cd=0;
2470 bool isRelated=FALSE;
2471 bool isMemberOf=FALSE;
2472
2473 QCString classScope=stripAnonymousNamespaceScope(scope);
2474 classScope=stripTemplateSpecifiersFromScope(classScope,FALSE);
2475 QCString annScopePrefix=scope.left(scope.length()-classScope.length());
2476
2477 if (root->name.findRev("::")!=-1)
2478 {
2479 if (root->type=="friend class" || root->type=="friend struct" ||
2480 root->type=="friend union")
2481 {
2482 cd=getClass(scope);
2483 if (cd)
2484 {
2485 addVariableToClass(rootNav, // entry
2486 cd, // class to add member to
2487 MemberDef::Friend, // type of member
2488 name, // name of the member
2489 FALSE, // from Anonymous scope
2490 0, // anonymous member
2491 Public, // protection
2492 Member // related to a class
2493 );
2494 }
2495 }
2496 goto nextMember;
2497 /* skip this member, because it is a
2498 * static variable definition (always?), which will be
2499 * found in a class scope as well, but then we know the
2500 * correct protection level, so only then it will be
2501 * inserted in the correct list!
2502 */
2503 }
2504
2505 if (type=="@")
2506 mtype=MemberDef::EnumValue;
2507 else if (type.left(8)=="typedef ")
2508 mtype=MemberDef::Typedef;
2509 else if (type.left(7)=="friend ")
2510 mtype=MemberDef::Friend;
2511 else if (root->mtype==Property)
2512 mtype=MemberDef::Property;
2513 else if (root->mtype==Event)
2514 mtype=MemberDef::Event;
2515 else
2516 mtype=MemberDef::Variable;
2517
2518 if (!root->relates.isEmpty()) // related variable
2519 {
2520 isRelated=TRUE;
2521 isMemberOf=(root->relatesType == MemberOf);
2522 if (getClass(root->relates)==0 && !scope.isEmpty())
2523 scope=mergeScopes(scope,root->relates);
2524 else
2525 scope=root->relates;
2526 }
2527
2528 cd=getClass(scope);
2529 if (cd==0 && classScope!=scope) cd=getClass(classScope);
2530 if (cd)
2531 {
2532 MemberDef *md=0;
2533
2534 // if cd is an anonymous scope we insert the member
2535 // into a non-anonymous scope as well. This is needed to
2536 // be able to refer to it using \var or \fn
2537
2538 //int indentDepth=0;
2539 int si=scope.find('@');
2540 //int anonyScopes = 0;
2541 bool added=FALSE;
2542
2543 if (si!=-1) // anonymous scope
2544 {
2545 QCString pScope;
2546 ClassDef *pcd=0;
2547 pScope = scope.left(QMAX(si-2,0));
2548 if (!pScope.isEmpty())
2549 pScope.prepend(annScopePrefix);
2550 else if (annScopePrefix.length()>2)
2551 pScope=annScopePrefix.left(annScopePrefix.length()-2);
2552 if (name.at(0)!='@')
2553 {
2554 if (!pScope.isEmpty() && (pcd=getClass(pScope)))
2555 {
2556 md=addVariableToClass(rootNav, // entry
2557 pcd, // class to add member to
2558 mtype, // member type
2559 name, // member name
2560 TRUE, // from anonymous scope
2561 0, // from anonymous member
2562 root->protection,
2563 isMemberOf ? Foreign : isRelated ? Related : Member
2564 );
2565 added=TRUE;
2566 }
2567 else // anonymous scope inside namespace or file => put variable in the global scope
2568 {
2569 if (mtype==MemberDef::Variable)
2570 {
2571 md=addVariableToFile(rootNav,mtype,pScope,name,TRUE,0);
2572 }
2573 added=TRUE;
2574 }
2575 }
2576 }
2577
2578 //printf("name=`%s' scope=%s scope.right=%s\n",
2579 // name.data(),scope.data(),
2580 // scope.right(scope.length()-si).data());
2581 addVariableToClass(rootNav, // entry
2582 cd, // class to add member to
2583 mtype, // member type
2584 name, // name of the member
2585 FALSE, // from anonymous scope
2586 md, // from anonymous member
2587 root->protection,
2588 isMemberOf ? Foreign : isRelated ? Related : Member);
2589 }
2590 else if (!name.isEmpty()) // global variable
2591 {
2592 //printf("Inserting member in global scope %s!\n",scope.data());
2593 addVariableToFile(rootNav,mtype,scope,name,FALSE,/*0,*/0);
2594 }
2595
2596nextMember:
2597 rootNav->releaseEntry();
2598}
2599
2600//----------------------------------------------------------------------
2601// Searches the Entry tree for typedef documentation sections.
2602// If found they are stored in their class or in the global list.
2603static void buildTypedefList(EntryNav *rootNav)
2604{
2605 //printf("buildVarList(%s)\n",rootNav->name().data());
2606 if (!rootNav->name().isEmpty() &&
2607 rootNav->section()==Entry::VARIABLE_SEC &&
2608 rootNav->type().find("typedef ")!=-1 // its a typedef
2609 )
2610 {
2611 addVariable(rootNav);
2612 }
2613 if (rootNav->children())
2614 {
2615 EntryNavListIterator eli(*rootNav->children());
2616 EntryNav *e;
2617 for (;(e=eli.current());++eli)
2618 {
2619 if (e->section()!=Entry::ENUM_SEC)
2620 {
2621 buildTypedefList(e);
2622 }
2623 }
2624 }
2625}
2626
2627//----------------------------------------------------------------------
2628// Searches the Entry tree for Variable documentation sections.
2629// If found they are stored in their class or in the global list.
2630
2631static void buildVarList(EntryNav *rootNav)
2632{
2633 //printf("buildVarList(%s)\n",rootNav->name().data());
2634 int isFuncPtr=-1;
2635 if (!rootNav->name().isEmpty() &&
2636 (rootNav->type().isEmpty() || g_compoundKeywordDict.find(rootNav->type())==0) &&
2637 (
2638 (rootNav->section()==Entry::VARIABLE_SEC // it's a variable
2639 ) ||
2640 (rootNav->section()==Entry::FUNCTION_SEC && // or maybe a function pointer variable
2641 (isFuncPtr=findFunctionPtr(rootNav->type(),rootNav->lang()))!=-1
2642 ) ||
2643 (rootNav->section()==Entry::FUNCTION_SEC && // class variable initialized by constructor
2644 isVarWithConstructor(rootNav)
2645 )
2646 )
2647 ) // documented variable
2648 {
2649 addVariable(rootNav,isFuncPtr);
2650 }
2651 if (rootNav->children())
2652 {
2653 EntryNavListIterator eli(*rootNav->children());
2654 EntryNav *e;
2655 for (;(e=eli.current());++eli)
2656 {
2657 if (e->section()!=Entry::ENUM_SEC)
2658 {
2659 buildVarList(e);
2660 }
2661 }
2662 }
2663}
2664
2665//----------------------------------------------------------------------
2666// Searches the Entry tree for Function sections.
2667// If found they are stored in their class or in the global list.
2668
2669static void addMethodToClass(EntryNav *rootNav,ClassDef *cd,
2670 const QCString &rname,bool isFriend)
2671{
2672 Entry *root = rootNav->entry();
2673 FileDef *fd=rootNav->fileDef();
2674
2675 int l,i=-1;
2676 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
2677
2678 if (!root->type.isEmpty() && (i=re.match(root->type,0,&l))!=-1) // function variable
2679 {
2680 root->args+=root->type.right(root->type.length()-i-l);
2681 root->type=root->type.left(i+l);
2682 }
2683
2684 QCString name=removeRedundantWhiteSpace(rname);
2685 if (name.left(2)=="::") name=name.right(name.length()-2);
2686
2687 MemberDef::MemberType mtype;
2688 if (isFriend) mtype=MemberDef::Friend;
2689 else if (root->mtype==Signal) mtype=MemberDef::Signal;
2690 else if (root->mtype==Slot) mtype=MemberDef::Slot;
2691 else if (root->mtype==DCOP) mtype=MemberDef::DCOP;
2692 else mtype=MemberDef::Function;
2693
2694 // strip redundant template specifier for constructors
2695 if ((fd==0 || getLanguageFromFileName(fd->name())==SrcLangExt_Cpp) &&
2696 name.left(9)!="operator " && (i=name.find('<'))!=-1 && name.find('>')!=-1)
2697 {
2698 name=name.left(i);
2699 }
2700
2701 //printf("root->name=`%s; root->args=`%s' root->argList=`%s'\n",
2702 // root->name.data(),root->args.data(),argListToString(root->argList).data()
2703 // );
2704
2705 // adding class member
2706 MemberDef *md=new MemberDef(
2707 root->fileName,root->startLine,
2708 root->type,name,root->args,root->exception,
2709 root->protection,root->virt,
2710 root->stat && root->relatesType != MemberOf,
2711 root->relates.isEmpty() ? Member :
2712 root->relatesType == MemberOf ? Foreign : Related,
2713 mtype,root->tArgLists ? root->tArgLists->last() : 0,root->argList);
2714 md->setTagInfo(rootNav->tagInfo());
2715 md->setMemberClass(cd);
2716 md->setDocumentation(root->doc,root->docFile,root->docLine);
2717 md->setDocsForDefinition(!root->proto);
2718 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
2719 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
2720 md->setBodySegment(root->bodyLine,root->endBodyLine);
2721 md->setMemberSpecifiers(root->spec);
2722 md->setMemberGroupId(root->mGrpId);
2723 md->setTypeConstraints(root->typeConstr);
2724 md->setBodyDef(fd);
2725 md->setFileDef(fd);
2726 //md->setScopeTemplateArguments(root->tArgList);
2727 md->addSectionsToDefinition(root->anchors);
2728 QCString def;
2729 QCString qualScope = cd->qualifiedNameWithTemplateParameters();
2730 QCString scopeSeparator="::";
2731 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
2732 {
2733 qualScope = substitute(qualScope,"::",".");
2734 scopeSeparator=".";
2735 }
2736 if (!root->relates.isEmpty() || isFriend || Config_getBool("HIDE_SCOPE_NAMES"))
2737 {
2738 if (!root->type.isEmpty())
2739 {
2740 if (root->argList)
2741 {
2742 def=root->type+" "+name;
2743 }
2744 else
2745 {
2746 def=root->type+" "+name+root->args;
2747 }
2748 }
2749 else
2750 {
2751 if (root->argList)
2752 {
2753 def=name;
2754 }
2755 else
2756 {
2757 def=name+root->args;
2758 }
2759 }
2760 }
2761 else
2762 {
2763 if (!root->type.isEmpty())
2764 {
2765 if (root->argList)
2766 {
2767 def=root->type+" "+qualScope+scopeSeparator+name;
2768 }
2769 else
2770 {
2771 def=root->type+" "+qualScope+scopeSeparator+name+root->args;
2772 }
2773 }
2774 else
2775 {
2776 if (root->argList)
2777 {
2778 def=qualScope+scopeSeparator+name;
2779 }
2780 else
2781 {
2782 def=qualScope+scopeSeparator+name+root->args;
2783 }
2784 }
2785 }
2786 if (def.left(7)=="friend ") def=def.right(def.length()-7);
2787 md->setDefinition(def);
2788 md->enableCallGraph(root->callGraph);
2789 md->enableCallerGraph(root->callerGraph);
2790
2791 Debug::print(Debug::Functions,0,
2792 " Func Member:\n"
2793 " `%s' `%s'::`%s' `%s' proto=%d\n"
2794 " def=`%s'\n",
2795 root->type.data(),
2796 qualScope.data(),
2797 rname.data(),
2798 root->args.data(),
2799 root->proto,
2800 def.data()
2801 );
2802
2803 // add member to the global list of all members
2804 //printf("Adding member=%s class=%s\n",md->name().data(),cd->name().data());
2805 MemberName *mn;
2806 if ((mn=Doxygen::memberNameSDict->find(name)))
2807 {
2808 mn->append(md);
2809 }
2810 else
2811 {
2812 mn = new MemberName(name);
2813 mn->append(md);
2814 Doxygen::memberNameSDict->append(name,mn);
2815 }
2816
2817 // add member to the class cd
2818 cd->insertMember(md);
2819 // add file to list of used files
2820 cd->insertUsedFile(root->fileName);
2821
2822 addMemberToGroups(root,md);
2823 rootNav->changeSection(Entry::EMPTY_SEC);
2824 md->setRefItems(root->sli);
2825}
2826
2827
2828static void buildFunctionList(EntryNav *rootNav)
2829{
2830 if (rootNav->section()==Entry::FUNCTION_SEC)
2831 {
2832 rootNav->loadEntry(g_storage);
2833 Entry *root = rootNav->entry();
2834
2835 Debug::print(Debug::Functions,0,
2836 "FUNCTION_SEC:\n"
2837 " `%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",
2838 root->type.data(),
2839 rootNav->parent()->name().data(),
2840 root->name.data(),
2841 root->args.data(),
2842 root->relates.data(),
2843 root->relatesType,
2844 root->fileName.data(),
2845 root->startLine,
2846 root->bodyLine,
2847 root->tArgLists ? (int)root->tArgLists->count() : -1,
2848 root->mGrpId,
2849 root->spec,
2850 root->proto,
2851 root->docFile.data()
2852 );
2853
2854 bool isFriend=root->type.find("friend ")!=-1;
2855 QCString rname = removeRedundantWhiteSpace(root->name);
2856 //printf("rname=%s\n",rname.data());
2857
2858 QCString scope=rootNav->parent()->name(); //stripAnonymousNamespaceScope(root->parent->name);
2859 if (!rname.isEmpty() && scope.find('@')==-1)
2860 {
2861 ClassDef *cd=0;
2862 // check if this function's parent is a class
2863 scope=stripTemplateSpecifiersFromScope(scope,FALSE);
2864
2865 FileDef *rfd=rootNav->fileDef();
2866
2867 int memIndex=rname.findRev("::");
2868
2869 cd=getClass(scope);
2870 if (cd && scope+"::"==rname.left(scope.length()+2)) // found A::f inside A
2871 {
2872 // strip scope from name
2873 rname=rname.right(rname.length()-rootNav->parent()->name().length()-2);
2874 }
2875
2876 NamespaceDef *nd = 0;
2877 bool isMember=FALSE;
2878 if (memIndex!=-1)
2879 {
2880 int ts=rname.find('<');
2881 int te=rname.find('>');
2882 if (memIndex>0 && (ts==-1 || te==-1))
2883 {
2884 // note: the following code was replaced by inMember=TRUE to deal with a
2885 // function rname='X::foo' of class X inside a namespace also called X...
2886 // bug id 548175
2887 //nd = Doxygen::namespaceSDict->find(rname.left(memIndex));
2888 //isMember = nd==0;
2889 //if (nd)
2890 //{
2891 // // strip namespace scope from name
2892 // scope=rname.left(memIndex);
2893 // rname=rname.right(rname.length()-memIndex-2);
2894 //}
2895 isMember = TRUE;
2896 }
2897 else
2898 {
2899 isMember=memIndex<ts || memIndex>te;
2900 }
2901 }
2902
2903 static QRegExp re("([a-z_A-Z0-9: ]*[ &*]+[ ]*");
2904 if (!rootNav->parent()->name().isEmpty() &&
2905 (rootNav->parent()->section() & Entry::COMPOUND_MASK) &&
2906 cd &&
2907 // do some fuzzy things to exclude function pointers
2908 (root->type.isEmpty() ||
2909 (root->type.find(re,0)==-1 || root->args.find(")[")!=-1) || // type contains ..(..* and args not )[.. -> function pointer
2910 root->type.find(")(")!=-1 || root->type.find("operator")!=-1 // type contains ..)(.. and not "operator"
2911 )
2912 )
2913 {
2914 Debug::print(Debug::Functions,0," --> member %s of class %s!\n",
2915 rname.data(),cd->name().data());
2916 addMethodToClass(rootNav,cd,rname,isFriend);
2917 }
2918 else if (!((rootNav->parent()->section() & Entry::COMPOUND_MASK)
2919 || rootNav->parent()->section()==Entry::OBJCIMPL_SEC
2920 ) &&
2921 !isMember &&
2922 (root->relates.isEmpty() || root->relatesType == Duplicate) &&
2923 root->type.left(7)!="extern " && root->type.left(8)!="typedef "
2924 )
2925 // no member => unrelated function
2926 {
2927 /* check the uniqueness of the function name in the file.
2928 * A file could contain a function prototype and a function definition
2929 * or even multiple function prototypes.
2930 */
2931 bool found=FALSE;
2932 MemberName *mn;
2933 MemberDef *md=0;
2934 if ((mn=Doxygen::functionNameSDict->find(rname)))
2935 {
2936 Debug::print(Debug::Functions,0," --> function %s already found!\n",rname.data());
2937 MemberNameIterator mni(*mn);
2938 for (mni.toFirst();(!found && (md=mni.current()));++mni)
2939 {
2940 NamespaceDef *mnd = md->getNamespaceDef();
2941 NamespaceDef *rnd = 0;
2942 //printf("root namespace=%s\n",rootNav->parent()->name().data());
2943 QCString fullScope = scope;
2944 QCString parentScope = rootNav->parent()->name();
2945 if (!parentScope.isEmpty() && !leftScopeMatch(parentScope,scope))
2946 {
2947 if (!scope.isEmpty()) fullScope.prepend("::");
2948 fullScope.prepend(parentScope);
2949 }
2950 //printf("fullScope=%s\n",fullScope.data());
2951 rnd = getResolvedNamespace(fullScope);
2952 FileDef *mfd = md->getFileDef();
2953 QCString nsName,rnsName;
2954 if (mnd) nsName = mnd->name().copy();
2955 if (rnd) rnsName = rnd->name().copy();
2956 //printf("matching arguments for %s%s %s%s\n",
2957 // md->name().data(),md->argsString(),rname.data(),argListToString(root->argList).data());
2958 LockingPtr<ArgumentList> mdAl = md->argumentList();
2959 LockingPtr<ArgumentList> mdTempl = md->templateArguments();
2960
2961 // in case of template functions, we need to check if the
2962 // functions have the same number of template parameters
2963 bool sameNumTemplateArgs = TRUE;
2964 if (mdTempl!=0 && root->tArgLists)
2965 {
2966 if (mdTempl->count()!=root->tArgLists->getLast()->count())
2967 {
2968 sameNumTemplateArgs = FALSE;
2969 }
2970 }
2971 if (
2972 matchArguments2(md->getOuterScope(),mfd,mdAl.pointer(),
2973 rnd ? rnd : Doxygen::globalScope,rfd,root->argList,
2974 FALSE) &&
2975 sameNumTemplateArgs
2976 )
2977 {
2978 GroupDef *gd=0;
2979 if (root->groups->first()!=0)
2980 {
2981 gd = Doxygen::groupSDict->find(root->groups->first()->groupname.data());
2982 }
2983 //printf("match!\n");
2984 //printf("mnd=%p rnd=%p nsName=%s rnsName=%s\n",mnd,rnd,nsName.data(),rnsName.data());
2985 // see if we need to create a new member
2986 found=(mnd && rnd && nsName==rnsName) || // members are in the same namespace
2987 ((mnd==0 && rnd==0 && mfd!=0 && // no external reference and
2988 mfd->absFilePath()==root->fileName // prototype in the same file
2989 )
2990 );
2991 // otherwise, allow a duplicate global member with the same argument list
2992 if (!found && gd && gd==md->getGroupDef())
2993 {
2994 // member is already in the group, so we don't want to add it again.
2995 found=TRUE;
2996 }
2997
2998 //printf("combining function with prototype found=%d in namespace %s\n",
2999 // found,nsName.data());
3000
3001 if (found)
3002 {
3003 // merge argument lists
3004 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
3005 // merge documentation
3006 if (md->documentation().isEmpty() && !root->doc.isEmpty())
3007 {
3008 ArgumentList *argList = new ArgumentList;
3009 stringToArgumentList(root->args,argList);
3010 if (root->proto)
3011 {
3012 //printf("setDeclArgumentList to %p\n",argList);
3013 md->setDeclArgumentList(argList);
3014 }
3015 else
3016 {
3017 md->setArgumentList(argList);
3018 }
3019 }
3020
3021 md->setDocumentation(root->doc,root->docFile,root->docLine);
3022 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3023 md->setDocsForDefinition(!root->proto);
3024 if (md->getStartBodyLine()!=-1 && md->getStartBodyLine()==-1)
3025 {
3026 md->setBodySegment(root->bodyLine,root->endBodyLine);
3027 md->setBodyDef(rfd);
3028 }
3029
3030 if (md->briefDescription().isEmpty() && !root->brief.isEmpty())
3031 {
3032 md->setArgsString(root->args);
3033 }
3034 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3035
3036 md->addSectionsToDefinition(root->anchors);
3037
3038 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
3039 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
3040
3041 // merge ingroup specifiers
3042 if (md->getGroupDef()==0 && root->groups->first()!=0)
3043 {
3044 addMemberToGroups(root,md);
3045 }
3046 else if (md->getGroupDef()!=0 && root->groups->count()==0)
3047 {
3048 //printf("existing member is grouped, new member not\n");
3049 root->groups->append(new Grouping(md->getGroupDef()->name(), md->getGroupPri()));
3050 }
3051 else if (md->getGroupDef()!=0 && root->groups->first()!=0)
3052 {
3053 //printf("both members are grouped\n");
3054 }
3055
3056 // if md is a declaration and root is the corresponding
3057 // definition, then turn md into a definition.
3058 if (md->isPrototype() && !root->proto)
3059 {
3060 md->setPrototype(FALSE);
3061 }
3062 }
3063 }
3064 }
3065 }
3066 if (!found) /* global function is unique with respect to the file */
3067 {
3068 Debug::print(Debug::Functions,0," --> new function %s found!\n",rname.data());
3069 //printf("New function type=`%s' name=`%s' args=`%s' bodyLine=%d\n",
3070 // root->type.data(),rname.data(),root->args.data(),root->bodyLine);
3071
3072 // new global function
3073 ArgumentList *tArgList = root->tArgLists ? root->tArgLists->last() : 0;
3074 QCString name=removeRedundantWhiteSpace(rname);
3075 md=new MemberDef(
3076 root->fileName,root->startLine,
3077 root->type,name,root->args,root->exception,
3078 root->protection,root->virt,root->stat,Member,
3079 MemberDef::Function,tArgList,root->argList);
3080
3081 md->setTagInfo(rootNav->tagInfo());
3082 //md->setDefFile(root->fileName);
3083 //md->setDefLine(root->startLine);
3084 md->setDocumentation(root->doc,root->docFile,root->docLine);
3085 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
3086 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
3087 md->setPrototype(root->proto);
3088 md->setDocsForDefinition(!root->proto);
3089 md->setTypeConstraints(root->typeConstr);
3090 //md->setBody(root->body);
3091 md->setBodySegment(root->bodyLine,root->endBodyLine);
3092 FileDef *fd=rootNav->fileDef();
3093 md->setBodyDef(fd);
3094 md->addSectionsToDefinition(root->anchors);
3095 md->setMemberSpecifiers(root->spec);
3096 md->setMemberGroupId(root->mGrpId);
3097
3098 // see if the function is inside a namespace that was not part of
3099 // the name already (in that case nd should be non-zero already)
3100 if (nd==0 && rootNav->parent()->section() == Entry::NAMESPACE_SEC )
3101 {
3102 //QCString nscope=removeAnonymousScopes(rootNav->parent()->name());
3103 QCString nscope=rootNav->parent()->name();
3104 if (!nscope.isEmpty())
3105 {
3106 nd = getResolvedNamespace(nscope);
3107 }
3108 }
3109
3110 if (!scope.isEmpty())
3111 {
3112 if (Config_getBool("OPTIMIZE_OUTPUT_JAVA"))
3113 {
3114 scope = substitute(scope,"::",".")+".";
3115 }
3116 else
3117 {
3118 scope+="::";
3119 }
3120 }
3121
3122 QCString def;
3123 if (!root->type.isEmpty())
3124 {
3125 if (root->argList)
3126 {
3127 def=root->type+" "+scope+name;
3128 }
3129 else
3130 {
3131 def=root->type+" "+scope+name+root->args;
3132 }
3133 }
3134 else
3135 {
3136 if (root->argList)
3137 {
3138 def=scope+name.copy();
3139 }
3140 else
3141 {
3142 def=scope+name+root->args;
3143 }
3144 }
3145 Debug::print(Debug::Functions,0,
3146 " Global Function:\n"
3147 " `%s' `%s'::`%s' `%s' proto=%d\n"
3148 " def=`%s'\n",
3149 root->type.data(),
3150 rootNav->parent()->name().data(),
3151 rname.data(),
3152 root->args.data(),
3153 root->proto,
3154 def.data()
3155 );
3156 md->setDefinition(def);
3157 md->enableCallGraph(root->callGraph);
3158 md->enableCallerGraph(root->callerGraph);
3159 //if (root->mGrpId!=-1)
3160 //{
3161 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
3162 //}
3163
3164 md->setRefItems(root->sli);
3165 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
3166 {
3167 // add member to namespace
3168 md->setNamespace(nd);
3169 nd->insertMember(md);
3170 }
3171 if (fd)
3172 {
3173 // add member to the file (we do this even if we have already
3174 // inserted it into the namespace)
3175 md->setFileDef(fd);
3176 fd->insertMember(md);
3177 }
3178
3179 // add member to the list of file members
3180 //printf("Adding member=%s\n",md->name().data());
3181 MemberName *mn;
3182 if ((mn=Doxygen::functionNameSDict->find(name)))
3183 {
3184 mn->append(md);
3185 }
3186 else
3187 {
3188 mn = new MemberName(name);
3189 mn->append(md);
3190 Doxygen::functionNameSDict->append(name,mn);
3191 }
3192 addMemberToGroups(root,md);
3193 if (root->relatesType == Simple) // if this is a relatesalso command,
3194 // allow find Member to pick it up
3195 {
3196 rootNav->changeSection(Entry::EMPTY_SEC); // Otherwise we have finished
3197 // with this entry.
3198
3199 }
3200 }
3201 else
3202 {
3203 FileDef *fd=rootNav->fileDef();
3204 if (fd)
3205 {
3206 // add member to the file (we do this even if we have already
3207 // inserted it into the namespace)
3208 fd->insertMember(md);
3209 }
3210 }
3211
3212 //printf("unrelated function %d `%s' `%s' `%s'\n",
3213 // root->parent->section,root->type.data(),rname.data(),root->args.data());
3214 }
3215 else
3216 {
3217 Debug::print(Debug::Functions,0," --> %s not processed!\n",rname.data());
3218 }
3219 }
3220 else if (rname.isEmpty())
3221 {
3222 warn(root->fileName,root->startLine,
3223 "warning: Illegal member name found."
3224 );
3225 }
3226
3227 rootNav->releaseEntry();
3228 }
3229 RECURSE_ENTRYTREE(buildFunctionList,rootNav);
3230}
3231
3232//----------------------------------------------------------------------
3233
3234static void findFriends()
3235{
3236 //printf("findFriends()\n");
3237 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
3238 MemberName *fn;
3239 for (;(fn=fnli.current());++fnli) // for each global function name
3240 {
3241 //printf("Function name=`%s'\n",fn->memberName());
3242 MemberName *mn;
3243 if ((mn=Doxygen::memberNameSDict->find(fn->memberName())))
3244 { // there are members with the same name
3245 //printf("Function name is also a member name\n");
3246 MemberNameIterator fni(*fn);
3247 MemberDef *fmd;
3248 for (;(fmd=fni.current());++fni) // for each function with that name
3249 {
3250 MemberNameIterator mni(*mn);
3251 MemberDef *mmd;
3252 for (;(mmd=mni.current());++mni) // for each member with that name
3253 {
3254 //printf("Checking for matching arguments
3255 // mmd->isRelated()=%d mmd->isFriend()=%d mmd->isFunction()=%d\n",
3256 // mmd->isRelated(),mmd->isFriend(),mmd->isFunction());
3257 LockingPtr<ArgumentList> mmdAl = mmd->argumentList();
3258 LockingPtr<ArgumentList> fmdAl = fmd->argumentList();
3259 if ((mmd->isFriend() || (mmd->isRelated() && mmd->isFunction())) &&
3260 matchArguments2(mmd->getOuterScope(), mmd->getFileDef(), mmdAl.pointer(),
3261 fmd->getOuterScope(), fmd->getFileDef(), fmdAl.pointer(),
3262 TRUE
3263 )
3264
3265 ) // if the member is related and the arguments match then the
3266 // function is actually a friend.
3267 {
3268 mergeArguments(mmdAl.pointer(),fmdAl.pointer());
3269 if (!fmd->documentation().isEmpty())
3270 {
3271 mmd->setDocumentation(fmd->documentation(),fmd->docFile(),fmd->docLine());
3272 }
3273 else if (!mmd->documentation().isEmpty())
3274 {
3275 fmd->setDocumentation(mmd->documentation(),mmd->docFile(),mmd->docLine());
3276 }
3277 if (mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3278 {
3279 mmd->setBriefDescription(fmd->briefDescription(),fmd->briefFile(),fmd->briefLine());
3280 }
3281 else if (!mmd->briefDescription().isEmpty() && !fmd->briefDescription().isEmpty())
3282 {
3283 fmd->setBriefDescription(mmd->briefDescription(),mmd->briefFile(),mmd->briefLine());
3284 }
3285 if (!fmd->inbodyDocumentation().isEmpty())
3286 {
3287 mmd->setInbodyDocumentation(fmd->inbodyDocumentation(),fmd->inbodyFile(),fmd->inbodyLine());
3288 }
3289 else if (!mmd->inbodyDocumentation().isEmpty())
3290 {
3291 fmd->setInbodyDocumentation(mmd->inbodyDocumentation(),mmd->inbodyFile(),mmd->inbodyLine());
3292 }
3293 //printf("body mmd %d fmd %d\n",mmd->getStartBodyLine(),fmd->getStartBodyLine());
3294 if (mmd->getStartBodyLine()==-1 && fmd->getStartBodyLine()!=-1)
3295 {
3296 mmd->setBodySegment(fmd->getStartBodyLine(),fmd->getEndBodyLine());
3297 mmd->setBodyDef(fmd->getBodyDef());
3298 //mmd->setBodyMember(fmd);
3299 }
3300 else if (mmd->getStartBodyLine()!=-1 && fmd->getStartBodyLine()==-1)
3301 {
3302 fmd->setBodySegment(mmd->getStartBodyLine(),mmd->getEndBodyLine());
3303 fmd->setBodyDef(mmd->getBodyDef());
3304 //fmd->setBodyMember(mmd);
3305 }
3306 mmd->setDocsForDefinition(fmd->isDocsForDefinition());
3307
3308 mmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3309 mmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3310 fmd->enableCallGraph(mmd->hasCallGraph() || fmd->hasCallGraph());
3311 fmd->enableCallerGraph(mmd->hasCallerGraph() || fmd->hasCallerGraph());
3312 }
3313 }
3314 }
3315 }
3316 }
3317}
3318
3319//----------------------------------------------------------------------
3320
3321static void transferArgumentDocumentation(ArgumentList *decAl,ArgumentList *defAl)
3322{
3323 if (decAl && defAl)
3324 {
3325 ArgumentListIterator decAli(*decAl);
3326 ArgumentListIterator defAli(*defAl);
3327 Argument *decA,*defA;
3328 for (decAli.toFirst(),defAli.toFirst();
3329 (decA=decAli.current()) && (defA=defAli.current());
3330 ++decAli,++defAli)
3331 {
3332 //printf("Argument decA->name=%s (doc=%s) defA->name=%s (doc=%s)\n",
3333 // decA->name.data(),decA->docs.data(),
3334 // defA->name.data(),defA->docs.data()
3335 // );
3336 if (decA->docs.isEmpty() && !defA->docs.isEmpty())
3337 {
3338 decA->docs = defA->docs.copy();
3339 }
3340 else if (defA->docs.isEmpty() && !decA->docs.isEmpty())
3341 {
3342 defA->docs = decA->docs.copy();
3343 }
3344 }
3345 }
3346}
3347
3348static void transferFunctionDocumentation()
3349{
3350 //printf("---- transferFunctionDocumentation()\n");
3351
3352 // find matching function declaration and definitions.
3353 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3354 MemberName *mn;
3355 for (;(mn=mnli.current());++mnli)
3356 {
3357 //printf("memberName=%s count=%d\n",mn->memberName(),mn->count());
3358 MemberDef *mdef=0,*mdec=0;
3359 MemberNameIterator mni1(*mn);
3360 /* find a matching function declaration and definition for this function */
3361 for (;(mdec=mni1.current());++mni1)
3362 {
3363 //printf("mdec=%s isPrototype()=%d\n",mdec->name().data(),mdec->isPrototype());
3364 if (mdec->isPrototype() ||
3365 (mdec->isVariable() && mdec->isExternal())
3366 )
3367 {
3368 MemberNameIterator mni2(*mn);
3369 for (;(mdef=mni2.current());++mni2)
3370 {
3371 if (
3372 (mdef->isFunction() && !mdef->isStatic() && !mdef->isPrototype()) ||
3373 (mdef->isVariable() && !mdef->isExternal() && !mdef->isStatic())
3374 )
3375 {
3376 //printf("mdef=(%p,%s) mdec=(%p,%s)\n",
3377 // mdef, mdef ? mdef->name().data() : "",
3378 // mdec, mdec ? mdec->name().data() : "");
3379
3380 LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
3381 LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
3382 if (matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
3383 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
3384 TRUE
3385 )
3386 ) /* match found */
3387 {
3388 //printf("Found member %s: definition in %s (doc=`%s') and declaration in %s (doc=`%s')\n",
3389 // mn->memberName(),
3390 // mdef->getFileDef()->name().data(),mdef->documentation().data(),
3391 // mdec->getFileDef()->name().data(),mdec->documentation().data()
3392 // );
3393
3394 // first merge argument documentation
3395 transferArgumentDocumentation(mdecAl.pointer(),mdefAl.pointer());
3396
3397 /* copy documentation between function definition and declaration */
3398 if (!mdec->briefDescription().isEmpty())
3399 {
3400 mdef->setBriefDescription(mdec->briefDescription(),mdec->briefFile(),mdec->briefLine());
3401 }
3402 else if (!mdef->briefDescription().isEmpty())
3403 {
3404 mdec->setBriefDescription(mdef->briefDescription(),mdef->briefFile(),mdef->briefLine());
3405 }
3406 if (!mdef->documentation().isEmpty())
3407 {
3408 //printf("transfering docs mdef->mdec (%s->%s)\n",mdef->argsString(),mdec->argsString());
3409 mdec->setDocumentation(mdef->documentation(),mdef->docFile(),mdef->docLine());
3410 mdec->setDocsForDefinition(mdef->isDocsForDefinition());
3411 if (mdefAl!=0)
3412 {
3413 ArgumentList *mdefAlComb = new ArgumentList;
3414 stringToArgumentList(mdef->argsString(),mdefAlComb);
3415 transferArgumentDocumentation(mdefAl.pointer(),mdefAlComb);
3416 mdec->setArgumentList(mdefAlComb);
3417 }
3418 }
3419 else if (!mdec->documentation().isEmpty())
3420 {
3421 //printf("transfering docs mdec->mdef (%s->%s)\n",mdec->argsString(),mdef->argsString());
3422 mdef->setDocumentation(mdec->documentation(),mdec->docFile(),mdec->docLine());
3423 mdef->setDocsForDefinition(mdec->isDocsForDefinition());
3424 if (mdecAl!=0)
3425 {
3426 ArgumentList *mdecAlComb = new ArgumentList;
3427 stringToArgumentList(mdec->argsString(),mdecAlComb);
3428 transferArgumentDocumentation(mdecAl.pointer(),mdecAlComb);
3429 mdef->setDeclArgumentList(mdecAlComb);
3430 }
3431 }
3432 if (!mdef->inbodyDocumentation().isEmpty())
3433 {
3434 mdec->setInbodyDocumentation(mdef->inbodyDocumentation(),mdef->inbodyFile(),mdef->inbodyLine());
3435 }
3436 else if (!mdec->inbodyDocumentation().isEmpty())
3437 {
3438 mdef->setInbodyDocumentation(mdec->inbodyDocumentation(),mdec->inbodyFile(),mdec->inbodyLine());
3439 }
3440 if (mdec->getStartBodyLine()!=-1 && mdef->getStartBodyLine()==-1)
3441 {
3442 //printf("body mdec->mdef %d-%d\n",mdec->getStartBodyLine(),mdef->getEndBodyLine());
3443 mdef->setBodySegment(mdec->getStartBodyLine(),mdec->getEndBodyLine());
3444 mdef->setBodyDef(mdec->getBodyDef());
3445 //mdef->setBodyMember(mdec);
3446 }
3447 else if (mdef->getStartBodyLine()!=-1 && mdec->getStartBodyLine()==-1)
3448 {
3449 //printf("body mdef->mdec %d-%d\n",mdef->getStartBodyLine(),mdec->getEndBodyLine());
3450 mdec->setBodySegment(mdef->getStartBodyLine(),mdef->getEndBodyLine());
3451 mdec->setBodyDef(mdef->getBodyDef());
3452 //mdec->setBodyMember(mdef);
3453 }
3454 mdec->mergeMemberSpecifiers(mdef->getMemberSpecifiers());
3455 mdef->mergeMemberSpecifiers(mdec->getMemberSpecifiers());
3456
3457
3458 // copy group info.
3459 if (mdec->getGroupDef()==0 && mdef->getGroupDef()!=0)
3460 {
3461 mdec->setGroupDef(mdef->getGroupDef(),
3462 mdef->getGroupPri(),
3463 mdef->docFile(),
3464 mdef->docLine(),
3465 mdef->hasDocumentation(),
3466 mdef
3467 );
3468 }
3469 else if (mdef->getGroupDef()==0 && mdec->getGroupDef()!=0)
3470 {
3471 mdef->setGroupDef(mdec->getGroupDef(),
3472 mdec->getGroupPri(),
3473 mdec->docFile(),
3474 mdec->docLine(),
3475 mdec->hasDocumentation(),
3476 mdec
3477 );
3478 }
3479
3480
3481 mdec->mergeRefItems(mdef);
3482 mdef->mergeRefItems(mdec);
3483
3484 mdef->setMemberDeclaration(mdec);
3485 mdec->setMemberDefinition(mdef);
3486
3487 mdef->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());
3488 mdef->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
3489 mdec->enableCallGraph(mdec->hasCallGraph() || mdef->hasCallGraph());
3490 mdec->enableCallerGraph(mdec->hasCallerGraph() || mdef->hasCallerGraph());
3491 }
3492 }
3493 }
3494 }
3495 }
3496 }
3497}
3498
3499//----------------------------------------------------------------------
3500
3501static void transferFunctionReferences()
3502{
3503 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3504 MemberName *mn;
3505 for (;(mn=mnli.current());++mnli)
3506 {
3507 MemberDef *md,*mdef=0,*mdec=0;
3508 MemberNameIterator mni(*mn);
3509 /* find a matching function declaration and definition for this function */
3510 for (;(md=mni.current());++mni)
3511 {
3512 if (md->isPrototype())
3513 mdec=md;
3514 else if (md->isVariable() && md->isExternal())
3515 mdec=md;
3516
3517 if (md->isFunction() && !md->isStatic() && !md->isPrototype())
3518 mdef=md;
3519 else if (md->isVariable() && !md->isExternal() && !md->isStatic())
3520 mdef=md;
3521 }
3522 if (mdef && mdec)
3523 {
3524 LockingPtr<ArgumentList> mdefAl = mdef->argumentList();
3525 LockingPtr<ArgumentList> mdecAl = mdec->argumentList();
3526 if (
3527 matchArguments2(mdef->getOuterScope(),mdef->getFileDef(),mdefAl.pointer(),
3528 mdec->getOuterScope(),mdec->getFileDef(),mdecAl.pointer(),
3529 TRUE
3530 )
3531 ) /* match found */
3532 {
3533 LockingPtr<MemberSDict> defDict = mdef->getReferencesMembers();
3534 LockingPtr<MemberSDict> decDict = mdec->getReferencesMembers();
3535 if (defDict!=0)
3536 {
3537 MemberSDict::Iterator msdi(*defDict);
3538 MemberDef *rmd;
3539 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3540 {
3541 if (decDict==0 || decDict->find(rmd->name())==0)
3542 {
3543 mdec->addSourceReferences(rmd);
3544 }
3545 }
3546 }
3547 if (decDict!=0)
3548 {
3549 MemberSDict::Iterator msdi(*decDict);
3550 MemberDef *rmd;
3551 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3552 {
3553 if (defDict==0 || defDict->find(rmd->name())==0)
3554 {
3555 mdef->addSourceReferences(rmd);
3556 }
3557 }
3558 }
3559
3560 defDict = mdef->getReferencedByMembers();
3561 decDict = mdec->getReferencedByMembers();
3562 if (defDict!=0)
3563 {
3564 MemberSDict::Iterator msdi(*defDict);
3565 MemberDef *rmd;
3566 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3567 {
3568 if (decDict==0 || decDict->find(rmd->name())==0)
3569 {
3570 mdec->addSourceReferencedBy(rmd);
3571 }
3572 }
3573 }
3574 if (decDict!=0)
3575 {
3576 MemberSDict::Iterator msdi(*decDict);
3577 MemberDef *rmd;
3578 for (msdi.toFirst();(rmd=msdi.current());++msdi)
3579 {
3580 if (defDict==0 || defDict->find(rmd->name())==0)
3581 {
3582 mdef->addSourceReferencedBy(rmd);
3583 }
3584 }
3585 }
3586 }
3587 }
3588 }
3589}
3590
3591//----------------------------------------------------------------------
3592
3593static void transferRelatedFunctionDocumentation()
3594{
3595 // find match between function declaration and definition for
3596 // related functions
3597 MemberNameSDict::Iterator mnli(*Doxygen::functionNameSDict);
3598 MemberName *mn;
3599 for (mnli.toFirst();(mn=mnli.current());++mnli)
3600 {
3601 MemberDef *md;
3602 MemberNameIterator mni(*mn);
3603 /* find a matching function declaration and definition for this function */
3604 for (mni.toFirst();(md=mni.current());++mni) // for each global function
3605 {
3606 //printf(" Function `%s'\n",md->name().data());
3607 MemberName *rmn;
3608 if ((rmn=Doxygen::memberNameSDict->find(md->name()))) // check if there is a member with the same name
3609 {
3610 //printf(" Member name found\n");
3611 MemberDef *rmd;
3612 MemberNameIterator rmni(*rmn);
3613 for (rmni.toFirst();(rmd=rmni.current());++rmni) // for each member with the same name
3614 {
3615 LockingPtr<ArgumentList> mdAl = md->argumentList();
3616 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
3617 //printf(" Member found: related=`%d'\n",rmd->isRelated());
3618 if ((rmd->isRelated() || rmd->isForeign()) && // related function
3619 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
3620 rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
3621 TRUE
3622 )
3623 )
3624 {
3625 //printf(" Found related member `%s'\n",md->name().data());
3626 if (rmd->relatedAlso())
3627 md->setRelatedAlso(rmd->relatedAlso());
3628 else if (rmd->isForeign())
3629 md->makeForeign();
3630 else
3631 md->makeRelated();
3632 }
3633 }
3634 }
3635 }
3636 }
3637}
3638
3639//----------------------------------------------------------------------
3640
3641/*! make a dictionary of all template arguments of class cd
3642 * that are part of the base class name.
3643 * Example: A template class A with template arguments <R,S,T>
3644 * that inherits from B<T,T,S> will have T and S in the dictionary.
3645 */
3646static QDict<int> *getTemplateArgumentsInName(ArgumentList *templateArguments,const QCString &name)
3647{
3648 QDict<int> *templateNames = new QDict<int>(17);
3649 templateNames->setAutoDelete(TRUE);
3650 static QRegExp re("[a-z_A-Z][a-z_A-Z0-9:]*");
3651 if (templateArguments)
3652 {
3653 ArgumentListIterator ali(*templateArguments);
3654 Argument *arg;
3655 int count=0;
3656 for (ali.toFirst();(arg=ali.current());++ali,count++)
3657 {
3658 int i,p=0,l;
3659 while ((i=re.match(name,p,&l))!=-1)
3660 {
3661 QCString n = name.mid(i,l);
3662 if (n==arg->name)
3663 {
3664 if (templateNames->find(n)==0)
3665 {
3666 templateNames->insert(n,new int(count));
3667 }
3668 }
3669 p=i+l;
3670 }
3671 }
3672 }
3673 return templateNames;
3674}
3675
3676/*! Searches a class from within \a context and \a cd and returns its
3677 * definition if found (otherwise 0 is returned).
3678 */
3679static ClassDef *findClassWithinClassContext(Definition *context,ClassDef *cd,const QCString &name)
3680{
3681 FileDef *fd=cd->getFileDef();
3682 ClassDef *result=0;
3683 if (context && cd!=context)
3684 {
3685 result = getResolvedClass(context,0,name,0,0,TRUE,TRUE);
3686 }
3687 if (result==0)
3688 {
3689 result = getResolvedClass(cd,fd,name,0,0,TRUE,TRUE);
3690 }
3691 if (result==0) // try direct class, needed for namespaced classes imported via tag files (see bug624095)
3692 {
3693 result = getClass(name);
3694 }
3695 //printf("** Trying to find %s within context %s class %s result=%s lookup=%p\n",
3696 // name.data(),
3697 // context ? context->name().data() : "<none>",
3698 // cd ? cd->name().data() : "<none>",
3699 // result ? result->name().data() : "<none>",
3700 // Doxygen::classSDict.find(name)
3701 // );
3702 return result;
3703}
3704
3705enum FindBaseClassRelation_Mode
3706{
3707 TemplateInstances,
3708 DocumentedOnly,
3709 Undocumented
3710};
3711
3712static bool findClassRelation(
3713 EntryNav *rootNav,
3714 Definition *context,
3715 ClassDef *cd,
3716 BaseInfo *bi,
3717 QDict<int> *templateNames,
3718 /*bool insertUndocumented*/
3719 FindBaseClassRelation_Mode mode,
3720 bool isArtificial
3721 );
3722
3723
3724static void findUsedClassesForClass(EntryNav *rootNav,
3725 Definition *context,
3726 ClassDef *masterCd,
3727 ClassDef *instanceCd,
3728 bool isArtificial,
3729 ArgumentList *actualArgs=0,
3730 QDict<int> *templateNames=0
3731 )
3732{
3733 masterCd->visited=TRUE;
3734 ArgumentList *formalArgs = masterCd->templateArguments();
3735 if (masterCd->memberNameInfoSDict())
3736 {
3737 MemberNameInfoSDict::Iterator mnili(*masterCd->memberNameInfoSDict());
3738 MemberNameInfo *mni;
3739 for (;(mni=mnili.current());++mnili)
3740 {
3741 MemberNameInfoIterator mnii(*mni);
3742 MemberInfo *mi;
3743 for (mnii.toFirst();(mi=mnii.current());++mnii)
3744 {
3745 MemberDef *md=mi->memberDef;
3746 if (md->isVariable()) // for each member variable in this class
3747 {
3748 //printf(" Found variable %s in class %s\n",md->name().data(),masterCd->name().data());
3749 QCString type=removeRedundantWhiteSpace(md->typeString());
3750 QCString typedefValue = resolveTypeDef(masterCd,type);
3751 if (!typedefValue.isEmpty())
3752 {
3753 type = typedefValue;
3754 }
3755 int pos=0;
3756 QCString usedClassName;
3757 QCString templSpec;
3758 bool found=FALSE;
3759 // the type can contain template variables, replace them if present
3760 if (actualArgs)
3761 {
3762 type = substituteTemplateArgumentsInString(type,formalArgs,actualArgs);
3763 }
3764
3765 //printf(" template substitution gives=%s\n",type.data());
3766 while (!found && extractClassNameFromType(type,pos,usedClassName,templSpec)!=-1)
3767 {
3768 // find the type (if any) that matches usedClassName
3769 ClassDef *typeCd = getResolvedClass(masterCd,
3770 masterCd->getFileDef(),
3771 usedClassName,
3772 0,0,
3773 FALSE,TRUE
3774 );
3775 //printf("====> usedClassName=%s -> typeCd=%s\n",
3776 // usedClassName.data(),typeCd?typeCd->name().data():"<none>");
3777 if (typeCd)
3778 {
3779 usedClassName = typeCd->name();
3780 }
3781
3782 int sp=usedClassName.find('<');
3783 if (sp==-1) sp=0;
3784 int si=usedClassName.findRev("::",sp);
3785 if (si!=-1)
3786 {
3787 // replace any namespace aliases
3788 replaceNamespaceAliases(usedClassName,si);
3789 }
3790 // add any template arguments to the class
3791 QCString usedName = removeRedundantWhiteSpace(usedClassName+templSpec);
3792 //printf(" usedName=%s\n",usedName.data());
3793
3794 bool delTempNames=FALSE;
3795 if (templateNames==0)
3796 {
3797 templateNames = getTemplateArgumentsInName(formalArgs,usedName);
3798 delTempNames=TRUE;
3799 }
3800 BaseInfo bi(usedName,Public,Normal);
3801 findClassRelation(rootNav,context,instanceCd,&bi,templateNames,TemplateInstances,isArtificial);
3802
3803 if (masterCd->templateArguments())
3804 {
3805 ArgumentListIterator ali(*masterCd->templateArguments());
3806 Argument *arg;
3807 int count=0;
3808 for (ali.toFirst();(arg=ali.current());++ali,++count)
3809 {
3810 if (arg->name==usedName) // type is a template argument
3811 {
3812 found=TRUE;
3813 Debug::print(Debug::Classes,0," New used class `%s'\n", usedName.data());
3814
3815 ClassDef *usedCd = Doxygen::hiddenClasses->find(usedName);
3816 if (usedCd==0)
3817 {
3818 usedCd = new ClassDef(
3819 masterCd->getDefFileName(),masterCd->getDefLine(),
3820 usedName,ClassDef::Class);
3821 //printf("making %s a template argument!!!\n",usedCd->name().data());
3822 usedCd->makeTemplateArgument();
3823 usedCd->setUsedOnly(TRUE);
3824 Doxygen::hiddenClasses->append(usedName,usedCd);
3825 }
3826 if (usedCd)
3827 {
3828 if (isArtificial) usedCd->setArtificial(TRUE);
3829 Debug::print(Debug::Classes,0," Adding used class `%s' (1)\n", usedCd->name().data());
3830 instanceCd->addUsedClass(usedCd,md->name());
3831 usedCd->addUsedByClass(instanceCd,md->name());
3832 }
3833 }
3834 }
3835 }
3836
3837 if (!found)
3838 {
3839 ClassDef *usedCd=findClassWithinClassContext(context,masterCd,usedName);
3840 //printf("Looking for used class %s: result=%s master=%s\n",
3841 // usedName.data(),usedCd?usedCd->name().data():"<none>",masterCd?masterCd->name().data():"<none>");
3842
3843 if (usedCd)
3844 {
3845 found=TRUE;
3846 Debug::print(Debug::Classes,0," Adding used class `%s' (2)\n", usedCd->name().data());
3847 instanceCd->addUsedClass(usedCd,md->name()); // class exists
3848 usedCd->addUsedByClass(instanceCd,md->name());
3849 }
3850 }
3851 if (delTempNames)
3852 {
3853 delete templateNames;
3854 templateNames=0;
3855 }
3856 }
3857 if (!found && !type.isEmpty()) // used class is not documented in any scope
3858 {
3859 ClassDef *usedCd = Doxygen::hiddenClasses->find(type);
3860 if (usedCd==0 && !Config_getBool("HIDE_UNDOC_RELATIONS"))
3861 {
3862 if (type.right(2)=="(*" || type.right(2)=="(^") // type is a function pointer
3863 {
3864 type+=md->argsString();
3865 }
3866 Debug::print(Debug::Classes,0," New undocumented used class `%s'\n", type.data());
3867 usedCd = new ClassDef(
3868 masterCd->getDefFileName(),masterCd->getDefLine(),
3869 type,ClassDef::Class);
3870 usedCd->setUsedOnly(TRUE);
3871 Doxygen::hiddenClasses->append(type,usedCd);
3872 }
3873 if (usedCd)
3874 {
3875 if (isArtificial) usedCd->setArtificial(TRUE);
3876 Debug::print(Debug::Classes,0," Adding used class `%s' (3)\n", usedCd->name().data());
3877 instanceCd->addUsedClass(usedCd,md->name());
3878 usedCd->addUsedByClass(instanceCd,md->name());
3879 }
3880 }
3881 }
3882 }
3883 }
3884 }
3885 else
3886 {
3887 //printf("no members for class %s (%p)\n",masterCd->name().data(),masterCd);
3888 }
3889}
3890
3891static void findBaseClassesForClass(
3892 EntryNav *rootNav,
3893 Definition *context,
3894 ClassDef *masterCd,
3895 ClassDef *instanceCd,
3896 FindBaseClassRelation_Mode mode,
3897 bool isArtificial,
3898 ArgumentList *actualArgs=0,
3899 QDict<int> *templateNames=0
3900 )
3901{
3902 Entry *root = rootNav->entry();
3903 //if (masterCd->visited) return;
3904 masterCd->visited=TRUE;
3905 // The base class could ofcouse also be a non-nested class
3906 ArgumentList *formalArgs = masterCd->templateArguments();
3907 QListIterator<BaseInfo> bii(*root->extends);
3908 BaseInfo *bi=0;
3909 for (bii.toFirst();(bi=bii.current());++bii)
3910 {
3911 //printf("masterCd=%s bi->name='%s' #actualArgs=%d\n",
3912 // masterCd->localName().data(),bi->name.data(),actualArgs?(int)actualArgs->count():-1);
3913 bool delTempNames=FALSE;
3914 if (templateNames==0)
3915 {
3916 templateNames = getTemplateArgumentsInName(formalArgs,bi->name);
3917 delTempNames=TRUE;
3918 }
3919 BaseInfo tbi(bi->name,bi->prot,bi->virt);
3920 if (actualArgs) // substitute the formal template arguments of the base class
3921 {
3922 tbi.name = substituteTemplateArgumentsInString(bi->name,formalArgs,actualArgs);
3923 }
3924 //printf("bi->name=%s tbi.name=%s\n",bi->name.data(),tbi.name.data());
3925
3926 if (mode==DocumentedOnly)
3927 {
3928 // find a documented base class in the correct scope
3929 if (!findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,DocumentedOnly,isArtificial))
3930 {
3931 if (!Config_getBool("HIDE_UNDOC_RELATIONS"))
3932 {
3933 // no documented base class -> try to find an undocumented one
3934 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,Undocumented,isArtificial);
3935 }
3936 }
3937 }
3938 else if (mode==TemplateInstances)
3939 {
3940 findClassRelation(rootNav,context,instanceCd,&tbi,templateNames,TemplateInstances,isArtificial);
3941 }
3942 if (delTempNames)
3943 {
3944 delete templateNames;
3945 templateNames=0;
3946 }
3947 }
3948}
3949
3950//----------------------------------------------------------------------
3951
3952static bool findTemplateInstanceRelation(Entry *root,
3953 Definition *context,
3954 ClassDef *templateClass,const QCString &templSpec,
3955 QDict<int> *templateNames,
3956 bool isArtificial)
3957{
3958 Debug::print(Debug::Classes,0," derived from template %s with parameters %s\n",
3959 templateClass->name().data(),templSpec.data());
3960 //printf("findTemplateInstanceRelation(base=%s templSpec=%s templateNames=",
3961 // templateClass->name().data(),templSpec.data());
3962 //if (templateNames)
3963 //{
3964 // QDictIterator<int> qdi(*templateNames);
3965 // int *tempArgIndex;
3966 // for (;(tempArgIndex=qdi.current());++qdi)
3967 // {
3968 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
3969 // }
3970 //}
3971 //printf("\n");
3972
3973 bool existingClass = (templSpec ==
3974 tempArgListToString(templateClass->templateArguments())
3975 );
3976 if (existingClass) return TRUE;
3977
3978 bool freshInstance=FALSE;
3979 ClassDef *instanceClass = templateClass->insertTemplateInstance(
3980 root->fileName,root->startLine,templSpec,freshInstance);
3981 if (isArtificial) instanceClass->setArtificial(TRUE);
3982 instanceClass->setLanguage(root->lang);
3983
3984 if (freshInstance)
3985 {
3986 Debug::print(Debug::Classes,0," found fresh instance '%s'!\n",instanceClass->name().data());
3987 Doxygen::classSDict->append(instanceClass->name(),instanceClass);
3988 instanceClass->setTemplateBaseClassNames(templateNames);
3989
3990 // search for new template instances caused by base classes of
3991 // instanceClass
3992 EntryNav *templateRootNav = g_classEntries.find(templateClass->name());
3993 if (templateRootNav)
3994 {
3995 bool unloadNeeded=FALSE;
3996 Entry *templateRoot = templateRootNav->entry();
3997 if (templateRoot==0) // not yet loaded
3998 {
3999 templateRootNav->loadEntry(g_storage);
4000 templateRoot = templateRootNav->entry();
4001 ASSERT(templateRoot!=0); // now it should really be loaded
4002 unloadNeeded=TRUE;
4003 }
4004
4005 Debug::print(Debug::Classes,0," template root found %s templSpec=%s!\n",
4006 templateRoot->name.data(),templSpec.data());
4007 ArgumentList *templArgs = new ArgumentList;
4008 stringToArgumentList(templSpec,templArgs);
4009 findBaseClassesForClass(templateRootNav,context,templateClass,instanceClass,
4010 TemplateInstances,isArtificial,templArgs,templateNames);
4011
4012 findUsedClassesForClass(templateRootNav,context,templateClass,instanceClass,
4013 isArtificial,templArgs,templateNames);
4014 delete templArgs;
4015
4016 if (unloadNeeded) // still cleanup to do
4017 {
4018 templateRootNav->releaseEntry();
4019 }
4020 }
4021 else
4022 {
4023 Debug::print(Debug::Classes,0," no template root entry found!\n");
4024 // TODO: what happened if we get here?
4025 }
4026
4027 //Debug::print(Debug::Classes,0," Template instance %s : \n",instanceClass->name().data());
4028 //ArgumentList *tl = templateClass->templateArguments();
4029 }
4030 else
4031 {
4032 Debug::print(Debug::Classes,0," instance already exists!\n");
4033 }
4034 return TRUE;
4035}
4036
4037static bool isRecursiveBaseClass(const QCString &scope,const QCString &name)
4038{
4039 QCString n=name;
4040 int index=n.find('<');
4041 if (index!=-1)
4042 {
4043 n=n.left(index);
4044 }
4045 bool result = rightScopeMatch(scope,n);
4046 return result;
4047}
4048
4049/*! Searches for the end of a template in prototype \a s starting from
4050 * character position \a startPos. If the end was found the position
4051 * of the closing \> is returned, otherwise -1 is returned.
4052 *
4053 * Handles exotic cases such as
4054 * \code
4055 * Class<(id<0)>
4056 * Class<bits<<2>
4057 * Class<"<">
4058 * Class<'<'>
4059 * Class<(")<")>
4060 * \endcode
4061 */
4062static int findEndOfTemplate(const QCString &s,int startPos)
4063{
4064 // locate end of template
4065 int e=startPos;
4066 int brCount=1;
4067 int roundCount=0;
4068 int len = s.length();
4069 bool insideString=FALSE;
4070 bool insideChar=FALSE;
4071 char pc = 0;
4072 while (e<len && brCount!=0)
4073 {
4074 char c=s.at(e);
4075 switch(c)
4076 {
4077 case '<':
4078 if (!insideString && !insideChar)
4079 {
4080 if (e<len-1 && s.at(e+1)=='<')
4081 e++;
4082 else if (roundCount==0)
4083 brCount++;
4084 }
4085 break;
4086 case '>':
4087 if (!insideString && !insideChar)
4088 {
4089 if (e<len-1 && s.at(e+1)=='>')
4090 e++;
4091 else if (roundCount==0)
4092 brCount--;
4093 }
4094 break;
4095 case '(':
4096 if (!insideString && !insideChar)
4097 roundCount++;
4098 break;
4099 case ')':
4100 if (!insideString && !insideChar)
4101 roundCount--;
4102 break;
4103 case '"':
4104 if (!insideChar)
4105 {
4106 if (insideString && pc!='\\')
4107 insideString=FALSE;
4108 else
4109 insideString=TRUE;
4110 }
4111 break;
4112 case '\'':
4113 if (!insideString)
4114 {
4115 if (insideChar && pc!='\\')
4116 insideChar=FALSE;
4117 else
4118 insideChar=TRUE;
4119 }
4120 break;
4121 }
4122 pc = c;
4123 e++;
4124 }
4125 return brCount==0 ? e : -1;
4126}
4127
4128static bool findClassRelation(
4129 EntryNav *rootNav,
4130 Definition *context,
4131 ClassDef *cd,
4132 BaseInfo *bi,
4133 QDict<int> *templateNames,
4134 FindBaseClassRelation_Mode mode,
4135 bool isArtificial
4136 )
4137{
4138 //printf("findClassRelation(class=%s base=%s templateNames=",
4139 // cd->name().data(),bi->name.data());
4140 //if (templateNames)
4141 //{
4142 // QDictIterator<int> qdi(*templateNames);
4143 // int *tempArgIndex;
4144 // for (;(tempArgIndex=qdi.current());++qdi)
4145 // {
4146 // printf("(%s->%d) ",qdi.currentKey(),*tempArgIndex);
4147 // }
4148 //}
4149 //printf("\n");
4150
4151 Entry *root = rootNav->entry();
4152
4153 QCString biName=bi->name;
4154 bool explicitGlobalScope=FALSE;
4155 //printf("findClassRelation: biName=`%s'\n",biName.data());
4156 if (biName.left(2)=="::") // explicit global scope
4157 {
4158 biName=biName.right(biName.length()-2);
4159 explicitGlobalScope=TRUE;
4160 }
4161
4162 EntryNav *parentNode=rootNav->parent();
4163 bool lastParent=FALSE;
4164 do // for each parent scope, starting with the largest scope
4165 // (in case of nested classes)
4166 {
4167 QCString scopeName= parentNode ? parentNode->name().data() : "";
4168 int scopeOffset=explicitGlobalScope ? 0 : scopeName.length();
4169 do // try all parent scope prefixes, starting with the largest scope
4170 {
4171 //printf("scopePrefix=`%s' biName=`%s'\n",
4172 // scopeName.left(scopeOffset).data(),biName.data());
4173
4174 QCString baseClassName=biName;
4175 if (scopeOffset>0)
4176 {
4177 baseClassName.prepend(scopeName.left(scopeOffset)+"::");
4178 }
4179 //QCString stripped;
4180 //baseClassName=stripTemplateSpecifiersFromScope
4181 // (removeRedundantWhiteSpace(baseClassName),TRUE,
4182 // &stripped);
4183 MemberDef *baseClassTypeDef=0;
4184 QCString templSpec;
4185 ClassDef *baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4186 cd->getFileDef(),
4187 baseClassName,
4188 &baseClassTypeDef,
4189 &templSpec,
4190 mode==Undocumented,
4191 TRUE
4192 );
4193 //printf("baseClassName=%s baseClass=%p cd=%p explicitGlobalScope=%d\n",
4194 // baseClassName.data(),baseClass,cd,explicitGlobalScope);
4195 //printf(" scope=`%s' baseClassName=`%s' baseClass=%s templSpec=%s\n",
4196 // cd ? cd->name().data():"<none>",
4197 // baseClassName.data(),
4198 // baseClass?baseClass->name().data():"<none>",
4199 // templSpec.data()
4200 // );
4201 //if (baseClassName.left(root->name.length())!=root->name ||
4202 // baseClassName.at(root->name.length())!='<'
4203 // ) // Check for base class with the same name.
4204 // // If found then look in the outer scope for a match
4205 // // and prevent recursion.
4206 if (!isRecursiveBaseClass(rootNav->name(),baseClassName) || explicitGlobalScope)
4207 {
4208 Debug::print(
4209 Debug::Classes,0," class relation %s inherited/used by %s found (%s and %s) templSpec='%s'\n",
4210 baseClassName.data(),
4211 rootNav->name().data(),
4212 (bi->prot==Private)?"private":((bi->prot==Protected)?"protected":"public"),
4213 (bi->virt==Normal)?"normal":"virtual",
4214 templSpec.data()
4215 );
4216
4217 int i=baseClassName.find('<');
4218 int si=baseClassName.findRev("::",i==-1 ? baseClassName.length() : i);
4219 if (si==-1) si=0;
4220 if (baseClass==0 && i!=-1)
4221 // base class has template specifiers
4222 {
4223 // TODO: here we should try to find the correct template specialization
4224 // but for now, we only look for the unspecializated base class.
4225 int e=findEndOfTemplate(baseClassName,i+1);
4226 //printf("baseClass==0 i=%d e=%d\n",i,e);
4227 if (e!=-1) // end of template was found at e
4228 {
4229 templSpec=removeRedundantWhiteSpace(baseClassName.mid(i,e-i));
4230 baseClassName=baseClassName.left(i)+baseClassName.right(baseClassName.length()-e);
4231 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4232 cd->getFileDef(),
4233 baseClassName,
4234 &baseClassTypeDef,
4235 0, //&templSpec,
4236 mode==Undocumented,
4237 TRUE
4238 );
4239 //printf("baseClass=%p -> baseClass=%s templSpec=%s\n",
4240 // baseClass,baseClassName.data(),templSpec.data());
4241 }
4242 }
4243 else if (baseClass && !templSpec.isEmpty()) // we have a known class, but also
4244 // know it is a template, so see if
4245 // we can also link to the explicit
4246 // instance (for instance if a class
4247 // derived from a template argument)
4248 {
4249 //printf("baseClass=%p templSpec=%s\n",baseClass,templSpec.data());
4250 ClassDef *templClass=getClass(baseClass->name()+templSpec);
4251 if (templClass)
4252 {
4253 // use the template instance instead of the template base.
4254 baseClass = templClass;
4255 templSpec.resize(0);
4256 }
4257 }
4258
4259 //printf("cd=%p baseClass=%p\n",cd,baseClass);
4260 bool found=baseClass!=0 && (baseClass!=cd || mode==TemplateInstances);
4261 //printf("1. found=%d\n",found);
4262 if (!found && si!=-1)
4263 {
4264 QCString tmpTemplSpec;
4265 // replace any namespace aliases
4266 replaceNamespaceAliases(baseClassName,si);
4267 baseClass=getResolvedClass(explicitGlobalScope ? Doxygen::globalScope : context,
4268 cd->getFileDef(),
4269 baseClassName,
4270 &baseClassTypeDef,
4271 &tmpTemplSpec,
4272 mode==Undocumented,
4273 TRUE
4274 );
4275 found=baseClass!=0 && baseClass!=cd;
4276 if (found) templSpec = tmpTemplSpec;
4277 }
4278 //printf("2. found=%d\n",found);
4279
4280 //printf("root->name=%s biName=%s baseClassName=%s\n",
4281 // root->name.data(),biName.data(),baseClassName.data());
4282 if (cd->isCSharp() && i!=-1) // C# generic -> add internal -g postfix
4283 {
4284 baseClassName+="-g";
4285 templSpec.resize(0);
4286 }
4287
4288 if (!found)
4289 {
4290 baseClass=findClassWithinClassContext(context,cd,baseClassName);
4291 //printf("findClassWithinClassContext(%s,%s)=%p\n",
4292 // cd->name().data(),baseClassName.data(),baseClass);
4293 found = baseClass!=0 && baseClass!=cd;
4294
4295 }
4296 if (!found)
4297 {
4298 // for PHP the "use A\B as C" construct map class C to A::B, so we lookup
4299 // the class name also in the alias mapping.
4300 QCString *aliasName = Doxygen::namespaceAliasDict[baseClassName];
4301 if (aliasName) // see if it is indeed a class.
4302 {
4303 baseClass=getClass(*aliasName);
4304 found = baseClass!=0 && baseClass!=cd;
4305 }
4306 }
4307 bool isATemplateArgument = templateNames!=0 && templateNames->find(biName)!=0;
4308 // make templSpec canonical
4309 // warning: the following line doesn't work for Mixin classes (see bug 560623)
4310 // templSpec = getCanonicalTemplateSpec(cd, cd->getFileDef(), templSpec);
4311
4312 //printf("3. found=%d\n",found);
4313 if (found)
4314 {
4315 Debug::print(Debug::Classes,0," Documented base class `%s' templSpec=%s\n",biName.data(),templSpec.isEmpty()?"":templSpec.data());
4316 // add base class to this class
4317
4318 // if templSpec is not empty then we should "instantiate"
4319 // the template baseClass. A new ClassDef should be created
4320 // to represent the instance. To be able to add the (instantiated)
4321 // members and documentation of a template class
4322 // (inserted in that template class at a later stage),
4323 // the template should know about its instances.
4324 // the instantiation process, should be done in a recursive way,
4325 // since instantiating a template may introduce new inheritance
4326 // relations.
4327 if (!templSpec.isEmpty() && mode==TemplateInstances)
4328 {
4329 // if baseClass is actually a typedef then we should not
4330 // instantiate it, since typedefs are in a different namespace
4331 // see bug531637 for an example where this would otherwise hang
4332 // doxygen
4333 if (baseClassTypeDef==0)
4334 {
4335 //printf(" => findTemplateInstanceRelation: %p\n",baseClassTypeDef);
4336 findTemplateInstanceRelation(root,context,baseClass,templSpec,templateNames,isArtificial);
4337 }
4338 }
4339 else if (mode==DocumentedOnly || mode==Undocumented)
4340 {
4341 //printf(" => insert base class\n");
4342 QCString usedName;
4343 if (baseClassTypeDef || cd->isCSharp())
4344 {
4345 usedName=biName;
4346 //printf("***** usedName=%s templSpec=%s\n",usedName.data(),templSpec.data());
4347 }
4348 if (Config_getBool("SIP_SUPPORT")) bi->prot=Public;
4349 cd->insertBaseClass(baseClass,usedName,bi->prot,bi->virt,templSpec);
4350 // add this class as super class to the base class
4351 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4352 }
4353 return TRUE;
4354 }
4355 else if (mode==Undocumented && (scopeOffset==0 || isATemplateArgument))
4356 {
4357 Debug::print(Debug::Classes,0,
4358 " New undocumented base class `%s' baseClassName=%s\n",
4359 biName.data(),baseClassName.data()
4360 );
4361 baseClass=0;
4362 if (isATemplateArgument)
4363 {
4364 baseClass=Doxygen::hiddenClasses->find(baseClassName);
4365 if (baseClass==0)
4366 {
4367 baseClass=new ClassDef(root->fileName,root->startLine,
4368 baseClassName,ClassDef::Class);
4369 Doxygen::hiddenClasses->append(baseClassName,baseClass);
4370 if (isArtificial) baseClass->setArtificial(TRUE);
4371 }
4372 }
4373 else
4374 {
4375 baseClass=Doxygen::classSDict->find(baseClassName);
4376 //printf("*** classDDict->find(%s)=%p biName=%s templSpec=%s\n",
4377 // baseClassName.data(),baseClass,biName.data(),templSpec.data());
4378 if (baseClass==0)
4379 {
4380 baseClass=new ClassDef(root->fileName,root->startLine,
4381 baseClassName,ClassDef::Class);
4382 Doxygen::classSDict->append(baseClassName,baseClass);
4383 if (isArtificial) baseClass->setArtificial(TRUE);
4384 }
4385 }
4386 // add base class to this class
4387 cd->insertBaseClass(baseClass,biName,bi->prot,bi->virt,templSpec);
4388 // add this class as super class to the base class
4389 baseClass->insertSubClass(cd,bi->prot,bi->virt,templSpec);
4390 // the undocumented base was found in this file
4391 baseClass->insertUsedFile(root->fileName);
4392 baseClass->setOuterScope(Doxygen::globalScope);
4393 return TRUE;
4394 }
4395 else
4396 {
4397 Debug::print(Debug::Classes,0," Base class `%s' not found\n",biName.data());
4398 }
4399 }
4400 else
4401 {
4402 if (mode!=TemplateInstances)
4403 {
4404 warn(root->fileName,root->startLine,
4405 "Detected potential recursive class relation "
4406 "between class %s and base class %s!\n",
4407 root->name.data(),baseClassName.data()
4408 );
4409 }
4410 // for mode==TemplateInstance this case is quite common and
4411 // indicates a relation between a template class and a template
4412 // instance with the same name.
4413 }
4414 if (scopeOffset==0)
4415 {
4416 scopeOffset=-1;
4417 }
4418 else if ((scopeOffset=scopeName.findRev("::",scopeOffset-1))==-1)
4419 {
4420 scopeOffset=0;
4421 }
4422 //printf("new scopeOffset=`%d'",scopeOffset);
4423 } while (scopeOffset>=0);
4424
4425 if (parentNode==0)
4426 {
4427 lastParent=TRUE;
4428 }
4429 else
4430 {
4431 parentNode=parentNode->parent();
4432 }
4433 } while (lastParent);
4434
4435 return FALSE;
4436}
4437
4438//----------------------------------------------------------------------
4439// Computes the base and super classes for each class in the tree
4440
4441static bool isClassSection(EntryNav *rootNav)
4442{
4443 if ( !rootNav->name().isEmpty() )
4444 {
4445 if (rootNav->section() & Entry::COMPOUND_MASK)
4446 // is it a compound (class, struct, union, interface ...)
4447 {
4448 return TRUE;
4449 }
4450 else if (rootNav->section() & Entry::COMPOUNDDOC_MASK)
4451 // is it a documentation block with inheritance info.
4452 {
4453 rootNav->loadEntry(g_storage);
4454 Entry *root = rootNav->entry();
4455 bool extends = root->extends->count()>0;
4456 rootNav->releaseEntry();
4457 if (extends) return TRUE;
4458 }
4459 }
4460 return FALSE;
4461}
4462
4463
4464/*! Builds a dictionary of all entry nodes in the tree starting with \a root
4465 */
4466static void findClassEntries(EntryNav *rootNav)
4467{
4468 if (isClassSection(rootNav))
4469 {
4470 g_classEntries.insert(rootNav->name(),rootNav);
4471 }
4472 RECURSE_ENTRYTREE(findClassEntries,rootNav);
4473}
4474
4475/*! Using the dictionary build by findClassEntries(), this
4476 * function will look for additional template specialization that
4477 * exists as inheritance relations only. These instances will be
4478 * added to the template they are derived from.
4479 */
4480static void findInheritedTemplateInstances()
4481{
4482 ClassSDict::Iterator cli(*Doxygen::classSDict);
4483 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4484 QDictIterator<EntryNav> edi(g_classEntries);
4485 EntryNav *rootNav;
4486 for (;(rootNav=edi.current());++edi)
4487 {
4488 ClassDef *cd;
4489 // strip any anonymous scopes first
4490 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4491 bName=stripTemplateSpecifiersFromScope(bName);
4492 Debug::print(Debug::Classes,0," Inheritance: Class %s : \n",bName.data());
4493 if ((cd=getClass(bName)))
4494 {
4495 rootNav->loadEntry(g_storage);
4496 //printf("Class %s %d\n",cd->name().data(),root->extends->count());
4497 findBaseClassesForClass(rootNav,cd,cd,cd,TemplateInstances,FALSE);
4498 rootNav->releaseEntry();
4499 }
4500 }
4501}
4502
4503static void findUsedTemplateInstances()
4504{
4505 ClassSDict::Iterator cli(*Doxygen::classSDict);
4506 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4507 QDictIterator<EntryNav> edi(g_classEntries);
4508 EntryNav *rootNav;
4509 for (;(rootNav=edi.current());++edi)
4510 {
4511 ClassDef *cd;
4512 // strip any anonymous scopes first
4513 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4514 bName=stripTemplateSpecifiersFromScope(bName);
4515 Debug::print(Debug::Classes,0," Usage: Class %s : \n",bName.data());
4516 if ((cd=getClass(bName)))
4517 {
4518 rootNav->loadEntry(g_storage);
4519 findUsedClassesForClass(rootNav,cd,cd,cd,TRUE);
4520 rootNav->releaseEntry();
4521 }
4522 }
4523}
4524
4525static void computeClassRelations()
4526{
4527 ClassSDict::Iterator cli(*Doxygen::classSDict);
4528 for (cli.toFirst();cli.current();++cli) cli.current()->visited=FALSE;
4529 QDictIterator<EntryNav> edi(g_classEntries);
4530 EntryNav *rootNav;
4531 for (;(rootNav=edi.current());++edi)
4532 {
4533 ClassDef *cd;
4534
4535 rootNav->loadEntry(g_storage);
4536 Entry *root = rootNav->entry();
4537
4538 // strip any anonymous scopes first
4539 QCString bName=stripAnonymousNamespaceScope(rootNav->name());
4540 bName=stripTemplateSpecifiersFromScope(bName);
4541 Debug::print(Debug::Classes,0," Relations: Class %s : \n",bName.data());
4542 if ((cd=getClass(bName)))
4543 {
4544 findBaseClassesForClass(rootNav,cd,cd,cd,DocumentedOnly,FALSE);
4545 }
4546 if ((cd==0 || (!cd->hasDocumentation() && !cd->isReference())) &&
4547 bName.right(2)!="::")
4548 {
4549 if (!root->name.isEmpty() && root->name.find('@')==-1 && // normal name
4550 (guessSection(root->fileName)==Entry::HEADER_SEC ||
4551 Config_getBool("EXTRACT_LOCAL_CLASSES")) && // not defined in source file
4552 (root->protection!=Private || Config_getBool("EXTRACT_PRIVATE")) && // hidden by protection
4553 !Config_getBool("HIDE_UNDOC_CLASSES") // undocumented class are visible
4554 )
4555 warn_undoc(
4556 root->fileName,root->startLine,
4557 "warning: Compound %s is not documented.",
4558 root->name.data()
4559 );
4560 }
4561
4562 rootNav->releaseEntry();
4563 }
4564}
4565
4566static void computeTemplateClassRelations()
4567{
4568 QDictIterator<EntryNav> edi(g_classEntries);
4569 EntryNav *rootNav;
4570 for (;(rootNav=edi.current());++edi)
4571 {
4572 rootNav->loadEntry(g_storage);
4573 Entry *root = rootNav->entry();
4574
4575 QCString bName=stripAnonymousNamespaceScope(root->name);
4576 bName=stripTemplateSpecifiersFromScope(bName);
4577 ClassDef *cd=getClass(bName);
4578 // strip any anonymous scopes first
4579 QDict<ClassDef> *templInstances = 0;
4580 if (cd && (templInstances=cd->getTemplateInstances()))
4581 {
4582 Debug::print(Debug::Classes,0," Template class %s : \n",cd->name().data());
4583 QDictIterator<ClassDef> tdi(*templInstances);
4584 ClassDef *tcd;
4585 for (tdi.toFirst();(tcd=tdi.current());++tdi) // for each template instance
4586 {
4587 Debug::print(Debug::Classes,0," Template instance %s : \n",tcd->name().data());
4588 QCString templSpec = tdi.currentKey();
4589 ArgumentList *templArgs = new ArgumentList;
4590 stringToArgumentList(templSpec,templArgs);
4591 QList<BaseInfo> *baseList=root->extends;
4592 BaseInfo *bi=baseList->first();
4593 while (bi) // for each base class of the template
4594 {
4595 // check if the base class is a template argument
4596 BaseInfo tbi(bi->name,bi->prot,bi->virt);
4597 ArgumentList *tl = cd->templateArguments();
4598 if (tl)
4599 {
4600 QDict<int> *baseClassNames = tcd->getTemplateBaseClassNames();
4601 QDict<int> *templateNames = getTemplateArgumentsInName(tl,bi->name);
4602 // for each template name that we inherit from we need to
4603 // substitute the formal with the actual arguments
4604 QDict<int> *actualTemplateNames = new QDict<int>(17);
4605 actualTemplateNames->setAutoDelete(TRUE);
4606 QDictIterator<int> qdi(*templateNames);
4607 for (qdi.toFirst();qdi.current();++qdi)
4608 {
4609 int templIndex = *qdi.current();
4610 Argument *actArg = 0;
4611 if (templIndex<(int)templArgs->count())
4612 {
4613 actArg=templArgs->at(templIndex);
4614 }
4615 if (actArg!=0 &&
4616 baseClassNames!=0 &&
4617 baseClassNames->find(actArg->type)!=0 &&
4618 actualTemplateNames->find(actArg->type)==0
4619 )
4620 {
4621 actualTemplateNames->insert(actArg->type,new int(templIndex));
4622 }
4623 }
4624 delete templateNames;
4625
4626 tbi.name = substituteTemplateArgumentsInString(bi->name,tl,templArgs);
4627 // find a documented base class in the correct scope
4628 if (!findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,DocumentedOnly,FALSE))
4629 {
4630 // no documented base class -> try to find an undocumented one
4631 findClassRelation(rootNav,cd,tcd,&tbi,actualTemplateNames,Undocumented,FALSE);
4632 }
4633 delete actualTemplateNames;
4634 }
4635 bi=baseList->next();
4636 }
4637 delete templArgs;
4638 } // class has no base classes
4639 }
4640
4641 rootNav->releaseEntry();
4642 }
4643}
4644
4645//-----------------------------------------------------------------------
4646// compute the references (anchors in HTML) for each function in the file
4647
4648static void computeMemberReferences()
4649{
4650 ClassSDict::Iterator cli(*Doxygen::classSDict);
4651 ClassDef *cd=0;
4652 for (cli.toFirst();(cd=cli.current());++cli)
4653 {
4654 cd->computeAnchors();
4655 }
4656 FileName *fn=Doxygen::inputNameList->first();
4657 while (fn)
4658 {
4659 FileDef *fd=fn->first();
4660 while (fd)
4661 {
4662 fd->computeAnchors();
4663 fd=fn->next();
4664 }
4665 fn=Doxygen::inputNameList->next();
4666 }
4667 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
4668 NamespaceDef *nd=0;
4669 for (nli.toFirst();(nd=nli.current());++nli)
4670 {
4671 nd->computeAnchors();
4672 }
4673 GroupSDict::Iterator gli(*Doxygen::groupSDict);
4674 GroupDef *gd;
4675 for (gli.toFirst();(gd=gli.current());++gli)
4676 {
4677 gd->computeAnchors();
4678 }
4679}
4680
4681//----------------------------------------------------------------------
4682
4683static void addListReferences()
4684{
4685 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
4686 MemberName *mn=0;
4687 for (mnli.toFirst();(mn=mnli.current());++mnli)
4688 {
4689 MemberNameIterator mni(*mn);
4690 MemberDef *md=0;
4691 for (mni.toFirst();(md=mni.current());++mni)
4692 {
4693 md->visited=FALSE;
4694 }
4695 }
4696 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
4697 for (fnli.toFirst();(mn=fnli.current());++fnli)
4698 {
4699 MemberNameIterator mni(*mn);
4700 MemberDef *md=0;
4701 for (mni.toFirst();(md=mni.current());++mni)
4702 {
4703 md->visited=FALSE;
4704 }
4705 }
4706
4707 ClassSDict::Iterator cli(*Doxygen::classSDict);
4708 ClassDef *cd=0;
4709 for (cli.toFirst();(cd=cli.current());++cli)
4710 {
4711 cd->addListReferences();
4712 }
4713 FileName *fn=Doxygen::inputNameList->first();
4714 while (fn)
4715 {
4716 FileDef *fd=fn->first();
4717 while (fd)
4718 {
4719 fd->addListReferences();
4720 fd=fn->next();
4721 }
4722 fn=Doxygen::inputNameList->next();
4723 }
4724 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
4725 NamespaceDef *nd=0;
4726 for (nli.toFirst();(nd=nli.current());++nli)
4727 {
4728 nd->addListReferences();
4729 }
4730 GroupSDict::Iterator gli(*Doxygen::groupSDict);
4731 GroupDef *gd;
4732 for (gli.toFirst();(gd=gli.current());++gli)
4733 {
4734 gd->addListReferences();
4735 }
4736 PageSDict::Iterator pdi(*Doxygen::pageSDict);
4737 PageDef *pd=0;
4738 for (pdi.toFirst();(pd=pdi.current());++pdi)
4739 {
4740 QCString name = pd->getOutputFileBase();
4741 if (pd->getGroupDef())
4742 {
4743 name = pd->getGroupDef()->getOutputFileBase();
4744 }
4745 {
4746 LockingPtr< QList<ListItemInfo> > xrefItems = pd->xrefListItems();
4747 addRefItem(xrefItems.pointer(),
4748 name,
4749 theTranslator->trPage(TRUE,TRUE),
4750 name,pd->title(),0);
4751 }
4752 }
4753 DirSDict::Iterator ddi(*Doxygen::directories);
4754 DirDef *dd = 0;
4755 for (ddi.toFirst();(dd=ddi.current());++ddi)
4756 {
4757 QCString name = dd->getOutputFileBase();
4758 //if (dd->getGroupDef())
4759 //{
4760 // name = dd->getGroupDef()->getOutputFileBase();
4761 //}
4762 LockingPtr< QList<ListItemInfo> > xrefItems = dd->xrefListItems();
4763 addRefItem(xrefItems.pointer(),
4764 name,
4765 theTranslator->trDir(TRUE,TRUE),
4766 name,dd->displayName(),0);
4767 }
4768}
4769
4770//----------------------------------------------------------------------
4771
4772static void generateXRefPages()
4773{
4774 QDictIterator<RefList> di(*Doxygen::xrefLists);
4775 RefList *rl;
4776 for (di.toFirst();(rl=di.current());++di)
4777 {
4778 rl->generatePage();
4779 }
4780}
4781
4782//----------------------------------------------------------------------
4783// Copy the documentation in entry `root' to member definition `md' and
4784// set the function declaration of the member to `funcDecl'. If the boolean
4785// over_load is set the standard overload text is added.
4786
4787static void addMemberDocs(EntryNav *rootNav,
4788 MemberDef *md, const char *funcDecl,
4789 ArgumentList *al,
4790 bool over_load,
4791 NamespaceSDict *
4792 )
4793{
4794 Entry *root = rootNav->entry();
4795 //printf("addMemberDocs: `%s'::`%s' `%s' funcDecl=`%s' mSpec=%d\n",
4796 // root->parent->name.data(),md->name().data(),md->argsString(),funcDecl,root->spec);
4797 QCString fDecl=funcDecl;
4798 // strip extern specifier
4799 fDecl.stripPrefix("extern ");
4800 md->setDefinition(fDecl);
4801 md->enableCallGraph(root->callGraph);
4802 md->enableCallerGraph(root->callerGraph);
4803 ClassDef *cd=md->getClassDef();
4804 NamespaceDef *nd=md->getNamespaceDef();
4805 QCString fullName;
4806 if (cd)
4807 fullName = cd->name();
4808 else if (nd)
4809 fullName = nd->name();
4810
4811 if (!fullName.isEmpty()) fullName+="::";
4812 fullName+=md->name();
4813 FileDef *rfd=rootNav->fileDef();
4814
4815 // TODO determine scope based on root not md
4816 Definition *rscope = md->getOuterScope();
4817
4818 LockingPtr<ArgumentList> mdAl = md->argumentList();
4819 if (al)
4820 {
4821 //printf("merging arguments (1) docs=%d\n",root->doc.isEmpty());
4822 mergeArguments(mdAl.pointer(),al,!root->doc.isEmpty());
4823 }
4824 else
4825 {
4826 if (
4827 matchArguments2( md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
4828 rscope,rfd,root->argList,
4829 TRUE
4830 )
4831 )
4832 {
4833 //printf("merging arguments (2)\n");
4834 mergeArguments(mdAl.pointer(),root->argList,!root->doc.isEmpty());
4835 }
4836 }
4837 if (over_load) // the \overload keyword was used
4838 {
4839 QCString doc=getOverloadDocs();
4840 if (!root->doc.isEmpty())
4841 {
4842 doc+="<p>";
4843 doc+=root->doc;
4844 }
4845 md->setDocumentation(doc,root->docFile,root->docLine);
4846 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
4847 md->setDocsForDefinition(!root->proto);
4848 }
4849 else
4850 {
4851 //printf("overwrite!\n");
4852 md->setDocumentation(root->doc,root->docFile,root->docLine);
4853 md->setDocsForDefinition(!root->proto);
4854
4855 //printf("overwrite!\n");
4856 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
4857
4858 if (
4859 (md->inbodyDocumentation().isEmpty() ||
4860 !rootNav->parent()->name().isEmpty()
4861 ) && !root->inbodyDocs.isEmpty()
4862 )
4863 {
4864 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
4865 }
4866 }
4867
4868 //printf("initializer: '%s'(isEmpty=%d) '%s'(isEmpty=%d)\n",
4869 // md->initializer().data(),md->initializer().isEmpty(),
4870 // root->initializer.data(),root->initializer.isEmpty()
4871 // );
4872 if (md->initializer().isEmpty() && !root->initializer.isEmpty())
4873 {
4874 //printf("setInitializer\n");
4875 md->setInitializer(root->initializer);
4876 }
4877
4878 md->setMaxInitLines(root->initLines);
4879
4880 if (rfd)
4881 {
4882 if ((md->getStartBodyLine()==-1 && root->bodyLine!=-1)
4883 )
4884 {
4885 //printf("Setting new body segment [%d,%d]\n",root->bodyLine,root->endBodyLine);
4886 md->setBodySegment(root->bodyLine,root->endBodyLine);
4887 md->setBodyDef(rfd);
4888 }
4889
4890 md->setRefItems(root->sli);
4891 }
4892
4893 md->enableCallGraph(md->hasCallGraph() || root->callGraph);
4894 md->enableCallerGraph(md->hasCallerGraph() || root->callerGraph);
4895
4896 md->mergeMemberSpecifiers(root->spec);
4897 md->addSectionsToDefinition(root->anchors);
4898 addMemberToGroups(root,md);
4899 if (cd) cd->insertUsedFile(root->fileName);
4900 //printf("root->mGrpId=%d\n",root->mGrpId);
4901 if (root->mGrpId!=-1)
4902 {
4903 if (md->getMemberGroupId()!=-1)
4904 {
4905 if (md->getMemberGroupId()!=root->mGrpId)
4906 {
4907 warn(
4908 root->fileName,root->startLine,
4909 "warning: member %s belongs to two different groups. The second "
4910 "one found here will be ignored.",
4911 md->name().data()
4912 );
4913 }
4914 }
4915 else // set group id
4916 {
4917 //printf("setMemberGroupId=%d md=%s\n",root->mGrpId,md->name().data());
4918 md->setMemberGroupId(root->mGrpId);
4919 }
4920 }
4921}
4922
4923//----------------------------------------------------------------------
4924// find a class definition given the scope name and (optionally) a
4925// template list specifier
4926
4927static ClassDef *findClassDefinition(FileDef *fd,NamespaceDef *nd,
4928 const char *scopeName)
4929{
4930 ClassDef *tcd = getResolvedClass(nd,fd,scopeName,0,0,TRUE,TRUE);
4931 return tcd;
4932}
4933
4934
4935//----------------------------------------------------------------------
4936// Adds the documentation contained in `root' to a global function
4937// with name `name' and argument list `args' (for overloading) and
4938// function declaration `decl' to the corresponding member definition.
4939
4940static bool findGlobalMember(EntryNav *rootNav,
4941 const QCString &namespaceName,
4942 const char *name,
4943 const char *tempArg,
4944 const char *,
4945 const char *decl)
4946{
4947 Entry *root = rootNav->entry();
4948 Debug::print(Debug::FindMembers,0,
4949 "2. findGlobalMember(namespace=%s,name=%s,tempArg=%s,decl=%s)\n",
4950 namespaceName.data(),name,tempArg,decl);
4951 QCString n=name;
4952 if (n.isEmpty()) return FALSE;
4953 if (n.find("::")!=-1) return FALSE; // skip undefined class members
4954 MemberName *mn=Doxygen::functionNameSDict->find(n+tempArg); // look in function dictionary
4955 if (mn==0)
4956 {
4957 mn=Doxygen::functionNameSDict->find(n); // try without template arguments
4958 }
4959 if (mn) // function name defined
4960 {
4961 Debug::print(Debug::FindMembers,0,"3. Found function scope\n");
4962 //int count=0;
4963 MemberNameIterator mni(*mn);
4964 MemberDef *md;
4965 bool found=FALSE;
4966 for (mni.toFirst();(md=mni.current()) && !found;++mni)
4967 {
4968 NamespaceDef *nd=md->getNamespaceDef();
4969
4970 //printf("Namespace namespaceName=%s nd=%s\n",
4971 // namespaceName.data(),nd ? nd->name().data() : "<none>");
4972
4973 FileDef *fd=rootNav->fileDef();
4974 //printf("File %s\n",fd ? fd->name().data() : "<none>");
4975 NamespaceSDict *nl = fd ? fd->getUsedNamespaces() : 0;
4976 //SDict<Definition> *cl = fd ? fd->getUsedClasses() : 0;
4977 //printf("NamespaceList %p\n",nl);
4978
4979 // search in the list of namespaces that are imported via a
4980 // using declaration
4981 bool viaUsingDirective = nl && nd && nl->find(nd->qualifiedName())!=0;
4982
4983 if ((namespaceName.isEmpty() && nd==0) || // not in a namespace
4984 (nd && nd->name()==namespaceName) || // or in the same namespace
4985 viaUsingDirective // member in `using' namespace
4986 )
4987 {
4988 Debug::print(Debug::FindMembers,0,"4. Try to add member `%s' to scope `%s'\n",
4989 md->name().data(),namespaceName.data());
4990 QCString nsName = nd ? nd->name().data() : "";
4991
4992 NamespaceDef *rnd = 0;
4993 if (!namespaceName.isEmpty()) rnd = Doxygen::namespaceSDict->find(namespaceName);
4994
4995 LockingPtr<ArgumentList> mdAl = md->argumentList();
4996 bool matching=
4997 (mdAl==0 && root->argList->count()==0) ||
4998 md->isVariable() || md->isTypedef() || /* in case of function pointers */
4999 matchArguments2(md->getOuterScope(),md->getFileDef(),mdAl.pointer(),
5000 rnd ? rnd : Doxygen::globalScope,fd,root->argList,
5001 FALSE);
5002
5003 // for template members we need to check if the number of
5004 // template arguments is the same, otherwise we are dealing with
5005 // different functions.
5006 if (matching && root->tArgLists)
5007 {
5008 LockingPtr<ArgumentList> mdTempl = md->templateArguments();
5009 if (mdTempl!=0)
5010 {
5011 if (root->tArgLists->getLast()->count()!=mdTempl->count())
5012 {
5013 matching=FALSE;
5014 }
5015 }
5016 }
5017
5018
5019 //printf("%s<->%s\n",
5020 // argListToString(md->argumentList()).data(),
5021 // argListToString(root->argList).data());
5022
5023 // for static members we also check if the comment block was found in
5024 // the same file. This is needed because static members with the same
5025 // name can be in different files. Thus it would be wrong to just
5026 // put the comment block at the first syntactically matching member.
5027 if (matching && md->isStatic() &&
5028 md->getDefFileName()!=root->fileName &&
5029 mn->count()>1)
5030 {
5031 matching = FALSE;
5032 }
5033
5034 if (matching) // add docs to the member
5035 {
5036 Debug::print(Debug::FindMembers,0,"5. Match found\n");
5037 addMemberDocs(rootNav,md,decl,root->argList,FALSE);
5038 found=TRUE;
5039 }
5040 }
5041 }
5042 if (!found && root->relatesType != Duplicate) // no match
5043 {
5044 QCString fullFuncDecl=decl;
5045 if (root->argList) fullFuncDecl+=argListToString(root->argList,TRUE);
5046 QCString warnMsg =
5047 QCString("warning: no matching file member found for \n")+fullFuncDecl;
5048 if (mn->count()>0)
5049 {
5050 warnMsg+="Possible candidates:\n";
5051 for (mni.toFirst();(md=mni.current());++mni)
5052 {
5053 warnMsg+=" ";
5054 warnMsg+=md->declaration();
5055 warnMsg+='\n';
5056 }
5057 }
5058 warn(root->fileName,root->startLine,warnMsg);
5059 }
5060 }
5061 else // got docs for an undefined member!
5062 {
5063 if (root->type!="friend class" &&
5064 root->type!="friend struct" &&
5065 root->type!="friend union" &&
5066 (!Config_getBool("TYPEDEF_HIDES_STRUCT") ||
5067 root->type.find("typedef ")==-1)
5068 )
5069 {
5070 warn(root->fileName,root->startLine,
5071 "warning: documented function `%s' was not declared or defined.",decl
5072 );
5073 }
5074 }
5075 return TRUE;
5076}
5077
5078static bool isSpecialization(
5079 const QList<ArgumentList> &srcTempArgLists,
5080 const QList<ArgumentList> &dstTempArgLists
5081 )
5082{
5083 QListIterator<ArgumentList> srclali(srcTempArgLists);
5084 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5085 for (;srclali.current();++srclali,++dstlali)
5086 {
5087 ArgumentList *sal = srclali.current();
5088 ArgumentList *dal = dstlali.current();
5089 if (!(sal && dal && sal->count()==dal->count())) return TRUE;
5090 }
5091 return FALSE;
5092}
5093
5094
5095static QCString substituteTemplatesInString(
5096 const QList<ArgumentList> &srcTempArgLists,
5097 const QList<ArgumentList> &dstTempArgLists,
5098 ArgumentList *funcTempArgList, // can be used to match template specializations
5099 const QCString &src
5100 )
5101{
5102 QCString dst;
5103 QRegExp re( "[A-Za-z_][A-Za-z_0-9]*");
5104 //printf("type=%s\n",sa->type.data());
5105 int i,p=0,l;
5106 while ((i=re.match(src,p,&l))!=-1) // for each word in srcType
5107 {
5108 bool found=FALSE;
5109 dst+=src.mid(p,i-p);
5110 QCString name=src.mid(i,l);
5111
5112 QListIterator<ArgumentList> srclali(srcTempArgLists);
5113 QListIterator<ArgumentList> dstlali(dstTempArgLists);
5114 for (;srclali.current() && !found;++srclali,++dstlali)
5115 {
5116 ArgumentListIterator tsali(*srclali.current());
5117 ArgumentListIterator tdali(*dstlali.current());
5118 Argument *tsa =0,*tda=0, *fa=0;
5119 if (funcTempArgList)
5120 {
5121 fa=funcTempArgList->first();
5122 }
5123
5124 for (tsali.toFirst();(tsa=tsali.current()) && !found;++tsali)
5125 {
5126 tda = tdali.current();
5127 //if (tda) printf("tsa=%s|%s tda=%s|%s\n",
5128 // tsa->type.data(),tsa->name.data(),
5129 // tda->type.data(),tda->name.data());
5130 if (name==tsa->name)
5131 {
5132 if (tda && tda->name.isEmpty())
5133 {
5134 int vc=0;
5135 if (tda->type.left(6)=="class ") vc=6;
5136 else if (tda->type.left(9)=="typename ") vc=9;
5137 if (vc>0) // convert type=="class T" to type=="class" name=="T"
5138 {
5139 tda->name = tda->type.mid(vc);
5140 tda->type = tda->type.left(vc-1);
5141 }
5142 }
5143 if (tda && !tda->name.isEmpty())
5144 {
5145 name=tda->name; // substitute
5146 found=TRUE;
5147 }
5148 else if (fa)
5149 {
5150 name=fa->type;
5151 found=TRUE;
5152 }
5153 }
5154 if (tda)
5155 ++tdali;
5156 else if (fa)
5157 fa=funcTempArgList->next();
5158 }
5159 //printf(" srcList='%s' dstList='%s faList='%s'\n",
5160 // argListToString(srclali.current()).data(),
5161 // argListToString(dstlali.current()).data(),
5162 // funcTempArgList ? argListToString(funcTempArgList).data() : "<none>");
5163 }
5164 dst+=name;
5165 p=i+l;
5166 }
5167 dst+=src.right(src.length()-p);
5168 //printf(" substituteTemplatesInString(%s)=%s\n",
5169 // src.data(),dst.data());
5170 return dst;
5171}
5172
5173static void substituteTemplatesInArgList(
5174 const QList<ArgumentList> &srcTempArgLists,
5175 const QList<ArgumentList> &dstTempArgLists,
5176 ArgumentList *src,
5177 ArgumentList *dst,
5178 ArgumentList *funcTempArgs = 0
5179 )
5180{
5181 ArgumentListIterator sali(*src);
5182 Argument *sa=0;
5183 Argument *da=dst->first();
5184
5185 for (sali.toFirst();(sa=sali.current());++sali) // for each member argument
5186 {
5187 QCString dstType = substituteTemplatesInString(
5188 srcTempArgLists,dstTempArgLists,funcTempArgs,
5189 sa->type);
5190 QCString dstArray = substituteTemplatesInString(
5191 srcTempArgLists,dstTempArgLists,funcTempArgs,
5192 sa->array);
5193 if (da==0)
5194 {
5195 da=new Argument(*sa);
5196 dst->append(da);
5197 da->type=dstType;
5198 da->array=dstArray;
5199 da=0;
5200 }
5201 else
5202 {
5203 da->type=dstType;
5204 da->type=dstArray;
5205 da=dst->next();
5206 }
5207 }
5208 dst->constSpecifier = src->constSpecifier;
5209 dst->volatileSpecifier = src->volatileSpecifier;
5210 dst->pureSpecifier = src->pureSpecifier;
5211 //printf("substituteTemplatesInArgList: replacing %s with %s\n",
5212 // argListToString(src).data(),argListToString(dst).data()
5213 // );
5214}
5215
5216
5217
5218/*! This function tries to find a member (in a documented class/file/namespace)
5219 * that corresponds to the function/variable declaration given in \a funcDecl.
5220 *
5221 * The boolean \a overloaded is used to specify whether or not a standard
5222 * overload documentation line should be generated.
5223 *
5224 * The boolean \a isFunc is a hint that indicates that this is a function
5225 * instead of a variable or typedef.
5226 */
5227static void findMember(EntryNav *rootNav,
5228 QCString funcDecl,
5229 bool overloaded,
5230 bool isFunc
5231 )
5232{
5233 Entry *root = rootNav->entry();
5234
5235 Debug::print(Debug::FindMembers,0,
5236 "findMember(root=%p,funcDecl=`%s',related=`%s',overload=%d,"
5237 "isFunc=%d mGrpId=%d tArgList=%p (#=%d) "
5238 "spec=%d lang=%x\n",
5239 root,funcDecl.data(),root->relates.data(),overloaded,isFunc,root->mGrpId,
5240 root->tArgLists,root->tArgLists ? root->tArgLists->count() : 0,
5241 root->spec,root->lang
5242 );
5243
5244 QCString scopeName;
5245 QCString className;
5246 QCString namespaceName;
5247 QCString funcType;
5248 QCString funcName;
5249 QCString funcArgs;
5250 QCString funcTempList;
5251 QCString exceptions;
5252 QCString funcSpec;
5253 bool isRelated=FALSE;
5254 bool isMemberOf=FALSE;
5255 bool isFriend=FALSE;
5256 bool done;
5257 do
5258 {
5259 done=TRUE;
5260 if (funcDecl.stripPrefix("friend ")) // treat friends as related members
5261 {
5262 isFriend=TRUE;
5263 done=FALSE;
5264 }
5265 if (funcDecl.stripPrefix("inline "))
5266 {
5267 root->spec|=Entry::Inline;
5268 done=FALSE;
5269 }
5270 if (funcDecl.stripPrefix("explicit "))
5271 {
5272 root->spec|=Entry::Explicit;
5273 done=FALSE;
5274 }
5275 if (funcDecl.stripPrefix("mutable "))
5276 {
5277 root->spec|=Entry::Mutable;
5278 done=FALSE;
5279 }
5280 if (funcDecl.stripPrefix("virtual "))
5281 {
5282 done=FALSE;
5283 }
5284 } while (!done);
5285
5286 // delete any ; from the function declaration
5287 int sep;
5288 while ((sep=funcDecl.find(';'))!=-1)
5289 {
5290 funcDecl=(funcDecl.left(sep)+funcDecl.right(funcDecl.length()-sep-1)).stripWhiteSpace();
5291 }
5292
5293 // make sure the first character is a space to simplify searching.
5294 if (!funcDecl.isEmpty() && funcDecl[0]!=' ') funcDecl.prepend(" ");
5295
5296 // remove some superfluous spaces
5297 funcDecl= substitute(
5298 substitute(
5299 substitute(funcDecl,"~ ","~"),
5300 ":: ","::"
5301 ),
5302 " ::","::"
5303 ).stripWhiteSpace();
5304
5305 //printf("funcDecl=`%s'\n",funcDecl.data());
5306 if (isFriend && funcDecl.left(6)=="class ")
5307 {
5308 //printf("friend class\n");
5309 funcDecl=funcDecl.right(funcDecl.length()-6);
5310 funcName = funcDecl.copy();
5311 }
5312 else if (isFriend && funcDecl.left(7)=="struct ")
5313 {
5314 funcDecl=funcDecl.right(funcDecl.length()-7);
5315 funcName = funcDecl.copy();
5316 }
5317 else
5318 {
5319 // extract information from the declarations
5320 parseFuncDecl(funcDecl,root->lang==SrcLangExt_ObjC,scopeName,funcType,funcName,
5321 funcArgs,funcTempList,exceptions
5322 );
5323 }
5324 //printf("scopeName=`%s' funcType=`%s' funcName=`%s' funcArgs=`%s'\n",
5325 // scopeName.data(),funcType.data(),funcName.data(),funcArgs.data());
5326
5327 // the class name can also be a namespace name, we decide this later.
5328 // if a related class name is specified and the class name could
5329 // not be derived from the function declaration, then use the
5330 // related field.
5331 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5332 // scopeName.data(),className.data(),namespaceName.data());
5333 if (!root->relates.isEmpty())
5334 { // related member, prefix user specified scope
5335 isRelated=TRUE;
5336 isMemberOf=(root->relatesType == MemberOf);
5337 if (getClass(root->relates)==0 && !scopeName.isEmpty())
5338 {
5339 scopeName= mergeScopes(scopeName,root->relates);
5340 }
5341 else
5342 {
5343 scopeName = root->relates;
5344 }
5345 }
5346
5347 if (root->relates.isEmpty() && rootNav->parent() &&
5348 ((rootNav->parent()->section()&Entry::SCOPE_MASK) ||
5349 (rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5350 ) &&
5351 !rootNav->parent()->name().isEmpty()) // see if we can combine scopeName
5352 // with the scope in which it was found
5353 {
5354 QCString joinedName = rootNav->parent()->name()+"::"+scopeName;
5355 if (!scopeName.isEmpty() &&
5356 (getClass(joinedName) || Doxygen::namespaceSDict->find(joinedName)))
5357 {
5358 scopeName = joinedName;
5359 }
5360 else
5361 {
5362 scopeName = mergeScopes(rootNav->parent()->name(),scopeName);
5363 }
5364 }
5365 else // see if we can prefix a namespace or class that is used from the file
5366 {
5367 FileDef *fd=rootNav->fileDef();
5368 if (fd)
5369 {
5370 NamespaceSDict *fnl = fd->getUsedNamespaces();
5371 if (fnl)
5372 {
5373 QCString joinedName;
5374 NamespaceDef *fnd;
5375 NamespaceSDict::Iterator nsdi(*fnl);
5376 for (nsdi.toFirst();(fnd=nsdi.current());++nsdi)
5377 {
5378 joinedName = fnd->name()+"::"+scopeName;
5379 if (Doxygen::namespaceSDict->find(joinedName))
5380 {
5381 scopeName=joinedName;
5382 break;
5383 }
5384 }
5385 }
5386 }
5387 }
5388 scopeName=stripTemplateSpecifiersFromScope(
5389 removeRedundantWhiteSpace(scopeName),FALSE,&funcSpec);
5390
5391 // funcSpec contains the last template specifiers of the given scope.
5392 // If this method does not have any template arguments or they are
5393 // empty while funcSpec is not empty we assume this is a
5394 // specialization of a method. If not, we clear the funcSpec and treat
5395 // this as a normal method of a template class.
5396 if (!(root->tArgLists &&
5397 root->tArgLists->count()>0 &&
5398 root->tArgLists->first()->count()==0
5399 )
5400 )
5401 {
5402 funcSpec.resize(0);
5403 }
5404
5405 // split scope into a namespace and a class part
5406 extractNamespaceName(scopeName,className,namespaceName,TRUE);
5407 //printf("scopeName=`%s' className=`%s' namespaceName=`%s'\n",
5408 // scopeName.data(),className.data(),namespaceName.data());
5409
5410 //namespaceName=removeAnonymousScopes(namespaceName);
5411 if (namespaceName.find('@')!=-1) return; // skip stuff in anonymous namespace...
5412
5413 //printf("namespaceName=`%s' className=`%s'\n",namespaceName.data(),className.data());
5414 // merge class and namespace scopes again
5415 scopeName.resize(0);
5416 if (!namespaceName.isEmpty())
5417 {
5418 if (className.isEmpty())
5419 {
5420 scopeName=namespaceName;
5421 }
5422 else if (!root->relates.isEmpty() || // relates command with explicit scope
5423 !getClass(className)) // class name only exists in a namespace
5424 {
5425 scopeName=namespaceName+"::"+className;
5426 }
5427 else
5428 {
5429 scopeName=className;
5430 }
5431 }
5432 else if (!className.isEmpty())
5433 {
5434 scopeName=className;
5435 }
5436 //printf("new scope=`%s'\n",scopeName.data());
5437
5438 QCString tempScopeName=scopeName;
5439 ClassDef *cd=getClass(scopeName);
5440 if (cd)
5441 {
5442 if (root->tArgLists) root->tArgLists->first();
5443 if (funcSpec.isEmpty())
5444 {
5445 tempScopeName=cd->qualifiedNameWithTemplateParameters(root->tArgLists);
5446 }
5447 else
5448 {
5449 tempScopeName=scopeName+funcSpec;
5450 }
5451 }
5452 //printf("scopeName=%s cd=%p root->tArgLists=%p result=%s\n",
5453 // scopeName.data(),cd,root->tArgLists,tempScopeName.data());
5454
5455 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
5456 // rebuild the function declaration (needed to get the scope right).
5457 if (!scopeName.isEmpty() && !isRelated && !isFriend && !Config_getBool("HIDE_SCOPE_NAMES"))
5458 {
5459 if (!funcType.isEmpty())
5460 {
5461 if (isFunc) // a function -> we use argList for the arguments
5462 {
5463 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcTempList;
5464 }
5465 else
5466 {
5467 funcDecl=funcType+" "+tempScopeName+"::"+funcName+funcArgs;
5468 }
5469 }
5470 else
5471 {
5472 if (isFunc) // a function => we use argList for the arguments
5473 {
5474 funcDecl=tempScopeName+"::"+funcName+funcTempList;
5475 }
5476 else // variable => add `argument' list
5477 {
5478 funcDecl=tempScopeName+"::"+funcName+funcArgs;
5479 }
5480 }
5481 }
5482 else // build declaration without scope
5483 {
5484 if (!funcType.isEmpty()) // but with a type
5485 {
5486 if (isFunc) // function => omit argument list
5487 {
5488 funcDecl=funcType+" "+funcName+funcTempList;
5489 }
5490 else // variable => add `argument' list
5491 {
5492 funcDecl=funcType+" "+funcName+funcArgs;
5493 }
5494 }
5495 else // no type
5496 {
5497 if (isFunc)
5498 {
5499 funcDecl=funcName+funcTempList;
5500 }
5501 else
5502 {
5503 funcDecl=funcName+funcArgs;
5504 }
5505 }
5506 }
5507
5508 if (funcType=="template class" && !funcTempList.isEmpty())
5509 return; // ignore explicit template instantiations
5510
5511 Debug::print(Debug::FindMembers,0,
5512 "findMember() Parse results:\n"
5513 " namespaceName=`%s'\n"
5514 " className=`%s`\n"
5515 " funcType=`%s'\n"
5516 " funcSpec=`%s'\n"
5517 " funcName=`%s'\n"
5518 " funcArgs=`%s'\n"
5519 " funcTempList=`%s'\n"
5520 " funcDecl=`%s'\n"
5521 " related=`%s'\n"
5522 " exceptions=`%s'\n"
5523 " isRelated=%d\n"
5524 " isMemberOf=%d\n"
5525 " isFriend=%d\n"
5526 " isFunc=%d\n\n",
5527 namespaceName.data(),className.data(),
5528 funcType.data(),funcSpec.data(),funcName.data(),funcArgs.data(),funcTempList.data(),
5529 funcDecl.data(),root->relates.data(),exceptions.data(),isRelated,isMemberOf,isFriend,
5530 isFunc
5531 );
5532
5533 MemberName *mn=0;
5534 if (!funcName.isEmpty()) // function name is valid
5535 {
5536 Debug::print(Debug::FindMembers,0,
5537 "1. funcName=`%s'\n",funcName.data());
5538 if (funcName.left(9)=="operator ") // strip class scope from cast operator
5539 {
5540 funcName = substitute(funcName,className+"::","");
5541 }
5542 if (!funcTempList.isEmpty()) // try with member specialization
5543 {
5544 mn=Doxygen::memberNameSDict->find(funcName+funcTempList);
5545 }
5546 if (mn==0) // try without specialization
5547 {
5548 mn=Doxygen::memberNameSDict->find(funcName);
5549 }
5550 if (!isRelated && mn) // function name already found
5551 {
5552 Debug::print(Debug::FindMembers,0,
5553 "2. member name exists (%d members with this name)\n",mn->count());
5554 if (!className.isEmpty()) // class name is valid
5555 {
5556 if (funcSpec.isEmpty()) // not a member specialization
5557 {
5558 int count=0;
5559 int noMatchCount=0;
5560 MemberNameIterator mni(*mn);
5561 MemberDef *md;
5562 bool memFound=FALSE;
5563 for (mni.toFirst();!memFound && (md=mni.current());++mni)
5564 {
5565 ClassDef *cd=md->getClassDef();
5566 Debug::print(Debug::FindMembers,0,
5567 "3. member definition found, "
5568 "scope needed=`%s' scope=`%s' args=`%s' fileName=%s\n",
5569 scopeName.data(),cd ? cd->name().data() : "<none>",
5570 md->argsString(),
5571 root->fileName.data());
5572 //printf("Member %s (member scopeName=%s) (this scopeName=%s) classTempList=%s\n",md->name().data(),cd->name().data(),scopeName.data(),classTempList.data());
5573 FileDef *fd=rootNav->fileDef();
5574 NamespaceDef *nd=0;
5575 if (!namespaceName.isEmpty()) nd=getResolvedNamespace(namespaceName);
5576
5577 //printf("scopeName %s->%s\n",scopeName.data(),
5578 // stripTemplateSpecifiersFromScope(scopeName,FALSE).data());
5579
5580 ClassDef *tcd=findClassDefinition(fd,nd,scopeName);
5581 if (tcd==0 && stripAnonymousNamespaceScope(cd->name())==scopeName)
5582 {
5583 // don't be fooled by anonymous scopes
5584 tcd=cd;
5585 }
5586 //printf("Looking for %s inside nd=%s result=%p (%s) cd=%p\n",
5587 // scopeName.data(),nd?nd->name().data():"<none>",tcd,tcd?tcd->name().data():"",cd);
5588
5589 if (cd && tcd==cd) // member's classes match
5590 {
5591 Debug::print(Debug::FindMembers,0,
5592 "4. class definition %s found\n",cd->name().data());
5593
5594 // get the template parameter lists found at the member declaration
5595 QList<ArgumentList> declTemplArgs;
5596 cd->getTemplateParameterLists(declTemplArgs);
5597 LockingPtr<ArgumentList> templAl = md->templateArguments();
5598 if (templAl!=0)
5599 {
5600 declTemplArgs.append(templAl.pointer());
5601 }
5602
5603 // get the template parameter lists found at the member definition
5604 QList<ArgumentList> *defTemplArgs = root->tArgLists;
5605 //printf("defTemplArgs=%p\n",defTemplArgs);
5606
5607 // do we replace the decl argument lists with the def argument lists?
5608 bool substDone=FALSE;
5609 ArgumentList *argList=0;
5610
5611 /* substitute the occurrences of class template names in the
5612 * argument list before matching
5613 */
5614 LockingPtr<ArgumentList> mdAl = md->argumentList();
5615 if (declTemplArgs.count()>0 && defTemplArgs &&
5616 declTemplArgs.count()==defTemplArgs->count() &&
5617 mdAl.pointer()
5618 )
5619 {
5620 /* the function definition has template arguments
5621 * and the class definition also has template arguments, so
5622 * we must substitute the template names of the class by that
5623 * of the function definition before matching.
5624 */
5625 argList = new ArgumentList;
5626 substituteTemplatesInArgList(declTemplArgs,*defTemplArgs,
5627 mdAl.pointer(),argList);
5628
5629 substDone=TRUE;
5630 }
5631 else /* no template arguments, compare argument lists directly */
5632 {
5633 argList = mdAl.pointer();
5634 }
5635
5636 Debug::print(Debug::FindMembers,0,
5637 "5. matching `%s'<=>`%s' className=%s namespaceName=%s\n",
5638 argListToString(argList,TRUE).data(),argListToString(root->argList,TRUE).data(),
5639 className.data(),namespaceName.data()
5640 );
5641
5642 bool matching=
5643 md->isVariable() || md->isTypedef() || // needed for function pointers
5644 (mdAl.pointer()==0 && root->argList->count()==0) ||
5645 matchArguments2(
5646 md->getClassDef(),md->getFileDef(),argList,
5647 cd,fd,root->argList,
5648 TRUE);
5649
5650 Debug::print(Debug::FindMembers,0,
5651 "6. match results of matchArguments2 = %d\n",matching);
5652
5653 if (substDone) // found a new argument list
5654 {
5655 if (matching) // replace member's argument list
5656 {
5657 md->setDefinitionTemplateParameterLists(root->tArgLists);
5658 md->setArgumentList(argList); // new owner of the list => no delete
5659 }
5660 else // no match
5661 {
5662 if (!funcTempList.isEmpty() &&
5663 isSpecialization(declTemplArgs,*defTemplArgs))
5664 {
5665 // check if we are dealing with a partial template
5666 // specialization. In this case we add it to the class
5667 // even though the member arguments do not match.
5668
5669 // TODO: copy other aspects?
5670 root->protection=md->protection(); // copy protection level
5671 addMethodToClass(rootNav,cd,md->name(),isFriend);
5672 return;
5673 }
5674 delete argList;
5675 }
5676 }
5677 if (matching)
5678 {
5679 addMemberDocs(rootNav,md,funcDecl,0,overloaded,0/* TODO */);
5680 count++;
5681 memFound=TRUE;
5682 }
5683 }
5684 else if (cd && cd!=tcd) // we did find a class with the same name as cd
5685 // but in a different namespace
5686 {
5687 noMatchCount++;
5688 }
5689 }
5690 if (count==0 && rootNav->parent() &&
5691 rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
5692 {
5693 goto localObjCMethod;
5694 }
5695 if (count==0 && !(isFriend && funcType=="class"))
5696 {
5697 int candidates=0;
5698 ClassDef *ccd = 0, *ecd = 0;
5699 MemberDef *cmd = 0, *emd = 0;
5700 if (mn->count()>0)
5701 {
5702 //printf("Assume template class\n");
5703 for (mni.toFirst();(md=mni.current());++mni)
5704 {
5705 ccd=md->getClassDef();
5706 cmd=md;
5707 //printf("ccd->name()==%s className=%s\n",ccd->name().data(),className.data());
5708 if (ccd!=0 && rightScopeMatch(ccd->name(),className))
5709 {
5710 LockingPtr<ArgumentList> templAl = md->templateArguments();
5711 if (root->tArgLists && templAl!=0 &&
5712 root->tArgLists->getLast()->count()<=templAl->count())
5713 {
5714 addMethodToClass(rootNav,ccd,md->name(),isFriend);
5715 return;
5716 }
5717 if (md->argsString()==argListToString(root->argList,TRUE,FALSE))
5718 { // exact argument list match -> remember
5719 ecd = ccd;
5720 emd = cmd;
5721 }
5722 candidates++;
5723 }
5724 }
5725 }
5726 static bool strictProtoMatching = Config_getBool("STRICT_PROTO_MATCHING");
5727 if (!strictProtoMatching)
5728 {
5729 if (candidates==1 && ccd && cmd)
5730 {
5731 // we didn't find an actual match on argument lists, but there is only 1 member with this
5732 // name in the same scope, so that has to be the one.
5733 addMemberDocs(rootNav,cmd,funcDecl,0,overloaded,0);
5734 return;
5735 }
5736 else if (candidates>1 && ecd && emd)
5737 {
5738 // we didn't find a unique match using type resolution,
5739 // but one of the matches has the exact same signature so
5740 // we take that one.
5741 addMemberDocs(rootNav,emd,funcDecl,0,overloaded,0);
5742 return;
5743 }
5744 }
5745
5746 QCString warnMsg = "warning: no ";
5747 if (noMatchCount>1) warnMsg+="uniquely ";
5748 warnMsg+="matching class member found for \n";
5749
5750 if (root->tArgLists)
5751 {
5752 QListIterator<ArgumentList> alli(*root->tArgLists);
5753 ArgumentList *al;
5754 for (;(al=alli.current());++alli)
5755 {
5756 warnMsg+=" template ";
5757 warnMsg+=tempArgListToString(al);
5758 warnMsg+='\n';
5759 }
5760 }
5761 QCString fullFuncDecl=funcDecl.copy();
5762 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
5763
5764 warnMsg+=" ";
5765 warnMsg+=fullFuncDecl;
5766 warnMsg+='\n';
5767
5768 if (candidates>0)
5769 {
5770 warnMsg+="Possible candidates:\n";
5771 for (mni.toFirst();(md=mni.current());++mni)
5772 {
5773 ClassDef *cd=md->getClassDef();
5774 if (cd!=0 && rightScopeMatch(cd->name(),className))
5775 {
5776 LockingPtr<ArgumentList> templAl = md->templateArguments();
5777 if (templAl!=0)
5778 {
5779 warnMsg+=" template ";
5780 warnMsg+=tempArgListToString(templAl.pointer());
5781 warnMsg+='\n';
5782 }
5783 warnMsg+=" ";
5784 if (md->typeString())
5785 {
5786 warnMsg+=md->typeString();
5787 warnMsg+=' ';
5788 }
5789 QCString qScope = cd->qualifiedNameWithTemplateParameters();
5790 if (!qScope.isEmpty())
5791 warnMsg+=qScope+"::"+md->name();
5792 if (md->argsString())
5793 warnMsg+=md->argsString();
5794 if (noMatchCount>1)
5795 {
5796 QCString lineFile;
5797 lineFile.sprintf(" at line %d of file ",md->getDefLine());
5798 warnMsg+=lineFile+md->getDefFileName();
5799 }
5800
5801 warnMsg+='\n';
5802 }
5803 }
5804 }
5805 warn_simple(root->fileName,root->startLine,warnMsg);
5806 }
5807 }
5808 else if (cd) // member specialization
5809 {
5810 MemberNameIterator mni(*mn);
5811 MemberDef *declMd=0;
5812 MemberDef *md=0;
5813 for (mni.toFirst();(md=mni.current());++mni)
5814 {
5815 if (md->getClassDef()==cd)
5816 {
5817 // TODO: we should probably also check for matching arguments
5818 declMd = md;
5819 break;
5820 }
5821 }
5822 MemberDef::MemberType mtype=MemberDef::Function;
5823 ArgumentList *tArgList = new ArgumentList;
5824 // getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
5825 md=new MemberDef(
5826 root->fileName,root->startLine,
5827 funcType,funcName,funcArgs,exceptions,
5828 declMd ? declMd->protection() : root->protection,
5829 root->virt,root->stat,Member,
5830 mtype,tArgList,root->argList);
5831 //printf("new specialized member %s args=`%s'\n",md->name().data(),funcArgs.data());
5832 md->setTagInfo(rootNav->tagInfo());
5833 md->setMemberClass(cd);
5834 md->setTemplateSpecialization(TRUE);
5835 md->setTypeConstraints(root->typeConstr);
5836 md->setDefinition(funcDecl);
5837 md->enableCallGraph(root->callGraph);
5838 md->enableCallerGraph(root->callerGraph);
5839 md->setDocumentation(root->doc,root->docFile,root->docLine);
5840 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5841 md->setDocsForDefinition(!root->proto);
5842 md->setPrototype(root->proto);
5843 md->addSectionsToDefinition(root->anchors);
5844 md->setBodySegment(root->bodyLine,root->endBodyLine);
5845 FileDef *fd=rootNav->fileDef();
5846 md->setBodyDef(fd);
5847 md->setMemberSpecifiers(root->spec);
5848 md->setMemberGroupId(root->mGrpId);
5849 mn->append(md);
5850 cd->insertMember(md);
5851 md->setRefItems(root->sli);
5852 delete tArgList;
5853 }
5854 else
5855 {
5856 //printf("*** Specialized member %s of unknown scope %s%s found!\n",
5857 // scopeName.data(),funcName.data(),funcArgs.data());
5858 }
5859 }
5860 else if (overloaded) // check if the function belongs to only one class
5861 {
5862 // for unique overloaded member we allow the class to be
5863 // omitted, this is to be Qt compatable. Using this should
5864 // however be avoided, because it is error prone
5865 MemberNameIterator mni(*mn);
5866 MemberDef *md=mni.toFirst();
5867 ASSERT(md);
5868 ClassDef *cd=md->getClassDef();
5869 ASSERT(cd);
5870 QCString className=cd->name().copy();
5871 ++mni;
5872 bool unique=TRUE;
5873 for (;(md=mni.current());++mni)
5874 {
5875 ClassDef *cd=md->getClassDef();
5876 if (className!=cd->name()) unique=FALSE;
5877 }
5878 if (unique)
5879 {
5880 MemberDef::MemberType mtype;
5881 if (root->mtype==Signal) mtype=MemberDef::Signal;
5882 else if (root->mtype==Slot) mtype=MemberDef::Slot;
5883 else if (root->mtype==DCOP) mtype=MemberDef::DCOP;
5884 else mtype=MemberDef::Function;
5885
5886 // new overloaded member function
5887 ArgumentList *tArgList =
5888 getTemplateArgumentsFromName(cd->name()+"::"+funcName,root->tArgLists);
5889 //printf("new related member %s args=`%s'\n",md->name().data(),funcArgs.data());
5890 MemberDef *md=new MemberDef(
5891 root->fileName,root->startLine,
5892 funcType,funcName,funcArgs,exceptions,
5893 root->protection,root->virt,root->stat,Related,
5894 mtype,tArgList,root->argList);
5895 md->setTagInfo(rootNav->tagInfo());
5896 md->setTypeConstraints(root->typeConstr);
5897 md->setMemberClass(cd);
5898 md->setDefinition(funcDecl);
5899 md->enableCallGraph(root->callGraph);
5900 md->enableCallerGraph(root->callerGraph);
5901 QCString doc=getOverloadDocs();
5902 doc+="<p>";
5903 doc+=root->doc;
5904 md->setDocumentation(doc,root->docFile,root->docLine);
5905 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
5906 md->setDocsForDefinition(!root->proto);
5907 md->setPrototype(root->proto);
5908 md->addSectionsToDefinition(root->anchors);
5909 md->setBodySegment(root->bodyLine,root->endBodyLine);
5910 FileDef *fd=rootNav->fileDef();
5911 md->setBodyDef(fd);
5912 md->setMemberSpecifiers(root->spec);
5913 md->setMemberGroupId(root->mGrpId);
5914 mn->append(md);
5915 cd->insertMember(md);
5916 cd->insertUsedFile(root->fileName);
5917 md->setRefItems(root->sli);
5918 }
5919 }
5920 else // unrelated function with the same name as a member
5921 {
5922 if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
5923 {
5924 QCString fullFuncDecl=funcDecl.copy();
5925 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
5926 warn(root->fileName,root->startLine,
5927 "warning: Cannot determine class for function\n%s",
5928 fullFuncDecl.data()
5929 );
5930 }
5931 }
5932 }
5933 else if (isRelated && !root->relates.isEmpty())
5934 {
5935 Debug::print(Debug::FindMembers,0,"2. related function\n"
5936 " scopeName=%s className=%s\n",scopeName.data(),className.data());
5937 if (className.isEmpty()) className=root->relates;
5938 ClassDef *cd;
5939 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
5940 if ((cd=getClass(scopeName)))
5941 {
5942 bool newMember=TRUE; // assume we have a new member
5943 bool newMemberName=FALSE;
5944 bool isDefine=FALSE;
5945 {
5946 MemberName *mn = Doxygen::functionNameSDict->find(funcName);
5947 if (mn)
5948 {
5949 MemberDef *md = mn->first();
5950 while (md && !isDefine)
5951 {
5952 isDefine = isDefine || md->isDefine();
5953 md = mn->next();
5954 }
5955 }
5956 }
5957
5958 FileDef *fd=rootNav->fileDef();
5959
5960 if ((mn=Doxygen::memberNameSDict->find(funcName))==0)
5961 {
5962 mn=new MemberName(funcName);
5963 newMemberName=TRUE; // we create a new member name
5964 }
5965 else
5966 {
5967 MemberDef *rmd=mn->first();
5968 while (rmd && newMember) // see if we got another member with matching arguments
5969 {
5970 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
5971
5972 newMember=
5973 !matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
5974 cd,fd,root->argList,
5975 TRUE);
5976 if (newMember) rmd=mn->next();
5977 }
5978 if (!newMember && rmd) // member already exists as rmd -> add docs
5979 {
5980 //printf("addMemberDocs for related member %s\n",root->name.data());
5981 //rmd->setMemberDefTemplateArguments(root->mtArgList);
5982 addMemberDocs(rootNav,rmd,funcDecl,0,overloaded);
5983 }
5984 }
5985
5986 if (newMember) // need to create a new member
5987 {
5988 MemberDef::MemberType mtype;
5989 if (isDefine)
5990 mtype=MemberDef::Define;
5991 else if (root->mtype==Signal)
5992 mtype=MemberDef::Signal;
5993 else if (root->mtype==Slot)
5994 mtype=MemberDef::Slot;
5995 else if (root->mtype==DCOP)
5996 mtype=MemberDef::DCOP;
5997 else
5998 mtype=MemberDef::Function;
5999
6000 //printf("New related name `%s' `%d'\n",funcName.data(),
6001 // root->argList ? (int)root->argList->count() : -1);
6002
6003 // new related (member) function
6004#if 0 // removed as it doesn't handle related template functions correctly
6005 ArgumentList *tArgList =
6006 getTemplateArgumentsFromName(scopeName+"::"+funcName,root->tArgLists);
6007 MemberDef *md=new MemberDef(
6008 root->fileName,root->startLine,
6009 funcType,funcName,funcArgs,exceptions,
6010 root->protection,root->virt,root->stat,TRUE,
6011 mtype,tArgList,funcArgs.isEmpty() ? 0 : root->argList);
6012#endif
6013 // first note that we pass:
6014 // (root->tArgLists ? root->tArgLists->last() : 0)
6015 // for the template arguments fo the new "member."
6016 // this accurately reflects the template arguments of
6017 // the related function, which don't have to do with
6018 // those of the related class.
6019 MemberDef *md=new MemberDef(
6020 root->fileName,root->startLine,
6021 funcType,funcName,funcArgs,exceptions,
6022 root->protection,root->virt,
6023 root->stat && !isMemberOf,
6024 isMemberOf ? Foreign : isRelated ? Related : Member,
6025 mtype,
6026 (root->tArgLists ? root->tArgLists->last() : 0),
6027 funcArgs.isEmpty() ? 0 : root->argList);
6028 //
6029 // we still have the problem that
6030 // MemberDef::writeDocumentation() in memberdef.cpp
6031 // writes the template argument list for the class,
6032 // as if this member is a member of the class.
6033 // fortunately, MemberDef::writeDocumentation() has
6034 // a special mechanism that allows us to totally
6035 // override the set of template argument lists that
6036 // are printed. We use that and set it to the
6037 // template argument lists of the related function.
6038 //
6039 md->setDefinitionTemplateParameterLists(root->tArgLists);
6040
6041 md->setTagInfo(rootNav->tagInfo());
6042
6043
6044
6045 //printf("Related member name=`%s' decl=`%s' bodyLine=`%d'\n",
6046 // funcName.data(),funcDecl.data(),root->bodyLine);
6047
6048 // try to find the matching line number of the body from the
6049 // global function list
6050 bool found=FALSE;
6051 if (root->bodyLine==-1)
6052 {
6053 MemberName *rmn=Doxygen::functionNameSDict->find(funcName);
6054 if (rmn)
6055 {
6056 MemberDef *rmd=rmn->first();
6057 while (rmd && !found) // see if we got another member with matching arguments
6058 {
6059 LockingPtr<ArgumentList> rmdAl = rmd->argumentList();
6060 // check for matching argument lists
6061 if (
6062 matchArguments2(rmd->getOuterScope(),rmd->getFileDef(),rmdAl.pointer(),
6063 cd,fd,root->argList,
6064 TRUE)
6065 )
6066 {
6067 found=TRUE;
6068 }
6069 if (!found) rmd=rmn->next();
6070 }
6071 if (rmd) // member found -> copy line number info
6072 {
6073 md->setBodySegment(rmd->getStartBodyLine(),rmd->getEndBodyLine());
6074 md->setBodyDef(rmd->getBodyDef());
6075 //md->setBodyMember(rmd);
6076 }
6077 }
6078 }
6079 if (!found) // line number could not be found or is available in this
6080 // entry
6081 {
6082 md->setBodySegment(root->bodyLine,root->endBodyLine);
6083 md->setBodyDef(fd);
6084 }
6085
6086 //if (root->mGrpId!=-1)
6087 //{
6088 // md->setMemberGroup(memberGroupDict[root->mGrpId]);
6089 //}
6090 md->setMemberClass(cd);
6091 md->setMemberSpecifiers(root->spec);
6092 md->setDefinition(funcDecl);
6093 md->enableCallGraph(root->callGraph);
6094 md->enableCallerGraph(root->callerGraph);
6095 md->setDocumentation(root->doc,root->docFile,root->docLine);
6096 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6097 md->setDocsForDefinition(!root->proto);
6098 md->setPrototype(root->proto);
6099 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6100 md->addSectionsToDefinition(root->anchors);
6101 md->setMemberGroupId(root->mGrpId);
6102 //md->setMemberDefTemplateArguments(root->mtArgList);
6103 mn->append(md);
6104 cd->insertMember(md);
6105 cd->insertUsedFile(root->fileName);
6106 md->setRefItems(root->sli);
6107 if (root->relatesType == Duplicate) md->setRelatedAlso(cd);
6108 addMemberToGroups(root,md);
6109 //printf("Adding member=%s\n",md->name().data());
6110 if (newMemberName)
6111 {
6112 //Doxygen::memberNameList.append(mn);
6113 //Doxygen::memberNameDict.insert(funcName,mn);
6114 Doxygen::memberNameSDict->append(funcName,mn);
6115 }
6116 }
6117 if (root->relatesType == Duplicate)
6118 {
6119 if (!findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl))
6120 {
6121 QCString fullFuncDecl=funcDecl.copy();
6122 if (isFunc) fullFuncDecl+=argListToString(root->argList,TRUE);
6123 warn(root->fileName,root->startLine,
6124 "warning: Cannot determine file/namespace for relatedalso function\n%s",
6125 fullFuncDecl.data()
6126 );
6127 }
6128 }
6129 }
6130 else
6131 {
6132 warn_undoc(root->fileName,root->startLine,
6133 "warning: class `%s' for related function `%s' is not "
6134 "documented.",
6135 className.data(),funcName.data()
6136 );
6137 }
6138 }
6139 else if (rootNav->parent() && rootNav->parent()->section()==Entry::OBJCIMPL_SEC)
6140 {
6141localObjCMethod:
6142 ClassDef *cd;
6143 //printf("scopeName=`%s' className=`%s'\n",scopeName.data(),className.data());
6144 if (Config_getBool("EXTRACT_LOCAL_METHODS") && (cd=getClass(scopeName)))
6145 {
6146 //printf("Local objective C method `%s' of class `%s' found\n",root->name.data(),cd->name().data());
6147 MemberDef *md=new MemberDef(
6148 root->fileName,root->startLine,
6149 funcType,funcName,funcArgs,exceptions,
6150 root->protection,root->virt,root->stat,Member,
6151 MemberDef::Function,0,root->argList);
6152 md->setTagInfo(rootNav->tagInfo());
6153 md->makeImplementationDetail();
6154 md->setMemberClass(cd);
6155 md->setDefinition(funcDecl);
6156 md->enableCallGraph(root->callGraph);
6157 md->enableCallerGraph(root->callerGraph);
6158 md->setDocumentation(root->doc,root->docFile,root->docLine);
6159 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6160 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6161 md->setDocsForDefinition(!root->proto);
6162 md->setPrototype(root->proto);
6163 md->addSectionsToDefinition(root->anchors);
6164 md->setBodySegment(root->bodyLine,root->endBodyLine);
6165 FileDef *fd=rootNav->fileDef();
6166 md->setBodyDef(fd);
6167 md->setMemberSpecifiers(root->spec);
6168 md->setMemberGroupId(root->mGrpId);
6169 cd->insertMember(md);
6170 cd->insertUsedFile(root->fileName);
6171 md->setRefItems(root->sli);
6172 if ((mn=Doxygen::memberNameSDict->find(root->name)))
6173 {
6174 mn->append(md);
6175 }
6176 else
6177 {
6178 mn = new MemberName(root->name);
6179 mn->append(md);
6180 Doxygen::memberNameSDict->append(root->name,mn);
6181 }
6182 }
6183 else
6184 {
6185 // local objective C method found for class without interface
6186 }
6187 }
6188 else // unrelated not overloaded member found
6189 {
6190 bool globMem = findGlobalMember(rootNav,namespaceName,funcName,funcTempList,funcArgs,funcDecl);
6191 if (className.isEmpty() && !globMem)
6192 {
6193 warn(root->fileName,root->startLine,
6194 "warning: class for member `%s' cannot "
6195 "be found.", funcName.data()
6196 );
6197 }
6198 else if (!className.isEmpty() && !globMem)
6199 {
6200 warn(root->fileName,root->startLine,
6201 "warning: member `%s' of class `%s' cannot be found",
6202 funcName.data(),className.data());
6203 }
6204 }
6205 }
6206 else
6207 {
6208 // this should not be called
6209 warn(root->fileName,root->startLine,
6210 "warning: member with no name found.");
6211 }
6212 return;
6213}
6214
6215//----------------------------------------------------------------------
6216// find the members corresponding to the different documentation blocks
6217// that are extracted from the sources.
6218
6219static void filterMemberDocumentation(EntryNav *rootNav)
6220{
6221 Entry *root = rootNav->entry();
6222 int i=-1,l;
6223 Debug::print(Debug::FindMembers,0,
6224 "findMemberDocumentation(): root->type=`%s' root->inside=`%s' root->name=`%s' root->args=`%s' section=%x root->spec=%d root->mGrpId=%d\n",
6225 root->type.data(),root->inside.data(),root->name.data(),root->args.data(),root->section,root->spec,root->mGrpId
6226 );
6227 //printf("rootNav->parent()->name()=%s\n",rootNav->parent()->name().data());
6228 bool isFunc=TRUE;
6229
6230 if (root->relatesType == Duplicate && !root->relates.isEmpty())
6231 {
6232 QCString tmp = root->relates;
6233 root->relates.resize(0);
6234 filterMemberDocumentation(rootNav);
6235 root->relates = tmp;
6236 }
6237
6238 if ( // detect func variable/typedef to func ptr
6239 (i=findFunctionPtr(root->type,root->lang,&l))!=-1
6240 )
6241 {
6242 //printf("Fixing function pointer!\n");
6243 // fix type and argument
6244 root->args.prepend(root->type.right(root->type.length()-i-l));
6245 root->type=root->type.left(i+l);
6246 //printf("Results type=%s,name=%s,args=%s\n",root->type.data(),root->name.data(),root->args.data());
6247 isFunc=FALSE;
6248 }
6249 else if ((root->type.left(8)=="typedef " && root->args.find('(')!=-1))
6250 // detect function types marked as functions
6251 {
6252 isFunc=FALSE;
6253 }
6254
6255 //printf("Member %s isFunc=%d\n",root->name.data(),isFunc);
6256 if (root->section==Entry::MEMBERDOC_SEC)
6257 {
6258 //printf("Documentation for inline member `%s' found args=`%s'\n",
6259 // root->name.data(),root->args.data());
6260 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6261 if (root->type.isEmpty())
6262 {
6263 findMember(rootNav,root->name+root->args+root->exception,FALSE,isFunc);
6264 }
6265 else
6266 {
6267 findMember(rootNav,root->type+" "+root->name+root->args+root->exception,FALSE,isFunc);
6268 }
6269 }
6270 else if (root->section==Entry::OVERLOADDOC_SEC)
6271 {
6272 //printf("Overloaded member %s found\n",root->name.data());
6273 findMember(rootNav,root->name,TRUE,isFunc);
6274 }
6275 else if
6276 ((root->section==Entry::FUNCTION_SEC // function
6277 ||
6278 (root->section==Entry::VARIABLE_SEC && // variable
6279 !root->type.isEmpty() && // with a type
6280 g_compoundKeywordDict.find(root->type)==0 // that is not a keyword
6281 // (to skip forward declaration of class etc.)
6282 )
6283 )
6284 )
6285 {
6286 //printf("Documentation for member `%s' found args=`%s' excp=`%s'\n",
6287 // root->name.data(),root->args.data(),root->exception.data());
6288 //if (root->relates.length()) printf(" Relates %s\n",root->relates.data());
6289 //printf("Inside=%s\n Relates=%s\n",root->inside.data(),root->relates.data());
6290 if (root->type=="friend class" || root->type=="friend struct" ||
6291 root->type=="friend union")
6292 {
6293 findMember(rootNav,
6294 root->type+" "+
6295 root->name,
6296 FALSE,FALSE);
6297
6298 }
6299 else if (!root->type.isEmpty())
6300 {
6301 findMember(rootNav,
6302 root->type+" "+
6303 root->inside+
6304 root->name+
6305 root->args+
6306 root->exception,
6307 FALSE,isFunc);
6308 }
6309 else
6310 {
6311 findMember(rootNav,
6312 root->inside+
6313 root->name+
6314 root->args+
6315 root->exception,
6316 FALSE,isFunc);
6317 }
6318 }
6319 else if (root->section==Entry::DEFINE_SEC && !root->relates.isEmpty())
6320 {
6321 findMember(rootNav,root->name+root->args,FALSE,!root->args.isEmpty());
6322 }
6323 else if (root->section==Entry::VARIABLEDOC_SEC)
6324 {
6325 //printf("Documentation for variable %s found\n",root->name.data());
6326 //if (!root->relates.isEmpty()) printf(" Relates %s\n",root->relates.data());
6327 findMember(rootNav,root->name,FALSE,FALSE);
6328 }
6329 else
6330 {
6331 // skip section
6332 //printf("skip section\n");
6333 }
6334}
6335
6336static void findMemberDocumentation(EntryNav *rootNav)
6337{
6338 if (rootNav->section()==Entry::MEMBERDOC_SEC ||
6339 rootNav->section()==Entry::OVERLOADDOC_SEC ||
6340 rootNav->section()==Entry::FUNCTION_SEC ||
6341 rootNav->section()==Entry::VARIABLE_SEC ||
6342 rootNav->section()==Entry::VARIABLEDOC_SEC ||
6343 rootNav->section()==Entry::DEFINE_SEC
6344 )
6345 {
6346 rootNav->loadEntry(g_storage);
6347
6348 filterMemberDocumentation(rootNav);
6349
6350 rootNav->releaseEntry();
6351 }
6352 if (rootNav->children())
6353 {
6354 EntryNavListIterator eli(*rootNav->children());
6355 EntryNav *e;
6356 for (;(e=eli.current());++eli)
6357 {
6358 if (e->section()!=Entry::ENUM_SEC) findMemberDocumentation(e);
6359 }
6360 }
6361}
6362
6363//----------------------------------------------------------------------
6364
6365static void findObjCMethodDefinitions(EntryNav *rootNav)
6366{
6367 if (rootNav->children())
6368 {
6369 EntryNavListIterator eli(*rootNav->children());
6370 EntryNav *objCImplNav;
6371 for (;(objCImplNav=eli.current());++eli)
6372 {
6373 if (objCImplNav->section()==Entry::OBJCIMPL_SEC && objCImplNav->children())
6374 {
6375 EntryNavListIterator seli(*objCImplNav->children());
6376 EntryNav *objCMethodNav;
6377 for (;(objCMethodNav=seli.current());++seli)
6378 {
6379 if (objCMethodNav->section()==Entry::FUNCTION_SEC)
6380 {
6381 objCMethodNav->loadEntry(g_storage);
6382 Entry *objCMethod = objCMethodNav->entry();
6383
6384 //Printf(" Found ObjC method definition %s\n",objCMethod->name.data());
6385 findMember(objCMethodNav, objCMethod->type+" "+objCImplNav->name()+"::"+
6386 objCMethod->name+" "+objCMethod->args, FALSE,TRUE);
6387 objCMethod->section=Entry::EMPTY_SEC;
6388
6389 objCMethodNav->releaseEntry();
6390 }
6391 }
6392 }
6393 }
6394 }
6395}
6396
6397//----------------------------------------------------------------------
6398// find and add the enumeration to their classes, namespaces or files
6399
6400static void findEnums(EntryNav *rootNav)
6401{
6402 if (rootNav->section()==Entry::ENUM_SEC)
6403 // non anonymous enumeration
6404 {
6405 rootNav->loadEntry(g_storage);
6406 Entry *root = rootNav->entry();
6407
6408 MemberDef *md=0;
6409 ClassDef *cd=0;
6410 FileDef *fd=0;
6411 NamespaceDef *nd=0;
6412 MemberNameSDict *mnsd=0;
6413 bool isGlobal;
6414 bool isRelated=FALSE;
6415 bool isMemberOf=FALSE;
6416 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
6417 int i;
6418
6419 QCString name;
6420 QCString scope;
6421
6422 if ((i=root->name.findRev("::"))!=-1) // scope is specified
6423 {
6424 scope=root->name.left(i); // extract scope
6425 name=root->name.right(root->name.length()-i-2); // extract name
6426 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6427 }
6428 else // no scope, check the scope in which the docs where found
6429 {
6430 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
6431 && !rootNav->parent()->name().isEmpty()
6432 ) // found enum docs inside a compound
6433 {
6434 scope=rootNav->parent()->name();
6435 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6436 }
6437 name=root->name;
6438 }
6439
6440 if (!root->relates.isEmpty())
6441 { // related member, prefix user specified scope
6442 isRelated=TRUE;
6443 isMemberOf=(root->relatesType == MemberOf);
6444 if (getClass(root->relates)==0 && !scope.isEmpty())
6445 scope=mergeScopes(scope,root->relates);
6446 else
6447 scope=root->relates.copy();
6448 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6449 }
6450
6451 if (cd && !name.isEmpty()) // found a enum inside a compound
6452 {
6453 //printf("Enum `%s'::`%s'\n",cd->name(),name.data());
6454 fd=0;
6455 mnsd=Doxygen::memberNameSDict;
6456 isGlobal=FALSE;
6457 }
6458 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
6459 {
6460 mnsd=Doxygen::functionNameSDict;
6461 isGlobal=TRUE;
6462 }
6463 else // found a global enum
6464 {
6465 fd=rootNav->fileDef();
6466 mnsd=Doxygen::functionNameSDict;
6467 isGlobal=TRUE;
6468 }
6469
6470 if (!name.isEmpty())
6471 {
6472 // new enum type
6473 md = new MemberDef(
6474 root->fileName,root->startLine,
6475 0,name,0,0,
6476 root->protection,Normal,FALSE,
6477 isMemberOf ? Foreign : isRelated ? Related : Member,
6478 MemberDef::Enumeration,
6479 0,0);
6480 md->setTagInfo(rootNav->tagInfo());
6481 if (!isGlobal) md->setMemberClass(cd); else md->setFileDef(fd);
6482 md->setBodySegment(root->bodyLine,root->endBodyLine);
6483 md->setBodyDef(rootNav->fileDef());
6484 //printf("Enum %s definition at line %d of %s: protection=%d\n",
6485 // root->name.data(),root->bodyLine,root->fileName.data(),root->protection);
6486 md->addSectionsToDefinition(root->anchors);
6487 md->setMemberGroupId(root->mGrpId);
6488 md->enableCallGraph(root->callGraph);
6489 md->enableCallerGraph(root->callerGraph);
6490 //printf("%s::setRefItems(%d)\n",md->name().data(),root->sli?root->sli->count():-1);
6491 md->setRefItems(root->sli);
6492 //printf("found enum %s nd=%p\n",name.data(),nd);
6493 bool defSet=FALSE;
6494 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
6495 {
6496 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
6497 {
6498 md->setDefinition(name);
6499 }
6500 else
6501 {
6502 md->setDefinition(nd->name()+"::"+name);
6503 }
6504 //printf("definition=%s\n",md->definition());
6505 defSet=TRUE;
6506 md->setNamespace(nd);
6507 nd->insertMember(md);
6508 }
6509
6510 // even if we have already added the enum to a namespace, we still
6511 // also want to add it to other appropriate places such as file
6512 // or class.
6513 if (isGlobal)
6514 {
6515 if (!defSet) md->setDefinition(name);
6516 if (fd==0 && rootNav->parent())
6517 {
6518 fd=rootNav->parent()->fileDef();
6519 }
6520 if (fd)
6521 {
6522 md->setFileDef(fd);
6523 fd->insertMember(md);
6524 }
6525 }
6526 else if (cd)
6527 {
6528 if (isRelated || Config_getBool("HIDE_SCOPE_NAMES"))
6529 {
6530 md->setDefinition(name);
6531 }
6532 else
6533 {
6534 md->setDefinition(cd->name()+"::"+name);
6535 }
6536 cd->insertMember(md);
6537 cd->insertUsedFile(root->fileName);
6538 }
6539 md->setDocumentation(root->doc,root->docFile,root->docLine);
6540 md->setDocsForDefinition(!root->proto);
6541 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6542 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6543
6544 //printf("Adding member=%s\n",md->name().data());
6545 MemberName *mn;
6546 if ((mn=(*mnsd)[name]))
6547 {
6548 // this is used if the same enum is in multiple namespaces/classes
6549 mn->append(md);
6550 }
6551 else // new enum name
6552 {
6553 mn = new MemberName(name);
6554 mn->append(md);
6555 mnsd->append(name,mn);
6556 //printf("add %s to new memberName. Now %d members\n",
6557 // name.data(),mn->count());
6558 }
6559 addMemberToGroups(root,md);
6560
6561#if 0
6562 if (rootNav->children())
6563 {
6564 EntryNavListIterator eli(*rootNav->children());
6565 EntryNav *e;
6566 for (;(e=eli.current());++eli)
6567 {
6568 //printf("e->name=%s isRelated=%d\n",e->name.data(),isRelated);
6569 MemberName *fmn=0;
6570 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
6571 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
6572 // get list of members with the same name as the field
6573 {
6574 MemberNameIterator fmni(*fmn);
6575 MemberDef *fmd;
6576 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
6577 {
6578 if (fmd->isEnumValue())
6579 {
6580 //printf("found enum value with same name\n");
6581 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
6582 {
6583 NamespaceDef *fnd=fmd->getNamespaceDef();
6584 if (fnd==nd) // enum value is inside a namespace
6585 {
6586 md->insertEnumField(fmd);
6587 fmd->setEnumScope(md);
6588 }
6589 }
6590 else if (isGlobal)
6591 {
6592 FileDef *ffd=fmd->getFileDef();
6593 if (ffd==fd) // enum value has file scope
6594 {
6595 md->insertEnumField(fmd);
6596 fmd->setEnumScope(md);
6597 }
6598 }
6599 else if (isRelated && cd) // reparent enum value to
6600 // match the enum's scope
6601 {
6602 md->insertEnumField(fmd); // add field def to list
6603 fmd->setEnumScope(md); // cross ref with enum name
6604 fmd->setEnumClassScope(cd); // cross ref with enum name
6605 fmd->setOuterScope(cd);
6606 fmd->makeRelated();
6607 cd->insertMember(fmd);
6608 }
6609 else
6610 {
6611 ClassDef *fcd=fmd->getClassDef();
6612 if (fcd==cd) // enum value is inside a class
6613 {
6614 //printf("Inserting enum field %s in enum scope %s\n",
6615 // fmd->name().data(),md->name().data());
6616 md->insertEnumField(fmd); // add field def to list
6617 fmd->setEnumScope(md); // cross ref with enum name
6618 }
6619 }
6620 }
6621 }
6622 }
6623 }
6624 }
6625#endif
6626 }
6627
6628 rootNav->releaseEntry();
6629 }
6630 else
6631 {
6632 RECURSE_ENTRYTREE(findEnums,rootNav);
6633 }
6634}
6635
6636//----------------------------------------------------------------------
6637
6638static void addEnumValuesToEnums(EntryNav *rootNav)
6639{
6640 if (rootNav->section()==Entry::ENUM_SEC)
6641 // non anonymous enumeration
6642 {
6643 rootNav->loadEntry(g_storage);
6644 Entry *root = rootNav->entry();
6645
6646 ClassDef *cd=0;
6647 FileDef *fd=0;
6648 NamespaceDef *nd=0;
6649 MemberNameSDict *mnsd=0;
6650 bool isGlobal;
6651 bool isRelated=FALSE;
6652 //printf("Found enum with name `%s' relates=%s\n",root->name.data(),root->relates.data());
6653 int i;
6654
6655 QCString name;
6656 QCString scope;
6657
6658 if ((i=root->name.findRev("::"))!=-1) // scope is specified
6659 {
6660 scope=root->name.left(i); // extract scope
6661 name=root->name.right(root->name.length()-i-2); // extract name
6662 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6663 }
6664 else // no scope, check the scope in which the docs where found
6665 {
6666 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
6667 && !rootNav->parent()->name().isEmpty()
6668 ) // found enum docs inside a compound
6669 {
6670 scope=rootNav->parent()->name();
6671 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6672 }
6673 name=root->name;
6674 }
6675
6676 if (!root->relates.isEmpty())
6677 { // related member, prefix user specified scope
6678 isRelated=TRUE;
6679 if (getClass(root->relates)==0 && !scope.isEmpty())
6680 scope=mergeScopes(scope,root->relates);
6681 else
6682 scope=root->relates.copy();
6683 if ((cd=getClass(scope))==0) nd=getResolvedNamespace(scope);
6684 }
6685
6686 if (cd && !name.isEmpty()) // found a enum inside a compound
6687 {
6688 //printf("Enum in class `%s'::`%s'\n",cd->name().data(),name.data());
6689 fd=0;
6690 mnsd=Doxygen::memberNameSDict;
6691 isGlobal=FALSE;
6692 }
6693 else if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@') // found enum inside namespace
6694 {
6695 //printf("Enum in namespace `%s'::`%s'\n",nd->name().data(),name.data());
6696 mnsd=Doxygen::functionNameSDict;
6697 isGlobal=TRUE;
6698 }
6699 else // found a global enum
6700 {
6701 fd=rootNav->fileDef();
6702 //printf("Enum in file `%s': `%s'\n",fd->name().data(),name.data());
6703 mnsd=Doxygen::functionNameSDict;
6704 isGlobal=TRUE;
6705 }
6706
6707 if (!name.isEmpty())
6708 {
6709 MemberName *mn = mnsd->find(name); // for all members with this name
6710 if (mn)
6711 {
6712 MemberNameIterator mni(*mn);
6713 MemberDef *md;
6714 for (mni.toFirst(); (md=mni.current()) ; ++mni) // for each enum in this list
6715 {
6716 if (md->isEnumerate() && rootNav->children())
6717 {
6718 EntryNavListIterator eli(*rootNav->children()); // for each enum value
6719 EntryNav *e;
6720 for (;(e=eli.current());++eli)
6721 {
6722 SrcLangExt sle;
6723 if (rootNav->fileDef() &&
6724 ( (sle=getLanguageFromFileName(rootNav->fileDef()->name()))==SrcLangExt_CSharp
6725 || sle==SrcLangExt_Java || sle==SrcLangExt_XML
6726 )
6727 )
6728 {
6729 // Unlike C++, for C# enum value are only inside the enum
6730 // scope, so we must create them here and only add them to the
6731 // enum
6732 e->loadEntry(g_storage);
6733 Entry *root = e->entry();
6734 if (md->qualifiedName()==rootNav->name()) // enum value scope matches that of the enum
6735 {
6736 MemberDef *fmd=new MemberDef(
6737 root->fileName,root->startLine,
6738 root->type,root->name,root->args,0,
6739 Public, Normal,root->stat,Member,
6740 MemberDef::EnumValue,0,0);
6741 if (md->getClassDef()) fmd->setMemberClass(md->getClassDef());
6742 else if (md->getNamespaceDef()) fmd->setNamespace(md->getNamespaceDef());
6743 else if (md->getFileDef()) fmd->setFileDef(md->getFileDef());
6744 fmd->setOuterScope(md->getOuterScope());
6745 fmd->setTagInfo(e->tagInfo());
6746 fmd->setDocumentation(root->doc,root->docFile,root->docLine);
6747 fmd->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6748 fmd->addSectionsToDefinition(root->anchors);
6749 fmd->setInitializer(root->initializer);
6750 fmd->setMaxInitLines(root->initLines);
6751 fmd->setMemberGroupId(root->mGrpId);
6752 fmd->setExplicitExternal(root->explicitExternal);
6753 fmd->setRefItems(root->sli);
6754 if (fmd)
6755 {
6756 md->insertEnumField(fmd);
6757 fmd->setEnumScope(md);
6758 }
6759 }
6760 e->releaseEntry();
6761 }
6762 else
6763 {
6764 //printf("e->name=%s isRelated=%d\n",e->name().data(),isRelated);
6765 MemberName *fmn=0;
6766 MemberNameSDict *emnsd = isRelated ? Doxygen::functionNameSDict : mnsd;
6767 if (!e->name().isEmpty() && (fmn=(*emnsd)[e->name()]))
6768 // get list of members with the same name as the field
6769 {
6770 MemberNameIterator fmni(*fmn);
6771 MemberDef *fmd;
6772 for (fmni.toFirst(); (fmd=fmni.current()) ; ++fmni)
6773 {
6774 if (fmd->isEnumValue() && fmd->getOuterScope()==md->getOuterScope()) // in same scope
6775 {
6776 //printf("found enum value with same name %s in scope %s\n",
6777 // fmd->name().data(),fmd->getOuterScope()->name().data());
6778 if (nd && !nd->name().isEmpty() && nd->name().at(0)!='@')
6779 {
6780 NamespaceDef *fnd=fmd->getNamespaceDef();
6781 if (fnd==nd) // enum value is inside a namespace
6782 {
6783 md->insertEnumField(fmd);
6784 fmd->setEnumScope(md);
6785 }
6786 }
6787 else if (isGlobal)
6788 {
6789 FileDef *ffd=fmd->getFileDef();
6790 if (ffd==fd) // enum value has file scope
6791 {
6792 md->insertEnumField(fmd);
6793 fmd->setEnumScope(md);
6794 }
6795 }
6796 else if (isRelated && cd) // reparent enum value to
6797 // match the enum's scope
6798 {
6799 md->insertEnumField(fmd); // add field def to list
6800 fmd->setEnumScope(md); // cross ref with enum name
6801 fmd->setEnumClassScope(cd); // cross ref with enum name
6802 fmd->setOuterScope(cd);
6803 fmd->makeRelated();
6804 cd->insertMember(fmd);
6805 }
6806 else
6807 {
6808 ClassDef *fcd=fmd->getClassDef();
6809 if (fcd==cd) // enum value is inside a class
6810 {
6811 //printf("Inserting enum field %s in enum scope %s\n",
6812 // fmd->name().data(),md->name().data());
6813 md->insertEnumField(fmd); // add field def to list
6814 fmd->setEnumScope(md); // cross ref with enum name
6815 }
6816 }
6817 }
6818 }
6819 }
6820 }
6821 }
6822 }
6823 }
6824 }
6825 }
6826
6827 rootNav->releaseEntry();
6828 }
6829 else
6830 {
6831 RECURSE_ENTRYTREE(addEnumValuesToEnums,rootNav);
6832 }
6833}
6834
6835
6836//----------------------------------------------------------------------
6837// find the documentation blocks for the enumerations
6838
6839static void findEnumDocumentation(EntryNav *rootNav)
6840{
6841 if (rootNav->section()==Entry::ENUMDOC_SEC
6842 && !rootNav->name().isEmpty()
6843 && rootNav->name().at(0)!='@' // skip anonymous enums
6844 )
6845 {
6846 rootNav->loadEntry(g_storage);
6847 Entry *root = rootNav->entry();
6848
6849 //printf("Found docs for enum with name `%s' in context %s\n",
6850 // root->name.data(),root->parent->name.data());
6851 int i;
6852 QCString name;
6853 QCString scope;
6854 if ((i=root->name.findRev("::"))!=-1) // scope is specified as part of the name
6855 {
6856 name=root->name.right(root->name.length()-i-2); // extract name
6857 scope=root->name.left(i); // extract scope
6858 //printf("Scope=`%s' Name=`%s'\n",scope.data(),name.data());
6859 }
6860 else // just the name
6861 {
6862 name=root->name;
6863 }
6864 if (( rootNav->parent()->section() & Entry::SCOPE_MASK )
6865 && !rootNav->parent()->name().isEmpty()
6866 ) // found enum docs inside a compound
6867 {
6868 if (!scope.isEmpty()) scope.prepend("::");
6869 scope.prepend(rootNav->parent()->name());
6870 }
6871 ClassDef *cd=getClass(scope);
6872
6873 if (!name.isEmpty())
6874 {
6875 bool found=FALSE;
6876 if (cd)
6877 {
6878 //printf("Enum: scope=`%s' name=`%s'\n",cd->name(),name.data());
6879 QCString className=cd->name().copy();
6880 MemberName *mn=Doxygen::memberNameSDict->find(name);
6881 if (mn)
6882 {
6883 MemberNameIterator mni(*mn);
6884 MemberDef *md;
6885 for (mni.toFirst();(md=mni.current()) && !found;++mni)
6886 {
6887 ClassDef *cd=md->getClassDef();
6888 if (cd && cd->name()==className && md->isEnumerate())
6889 {
6890 // documentation outside a compound overrides the documentation inside it
6891#if 0
6892 if (!md->documentation() || rootNav->parent()->name().isEmpty())
6893#endif
6894 {
6895 md->setDocumentation(root->doc,root->docFile,root->docLine);
6896 md->setDocsForDefinition(!root->proto);
6897 }
6898
6899 // brief descriptions inside a compound override the documentation
6900 // outside it
6901#if 0
6902 if (!md->briefDescription() || !rootNav->parent()->name().isEmpty())
6903#endif
6904 {
6905 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6906 }
6907
6908 if (!md->inbodyDocumentation() || !rootNav->parent()->name().isEmpty())
6909 {
6910 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6911 }
6912
6913 if (root->mGrpId!=-1 && md->getMemberGroupId()==-1)
6914 {
6915 md->setMemberGroupId(root->mGrpId);
6916 }
6917
6918 md->addSectionsToDefinition(root->anchors);
6919 md->setRefItems(root->sli);
6920
6921 GroupDef *gd=md->getGroupDef();
6922 if (gd==0 &&root->groups->first()!=0) // member not grouped but out-of-line documentation is
6923 {
6924 addMemberToGroups(root,md);
6925 }
6926
6927 found=TRUE;
6928 }
6929 }
6930 }
6931 else
6932 {
6933 //printf("MemberName %s not found!\n",name.data());
6934 }
6935 }
6936 else // enum outside class
6937 {
6938 //printf("Enum outside class: %s grpId=%d\n",name.data(),root->mGrpId);
6939 MemberName *mn=Doxygen::functionNameSDict->find(name);
6940 if (mn)
6941 {
6942 MemberNameIterator mni(*mn);
6943 MemberDef *md;
6944 for (mni.toFirst();(md=mni.current()) && !found;++mni)
6945 {
6946 if (md->isEnumerate())
6947 {
6948 md->setDocumentation(root->doc,root->docFile,root->docLine);
6949 md->setDocsForDefinition(!root->proto);
6950 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
6951 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
6952 md->addSectionsToDefinition(root->anchors);
6953 md->setMemberGroupId(root->mGrpId);
6954
6955 GroupDef *gd=md->getGroupDef();
6956 if (gd==0 && root->groups->first()!=0) // member not grouped but out-of-line documentation is
6957 {
6958 addMemberToGroups(root,md);
6959 }
6960
6961 found=TRUE;
6962 }
6963 }
6964 }
6965 }
6966 if (!found)
6967 {
6968 warn(root->fileName,root->startLine,
6969 "warning: Documentation for undefined enum `%s' found.",
6970 name.data()
6971 );
6972 }
6973 }
6974
6975 rootNav->releaseEntry();
6976 }
6977 RECURSE_ENTRYTREE(findEnumDocumentation,rootNav);
6978}
6979
6980// seach for each enum (member or function) in mnl if it has documented
6981// enum values.
6982static void findDEV(const MemberNameSDict &mnsd)
6983{
6984 MemberName *mn;
6985 MemberNameSDict::Iterator mnli(mnsd);
6986 // for each member name
6987 for (mnli.toFirst();(mn=mnli.current());++mnli)
6988 {
6989 MemberDef *md;
6990 MemberNameIterator mni(*mn);
6991 // for each member definition
6992 for (mni.toFirst();(md=mni.current());++mni)
6993 {
6994 if (md->isEnumerate()) // member is an enum
6995 {
6996 LockingPtr<MemberList> fmdl = md->enumFieldList();
6997 int documentedEnumValues=0;
6998 if (fmdl!=0) // enum has values
6999 {
7000 MemberListIterator fmni(*fmdl);
7001 MemberDef *fmd;
7002 // for each enum value
7003 for (fmni.toFirst();(fmd=fmni.current());++fmni)
7004 {
7005 if (fmd->isLinkableInProject()) documentedEnumValues++;
7006 }
7007 }
7008 // at least one enum value is documented
7009 if (documentedEnumValues>0) md->setDocumentedEnumValues(TRUE);
7010 }
7011 }
7012 }
7013}
7014
7015// seach for each enum (member or function) if it has documented enum
7016// values.
7017static void findDocumentedEnumValues()
7018{
7019 findDEV(*Doxygen::memberNameSDict);
7020 findDEV(*Doxygen::functionNameSDict);
7021}
7022
7023//----------------------------------------------------------------------
7024
7025static void addMembersToIndex()
7026{
7027 MemberName *mn;
7028 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7029 // for each member name
7030 for (mnli.toFirst();(mn=mnli.current());++mnli)
7031 {
7032 MemberDef *md;
7033 MemberNameIterator mni(*mn);
7034 // for each member definition
7035 for (mni.toFirst();(md=mni.current());++mni)
7036 {
7037 addClassMemberNameToIndex(md);
7038 }
7039 }
7040 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7041 // for each member name
7042 for (fnli.toFirst();(mn=fnli.current());++fnli)
7043 {
7044 MemberDef *md;
7045 MemberNameIterator mni(*mn);
7046 // for each member definition
7047 for (mni.toFirst();(md=mni.current());++mni)
7048 {
7049 if (md->getNamespaceDef())
7050 {
7051 addNamespaceMemberNameToIndex(md);
7052 }
7053 else
7054 {
7055 addFileMemberNameToIndex(md);
7056 }
7057 }
7058 }
7059}
7060
7061//----------------------------------------------------------------------
7062// computes the relation between all members. For each member `m'
7063// the members that override the implementation of `m' are searched and
7064// the member that `m' overrides is searched.
7065
7066static void computeMemberRelations()
7067{
7068 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7069 MemberName *mn;
7070 for ( ; (mn=mnli.current()) ; ++mnli ) // for each member name
7071 {
7072 MemberNameIterator mdi(*mn);
7073 MemberDef *md;
7074 for ( ; (md=mdi.current()) ; ++mdi ) // for each member with a specific name
7075 {
7076 MemberDef *bmd = mn->first(); // for each other member with the same name
7077 while (bmd)
7078 {
7079 ClassDef *mcd = md->getClassDef();
7080 if (mcd && mcd->baseClasses())
7081 {
7082 ClassDef *bmcd = bmd->getClassDef();
7083 //printf("Check relation between `%s'::`%s' (%p) and `%s'::`%s' (%p)\n",
7084 // mcd->name().data(),md->name().data(),md,
7085 // bmcd->name().data(),bmd->name().data(),bmd
7086 // );
7087 if (md!=bmd && bmcd && mcd && bmcd!=mcd && mcd->isBaseClass(bmcd,TRUE))
7088 {
7089 //printf(" derived scope\n");
7090 LockingPtr<ArgumentList> bmdAl = bmd->argumentList();
7091 LockingPtr<ArgumentList> mdAl = md->argumentList();
7092 //printf(" Base argList=`%s'\n Super argList=`%s'\n",
7093 // argListToString(bmdAl.pointer()).data(),
7094 // argListToString(mdAl.pointer()).data()
7095 // );
7096 if (
7097 matchArguments2(bmd->getOuterScope(),bmd->getFileDef(),bmdAl.pointer(),
7098 md->getOuterScope(), md->getFileDef(), mdAl.pointer(),
7099 TRUE
7100 )
7101 )
7102 {
7103 //printf(" match found!\n");
7104 if (mcd && bmcd &&
7105 mcd->isLinkable() && bmcd->isLinkable()
7106 )
7107 {
7108 MemberDef *rmd;
7109 if ((rmd=md->reimplements())==0 ||
7110 minClassDistance(mcd,bmcd)<minClassDistance(mcd,rmd->getClassDef())
7111 )
7112 {
7113 //printf("setting (new) reimplements member\n");
7114 md->setReimplements(bmd);
7115 }
7116 //printf("%s: add reimplements member %s\n",mcd->name().data(),bmcd->name().data());
7117 //md->setImplements(bmd);
7118 //printf("%s: add reimplementedBy member %s\n",bmcd->name().data(),mcd->name().data());
7119 bmd->insertReimplementedBy(md);
7120 }
7121 }
7122 }
7123 }
7124 bmd = mn->next();
7125 }
7126 }
7127 }
7128}
7129
7130
7131//----------------------------------------------------------------------------
7132//static void computeClassImplUsageRelations()
7133//{
7134// ClassDef *cd;
7135// ClassSDict::Iterator cli(*Doxygen::classSDict);
7136// for (;(cd=cli.current());++cli)
7137// {
7138// cd->determineImplUsageRelation();
7139// }
7140//}
7141
7142//----------------------------------------------------------------------------
7143
7144static void createTemplateInstanceMembers()
7145{
7146 ClassSDict::Iterator cli(*Doxygen::classSDict);
7147 ClassDef *cd;
7148 // for each class
7149 for (cli.toFirst();(cd=cli.current());++cli)
7150 {
7151 // that is a template
7152 QDict<ClassDef> *templInstances = cd->getTemplateInstances();
7153 if (templInstances)
7154 {
7155 QDictIterator<ClassDef> qdi(*templInstances);
7156 ClassDef *tcd=0;
7157 // for each instance of the template
7158 for (qdi.toFirst();(tcd=qdi.current());++qdi)
7159 {
7160 tcd->addMembersToTemplateInstance(cd,qdi.currentKey());
7161 }
7162 }
7163 }
7164}
7165
7166//----------------------------------------------------------------------------
7167
7168// builds the list of all members for each class
7169
7170static void buildCompleteMemberLists()
7171{
7172 ClassDef *cd;
7173 // merge members of categories into the class they extend
7174 ClassSDict::Iterator cli(*Doxygen::classSDict);
7175 for (cli.toFirst();(cd=cli.current());++cli)
7176 {
7177 int i=cd->name().find('(');
7178 if (i!=-1) // it is an Objective-C category
7179 {
7180 QCString baseName=cd->name().left(i);
7181 ClassDef *baseClass=Doxygen::classSDict->find(baseName);
7182 if (baseClass)
7183 {
7184 //printf("*** merging members of category %s into %s\n",
7185 // cd->name().data(),baseClass->name().data());
7186 baseClass->mergeCategory(cd);
7187 }
7188 }
7189 }
7190 // merge the member list of base classes into the inherited classes.
7191 for (cli.toFirst();(cd=cli.current());++cli)
7192 {
7193 if (// !cd->isReference() && // not an external class
7194 cd->subClasses()==0 && // is a root of the hierarchy
7195 cd->baseClasses()) // and has at least one base class
7196 {
7197 //printf("*** merging members for %s\n",cd->name().data());
7198 cd->mergeMembers();
7199 }
7200 }
7201 // now sort the member list of all classes.
7202 for (cli.toFirst();(cd=cli.current());++cli)
7203 {
7204 if (cd->memberNameInfoSDict()) cd->memberNameInfoSDict()->sort();
7205 }
7206}
7207
7208//----------------------------------------------------------------------------
7209
7210static void generateFileSources()
7211{
7212 if (documentedHtmlFiles==0) return;
7213 if (Doxygen::inputNameList->count()>0)
7214 {
7215 FileNameListIterator fnli(*Doxygen::inputNameList);
7216 FileName *fn;
7217 for (;(fn=fnli.current());++fnli)
7218 {
7219 FileNameIterator fni(*fn);
7220 FileDef *fd;
7221 for (;(fd=fni.current());++fni)
7222 {
7223 if (fd->generateSourceFile()) // sources need to be shown in the output
7224 {
7225 msg("Generating code for file %s...\n",fd->docName().data());
7226 fd->writeSource(*g_outputList);
7227 }
7228 else if (!fd->isReference() && Doxygen::parseSourcesNeeded)
7229 // we needed to parse the sources even if we do not show them
7230 {
7231 msg("Parsing code for file %s...\n",fd->docName().data());
7232 fd->parseSource();
7233 }
7234 }
7235 }
7236 }
7237}
7238
7239//----------------------------------------------------------------------------
7240
7241static void generateFileDocs()
7242{
7243 if (documentedHtmlFiles==0) return;
7244
7245 if (Doxygen::inputNameList->count()>0)
7246 {
7247 FileNameListIterator fnli(*Doxygen::inputNameList);
7248 FileName *fn;
7249 for (fnli.toFirst();(fn=fnli.current());++fnli)
7250 {
7251 FileNameIterator fni(*fn);
7252 FileDef *fd;
7253 for (fni.toFirst();(fd=fni.current());++fni)
7254 {
7255 bool doc = fd->isLinkableInProject();
7256 if (doc)
7257 {
7258 msg("Generating docs for file %s...\n",fd->docName().data());
7259 fd->writeDocumentation(*g_outputList);
7260 }
7261 }
7262 }
7263 }
7264}
7265
7266//----------------------------------------------------------------------------
7267
7268static void addSourceReferences()
7269{
7270 // add source references for class definitions
7271 ClassSDict::Iterator cli(*Doxygen::classSDict);
7272 ClassDef *cd=0;
7273 for (cli.toFirst();(cd=cli.current());++cli)
7274 {
7275 FileDef *fd=cd->getBodyDef();
7276 if (fd && cd->isLinkableInProject() && cd->getStartBodyLine()!=-1)
7277 {
7278 fd->addSourceRef(cd->getStartBodyLine(),cd,0);
7279 }
7280 }
7281 // add source references for namespace definitions
7282 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7283 NamespaceDef *nd=0;
7284 for (nli.toFirst();(nd=nli.current());++nli)
7285 {
7286 FileDef *fd=nd->getBodyDef();
7287 if (fd && nd->isLinkableInProject() && nd->getStartBodyLine()!=-1)
7288 {
7289 fd->addSourceRef(nd->getStartBodyLine(),nd,0);
7290 }
7291 }
7292
7293 // add source references for member names
7294 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7295 MemberName *mn=0;
7296 for (mnli.toFirst();(mn=mnli.current());++mnli)
7297 {
7298 MemberNameIterator mni(*mn);
7299 MemberDef *md=0;
7300 for (mni.toFirst();(md=mni.current());++mni)
7301 {
7302 //printf("class member %s: def=%s body=%d link?=%d\n",
7303 // md->name().data(),
7304 // md->getBodyDef()?md->getBodyDef()->name().data():"<none>",
7305 // md->getStartBodyLine(),md->isLinkableInProject());
7306 FileDef *fd=md->getBodyDef();
7307 if (fd &&
7308 md->getStartBodyLine()!=-1 &&
7309 md->isLinkableInProject() &&
7310 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7311 )
7312 {
7313 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7314 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
7315 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7316 }
7317 }
7318 }
7319 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7320 for (fnli.toFirst();(mn=fnli.current());++fnli)
7321 {
7322 MemberNameIterator mni(*mn);
7323 MemberDef *md=0;
7324 for (mni.toFirst();(md=mni.current());++mni)
7325 {
7326 FileDef *fd=md->getBodyDef();
7327 //printf("member %s body=[%d,%d] fd=%p link=%d parseSources=%d\n",
7328 // md->name().data(),
7329 // md->getStartBodyLine(),md->getEndBodyLine(),fd,
7330 // md->isLinkableInProject(),
7331 // Doxygen::parseSourcesNeeded);
7332 if (fd &&
7333 md->getStartBodyLine()!=-1 &&
7334 md->isLinkableInProject() &&
7335 (fd->generateSourceFile() || Doxygen::parseSourcesNeeded)
7336 )
7337 {
7338 //printf("Found member `%s' in file `%s' at line `%d' def=%s\n",
7339 // md->name().data(),fd->name().data(),md->getStartBodyLine(),md->getOuterScope()->name().data());
7340 fd->addSourceRef(md->getStartBodyLine(),md->getOuterScope(),md);
7341 }
7342 }
7343 }
7344}
7345
7346//----------------------------------------------------------------------------
7347
7348static void sortMemberLists()
7349{
7350 // sort class member lists
7351 ClassSDict::Iterator cli(*Doxygen::classSDict);
7352 ClassDef *cd=0;
7353 for (cli.toFirst();(cd=cli.current());++cli)
7354 {
7355 cd->sortMemberLists();
7356 }
7357
7358 // sort namespace member lists
7359 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7360 NamespaceDef *nd=0;
7361 for (nli.toFirst();(nd=nli.current());++nli)
7362 {
7363 nd->sortMemberLists();
7364 }
7365
7366 // sort file member lists
7367 FileNameListIterator fnli(*Doxygen::inputNameList);
7368 FileName *fn;
7369 for (;(fn=fnli.current());++fnli)
7370 {
7371 FileNameIterator fni(*fn);
7372 FileDef *fd;
7373 for (;(fd=fni.current());++fni)
7374 {
7375 fd->sortMemberLists();
7376 }
7377 }
7378
7379 // sort group member lists
7380 GroupSDict::Iterator gli(*Doxygen::groupSDict);
7381 GroupDef *gd;
7382 for (gli.toFirst();(gd=gli.current());++gli)
7383 {
7384 gd->sortMemberLists();
7385 }
7386}
7387
7388//----------------------------------------------------------------------------
7389// generate the documentation of all classes
7390
7391static void generateClassList(ClassSDict &classSDict)
7392{
7393 ClassSDict::Iterator cli(classSDict);
7394 for ( ; cli.current() ; ++cli )
7395 {
7396 ClassDef *cd=cli.current();
7397
7398 //printf("cd=%s getOuterScope=%p global=%p\n",cd->name().data(),cd->getOuterScope(),Doxygen::globalScope);
7399 if ((cd->getOuterScope()==0 || // <-- should not happen, but can if we read an old tag file
7400 cd->getOuterScope()==Doxygen::globalScope // only look at global classes
7401 ) && !cd->isHidden() && !cd->isEmbeddedInGroupDocs()
7402 )
7403 {
7404 // skip external references, anonymous compounds and
7405 // template instances
7406 if ( cd->isLinkableInProject() && cd->templateMaster()==0)
7407 {
7408 msg("Generating docs for compound %s...\n",cd->name().data());
7409
7410 cd->writeDocumentation(*g_outputList);
7411 cd->writeMemberList(*g_outputList);
7412 }
7413 // even for undocumented classes, the inner classes can be documented.
7414 cd->writeDocumentationForInnerClasses(*g_outputList);
7415 }
7416 }
7417}
7418
7419static void generateClassDocs()
7420{
7421 // write the installdox script if necessary
7422 if (Config_getBool("GENERATE_HTML") &&
7423 (Config_getList("TAGFILES").count()>0 ||
7424 Config_getBool("SEARCHENGINE")
7425 )
7426 )
7427 {
7428 writeInstallScript();
7429 }
7430
7431 msg("Generating annotated compound index...\n");
7432 writeAnnotatedIndex(*g_outputList);
7433
7434 //if (Config_getBool("ALPHABETICAL_INDEX"))
7435 //{
7436 msg("Generating alphabetical compound index...\n");
7437 writeAlphabeticalIndex(*g_outputList);
7438 //}
7439
7440 msg("Generating hierarchical class index...\n");
7441 writeHierarchicalIndex(*g_outputList);
7442
7443 msg("Generating member index...\n");
7444 writeClassMemberIndex(*g_outputList);
7445
7446 if (Doxygen::exampleSDict->count()>0)
7447 {
7448 msg("Generating example index...\n");
7449 }
7450
7451 generateClassList(*Doxygen::classSDict);
7452 generateClassList(*Doxygen::hiddenClasses);
7453}
7454
7455//----------------------------------------------------------------------------
7456
7457static void inheritDocumentation()
7458{
7459 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7460 MemberName *mn;
7461 //int count=0;
7462 for (;(mn=mnli.current());++mnli)
7463 {
7464 MemberNameIterator mni(*mn);
7465 MemberDef *md;
7466 for (;(md=mni.current());++mni)
7467 {
7468 //printf("%04d Member `%s'\n",count++,md->name().data());
7469 if (md->documentation().isEmpty() && md->briefDescription().isEmpty())
7470 { // no documentation yet
7471 MemberDef *bmd = md->reimplements();
7472 while (bmd && bmd->documentation().isEmpty() &&
7473 bmd->briefDescription().isEmpty()
7474 )
7475 { // search up the inheritance tree for a documentation member
7476 //printf("bmd=%s class=%s\n",bmd->name().data(),bmd->getClassDef()->name().data());
7477 bmd = bmd->reimplements();
7478 }
7479 if (bmd) // copy the documentation from the reimplemented member
7480 {
7481 md->setInheritsDocsFrom(bmd);
7482 md->setDocumentation(bmd->documentation(),bmd->docFile(),bmd->docLine());
7483 md->setDocsForDefinition(bmd->isDocsForDefinition());
7484 md->setBriefDescription(bmd->briefDescription(),bmd->briefFile(),bmd->briefLine());
7485 md->copyArgumentNames(bmd);
7486 md->setInbodyDocumentation(bmd->inbodyDocumentation(),bmd->inbodyFile(),bmd->inbodyLine());
7487 }
7488 }
7489 }
7490 }
7491}
7492
7493//----------------------------------------------------------------------------
7494
7495static void combineUsingRelations()
7496{
7497 // for each file
7498 FileNameListIterator fnli(*Doxygen::inputNameList);
7499 FileName *fn;
7500 for (fnli.toFirst();(fn=fnli.current());++fnli)
7501 {
7502 FileNameIterator fni(*fn);
7503 FileDef *fd;
7504 for (fni.toFirst();(fd=fni.current());++fni)
7505 {
7506 fd->visited=FALSE;
7507 }
7508 }
7509 for (fnli.toFirst();(fn=fnli.current());++fnli)
7510 {
7511 FileNameIterator fni(*fn);
7512 FileDef *fd;
7513 for (fni.toFirst();(fd=fni.current());++fni)
7514 {
7515 fd->combineUsingRelations();
7516 }
7517 }
7518
7519 // for each namespace
7520 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7521 NamespaceDef *nd;
7522 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
7523 {
7524 nd->visited=FALSE;
7525 }
7526 for (nli.toFirst() ; (nd=nli.current()) ; ++nli )
7527 {
7528 nd->combineUsingRelations();
7529 }
7530}
7531
7532//----------------------------------------------------------------------------
7533
7534static void addMembersToMemberGroup()
7535{
7536 // for each class
7537 ClassSDict::Iterator cli(*Doxygen::classSDict);
7538 ClassDef *cd;
7539 for ( ; (cd=cli.current()) ; ++cli )
7540 {
7541 cd->addMembersToMemberGroup();
7542 }
7543 // for each file
7544 FileName *fn=Doxygen::inputNameList->first();
7545 while (fn)
7546 {
7547 FileDef *fd=fn->first();
7548 while (fd)
7549 {
7550 fd->addMembersToMemberGroup();
7551 fd=fn->next();
7552 }
7553 fn=Doxygen::inputNameList->next();
7554 }
7555 // for each namespace
7556 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7557 NamespaceDef *nd;
7558 for ( ; (nd=nli.current()) ; ++nli )
7559 {
7560 nd->addMembersToMemberGroup();
7561 }
7562 // for each group
7563 GroupSDict::Iterator gli(*Doxygen::groupSDict);
7564 GroupDef *gd;
7565 for (gli.toFirst();(gd=gli.current());++gli)
7566 {
7567 gd->addMembersToMemberGroup();
7568 }
7569}
7570
7571//----------------------------------------------------------------------------
7572
7573static void distributeMemberGroupDocumentation()
7574{
7575 // for each class
7576 ClassSDict::Iterator cli(*Doxygen::classSDict);
7577 ClassDef *cd;
7578 for ( ; (cd=cli.current()) ; ++cli )
7579 {
7580 cd->distributeMemberGroupDocumentation();
7581 }
7582 // for each file
7583 FileName *fn=Doxygen::inputNameList->first();
7584 while (fn)
7585 {
7586 FileDef *fd=fn->first();
7587 while (fd)
7588 {
7589 fd->distributeMemberGroupDocumentation();
7590 fd=fn->next();
7591 }
7592 fn=Doxygen::inputNameList->next();
7593 }
7594 // for each namespace
7595 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7596 NamespaceDef *nd;
7597 for ( ; (nd=nli.current()) ; ++nli )
7598 {
7599 nd->distributeMemberGroupDocumentation();
7600 }
7601 // for each group
7602 GroupSDict::Iterator gli(*Doxygen::groupSDict);
7603 GroupDef *gd;
7604 for (gli.toFirst();(gd=gli.current());++gli)
7605 {
7606 gd->distributeMemberGroupDocumentation();
7607 }
7608}
7609
7610//----------------------------------------------------------------------------
7611
7612static void findSectionsInDocumentation()
7613{
7614 // for each class
7615 ClassSDict::Iterator cli(*Doxygen::classSDict);
7616 ClassDef *cd;
7617 for ( ; (cd=cli.current()) ; ++cli )
7618 {
7619 cd->findSectionsInDocumentation();
7620 }
7621 // for each file
7622 FileName *fn=Doxygen::inputNameList->first();
7623 while (fn)
7624 {
7625 FileDef *fd=fn->first();
7626 while (fd)
7627 {
7628 fd->findSectionsInDocumentation();
7629 fd=fn->next();
7630 }
7631 fn=Doxygen::inputNameList->next();
7632 }
7633 // for each namespace
7634 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
7635 NamespaceDef *nd;
7636 for ( ; (nd=nli.current()) ; ++nli )
7637 {
7638 nd->findSectionsInDocumentation();
7639 }
7640 // for each group
7641 GroupSDict::Iterator gli(*Doxygen::groupSDict);
7642 GroupDef *gd;
7643 for (gli.toFirst();(gd=gli.current());++gli)
7644 {
7645 gd->findSectionsInDocumentation();
7646 }
7647 // for each page
7648 PageSDict::Iterator pdi(*Doxygen::pageSDict);
7649 PageDef *pd=0;
7650 for (pdi.toFirst();(pd=pdi.current());++pdi)
7651 {
7652 pd->findSectionsInDocumentation();
7653 }
7654 if (Doxygen::mainPage) Doxygen::mainPage->findSectionsInDocumentation();
7655}
7656
7657static void flushCachedTemplateRelations()
7658{
7659 // remove all references to classes from the cache
7660 // as there can be new template instances in the inheritance path
7661 // to this class. Optimization: only remove those classes that
7662 // have inheritance instances as direct or indirect sub classes.
7663 QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);
7664 LookupInfo *li=0;
7665 for (ci.toFirst();(li=ci.current());++ci)
7666 {
7667 if (li->classDef)
7668 {
7669 Doxygen::lookupCache.remove(ci.currentKey());
7670 }
7671 }
7672 // remove all cached typedef resolutions whose target is a
7673 // template class as this may now be a template instance
7674 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7675 MemberName *fn;
7676 for (;(fn=fnli.current());++fnli) // for each global function name
7677 {
7678 MemberNameIterator fni(*fn);
7679 MemberDef *fmd;
7680 for (;(fmd=fni.current());++fni) // for each function with that name
7681 {
7682 if (fmd->isTypedefValCached())
7683 {
7684 ClassDef *cd = fmd->getCachedTypedefVal();
7685 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
7686 }
7687 }
7688 }
7689 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7690 for (;(fn=mnli.current());++mnli) // for each class method name
7691 {
7692 MemberNameIterator mni(*fn);
7693 MemberDef *fmd;
7694 for (;(fmd=mni.current());++mni) // for each function with that name
7695 {
7696 if (fmd->isTypedefValCached())
7697 {
7698 ClassDef *cd = fmd->getCachedTypedefVal();
7699 if (cd->isTemplate()) fmd->invalidateTypedefValCache();
7700 }
7701 }
7702 }
7703}
7704
7705//----------------------------------------------------------------------------
7706
7707static void flushUnresolvedRelations()
7708{
7709 // Remove all unresolved references to classes from the cache.
7710 // This is needed before resolving the inheritance relations, since
7711 // it would otherwise not find the inheritance relation
7712 // for C in the example below, as B::I was already found to be unresolvable
7713 // (which is correct if you igore the inheritance relation between A and B).
7714 //
7715 // class A { class I {} };
7716 // class B : public A {};
7717 // class C : public B::I {};
7718 //
7719 QCacheIterator<LookupInfo> ci(Doxygen::lookupCache);
7720 LookupInfo *li=0;
7721 for (ci.toFirst();(li=ci.current());++ci)
7722 {
7723 if (li->classDef==0 && li->typeDef==0)
7724 {
7725 Doxygen::lookupCache.remove(ci.currentKey());
7726 }
7727 }
7728
7729 MemberNameSDict::Iterator fnli(*Doxygen::functionNameSDict);
7730 MemberName *fn;
7731 for (;(fn=fnli.current());++fnli) // for each global function name
7732 {
7733 MemberNameIterator fni(*fn);
7734 MemberDef *fmd;
7735 for (;(fmd=fni.current());++fni) // for each function with that name
7736 {
7737 fmd->invalidateCachedArgumentTypes();
7738 }
7739 }
7740 MemberNameSDict::Iterator mnli(*Doxygen::memberNameSDict);
7741 for (;(fn=mnli.current());++mnli) // for each class method name
7742 {
7743 MemberNameIterator mni(*fn);
7744 MemberDef *fmd;
7745 for (;(fmd=mni.current());++mni) // for each function with that name
7746 {
7747 fmd->invalidateCachedArgumentTypes();
7748 }
7749 }
7750
7751}
7752
7753//----------------------------------------------------------------------------
7754
7755static void findDefineDocumentation(EntryNav *rootNav)
7756{
7757 if ((rootNav->section()==Entry::DEFINEDOC_SEC ||
7758 rootNav->section()==Entry::DEFINE_SEC) && !rootNav->name().isEmpty()
7759 )
7760 {
7761 rootNav->loadEntry(g_storage);
7762 Entry *root = rootNav->entry();
7763
7764 //printf("found define `%s' `%s' brief=`%s' doc=`%s'\n",
7765 // root->name.data(),root->args.data(),root->brief.data(),root->doc.data());
7766
7767 if (rootNav->tagInfo() && !root->name.isEmpty()) // define read from a tag file
7768 {
7769 MemberDef *md=new MemberDef("<tagfile>",1,
7770 "#define",root->name,root->args,0,
7771 Public,Normal,FALSE,Member,MemberDef::Define,0,0);
7772 md->setTagInfo(rootNav->tagInfo());
7773 //printf("Searching for `%s' fd=%p\n",filePathName.data(),fd);
7774 md->setFileDef(rootNav->parent()->fileDef());
7775 //printf("Adding member=%s\n",md->name().data());
7776 MemberName *mn;
7777 if ((mn=Doxygen::functionNameSDict->find(root->name)))
7778 {
7779 mn->append(md);
7780 }
7781 else
7782 {
7783 mn = new MemberName(root->name);
7784 mn->append(md);
7785 Doxygen::functionNameSDict->append(root->name,mn);
7786 }
7787 }
7788 MemberName *mn=Doxygen::functionNameSDict->find(root->name);
7789 if (mn)
7790 {
7791 int count=0;
7792 MemberDef *md=mn->first();
7793 while (md)
7794 {
7795 if (md->memberType()==MemberDef::Define) count++;
7796 md=mn->next();
7797 }
7798 if (count==1)
7799 {
7800 md=mn->first();
7801 while (md)
7802 {
7803 if (md->memberType()==MemberDef::Define)
7804 {
7805 md->setDocumentation(root->doc,root->docFile,root->docLine);
7806 md->setDocsForDefinition(!root->proto);
7807 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7808 if (md->inbodyDocumentation().isEmpty())
7809 {
7810 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7811 }
7812 md->setBodySegment(root->bodyLine,root->endBodyLine);
7813 md->setBodyDef(rootNav->fileDef());
7814 md->addSectionsToDefinition(root->anchors);
7815 md->setMaxInitLines(root->initLines);
7816 md->setRefItems(root->sli);
7817 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
7818 addMemberToGroups(root,md);
7819 }
7820 md=mn->next();
7821 }
7822 }
7823 else if (count>1 &&
7824 (!root->doc.isEmpty() ||
7825 !root->brief.isEmpty() ||
7826 root->bodyLine!=-1
7827 )
7828 )
7829 // multiple defines don't know where to add docs
7830 // but maybe they are in different files together with their documentation
7831 {
7832 md=mn->first();
7833 while (md)
7834 {
7835 if (md->memberType()==MemberDef::Define)
7836 {
7837 FileDef *fd=md->getFileDef();
7838 if (fd && fd->absFilePath()==root->fileName)
7839 // doc and define in the same file assume they belong together.
7840 {
7841#if 0
7842 if (md->documentation().isEmpty())
7843#endif
7844 {
7845 md->setDocumentation(root->doc,root->docFile,root->docLine);
7846 md->setDocsForDefinition(!root->proto);
7847 }
7848#if 0
7849 if (md->briefDescription().isEmpty())
7850#endif
7851 {
7852 md->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7853 }
7854 if (md->inbodyDocumentation().isEmpty())
7855 {
7856 md->setInbodyDocumentation(root->inbodyDocs,root->inbodyFile,root->inbodyLine);
7857 }
7858 md->setBodySegment(root->bodyLine,root->endBodyLine);
7859 md->setBodyDef(rootNav->fileDef());
7860 md->addSectionsToDefinition(root->anchors);
7861 md->setRefItems(root->sli);
7862 if (root->mGrpId!=-1) md->setMemberGroupId(root->mGrpId);
7863 addMemberToGroups(root,md);
7864 }
7865 }
7866 md=mn->next();
7867 }
7868 //warn("warning: define %s found in the following files:\n",root->name.data());
7869 //warn("Cannot determine where to add the documentation found "
7870 // "at line %d of file %s. \n",
7871 // root->startLine,root->fileName.data());
7872 }
7873 }
7874 else if (!root->doc.isEmpty() || !root->brief.isEmpty()) // define not found
7875 {
7876 static bool preEnabled = Config_getBool("ENABLE_PREPROCESSING");
7877 if (preEnabled)
7878 {
7879 warn(root->fileName,root->startLine,
7880 "warning: documentation for unknown define %s found.\n",
7881 root->name.data()
7882 );
7883 }
7884 else
7885 {
7886 warn(root->fileName,root->startLine,
7887 "warning: found documented #define but ignoring it because "
7888 "ENABLE_PREPROCESSING is NO.\n",
7889 root->name.data()
7890 );
7891 }
7892 }
7893
7894 rootNav->releaseEntry();
7895 }
7896 RECURSE_ENTRYTREE(findDefineDocumentation,rootNav);
7897}
7898
7899//----------------------------------------------------------------------------
7900
7901static void findDirDocumentation(EntryNav *rootNav)
7902{
7903 if (rootNav->section() == Entry::DIRDOC_SEC)
7904 {
7905 rootNav->loadEntry(g_storage);
7906 Entry *root = rootNav->entry();
7907
7908 QCString normalizedName = root->name;
7909 normalizedName = substitute(normalizedName,"\\","/");
7910 //printf("root->docFile=%s normalizedName=%s\n",
7911 // root->docFile.data(),normalizedName.data());
7912 if (root->docFile==normalizedName) // current dir?
7913 {
7914 int lastSlashPos=normalizedName.findRev('/');
7915 if (lastSlashPos!=-1) // strip file name
7916 {
7917 normalizedName=normalizedName.left(lastSlashPos);
7918 }
7919 }
7920 if (normalizedName.at(normalizedName.length()-1)!='/')
7921 {
7922 normalizedName+='/';
7923 }
7924 DirDef *dir,*matchingDir=0;
7925 SDict<DirDef>::Iterator sdi(*Doxygen::directories);
7926 for (sdi.toFirst();(dir=sdi.current());++sdi)
7927 {
7928 //printf("Dir: %s<->%s\n",dir->name().data(),normalizedName.data());
7929 if (dir->name().right(normalizedName.length())==normalizedName)
7930 {
7931 if (matchingDir)
7932 {
7933 warn(root->fileName,root->startLine,
7934 "warning: \\dir command matches multiple directories.\n"
7935 " Applying the command for directory %s\n"
7936 " Ignoring the command for directory %s\n",
7937 matchingDir->name().data(),dir->name().data()
7938 );
7939 }
7940 else
7941 {
7942 matchingDir=dir;
7943 }
7944 }
7945 }
7946 if (matchingDir)
7947 {
7948 //printf("Match for with dir %s\n",matchingDir->name().data());
7949 matchingDir->setBriefDescription(root->brief,root->briefFile,root->briefLine);
7950 matchingDir->setDocumentation(root->doc,root->docFile,root->docLine);
7951 matchingDir->setRefItems(root->sli);
7952 addDirToGroups(root,matchingDir);
7953 }
7954 else
7955 {
7956 warn(root->fileName,root->startLine,"warning: No matching "
7957 "directory found for command \\dir %s\n",normalizedName.data());
7958 }
7959 rootNav->releaseEntry();
7960 }
7961 RECURSE_ENTRYTREE(findDirDocumentation,rootNav);
7962}
7963
7964
7965//----------------------------------------------------------------------------
7966// create a (sorted) list of separate documentation pages
7967
7968static void buildPageList(EntryNav *rootNav)
7969{
7970 if (rootNav->section() == Entry::PAGEDOC_SEC)
7971 {
7972 rootNav->loadEntry(g_storage);
7973 Entry *root = rootNav->entry();
7974
7975 if (!root->name.isEmpty())
7976 {
7977 addRelatedPage(rootNav);
7978 }
7979
7980 rootNav->releaseEntry();
7981 }
7982 else if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
7983 {
7984 rootNav->loadEntry(g_storage);
7985 Entry *root = rootNav->entry();
7986
7987 QCString title=root->args.stripWhiteSpace();
7988 if (title.isEmpty()) title=theTranslator->trMainPage();
7989 QCString name = Config_getBool("GENERATE_TREEVIEW")?"main":"index";
7990 addRefItem(root->sli,
7991 name,
7992 "page",
7993 name,
7994 title,
7995 0
7996 );
7997
7998 rootNav->releaseEntry();
7999 }
8000 RECURSE_ENTRYTREE(buildPageList,rootNav);
8001}
8002
8003static void findMainPage(EntryNav *rootNav)
8004{
8005 if (rootNav->section() == Entry::MAINPAGEDOC_SEC)
8006 {
8007 rootNav->loadEntry(g_storage);
8008 Entry *root = rootNav->entry();
8009
8010 if (Doxygen::mainPage==0)
8011 {
8012 //printf("Found main page! \n======\n%s\n=======\n",root->doc.data());
8013 QCString title=root->args.stripWhiteSpace();
8014 QCString indexName=Config_getBool("GENERATE_TREEVIEW")?"main":"index";
8015 Doxygen::mainPage = new PageDef(root->fileName,root->startLine,
8016 indexName, root->brief+root->doc+root->inbodyDocs,title);
8017 //setFileNameForSections(root->anchors,"index",Doxygen::mainPage);
8018 Doxygen::mainPage->setFileName(indexName);
8019 addPageToContext(Doxygen::mainPage,rootNav);
8020
8021 // a page name is a label as well!
8022 SectionInfo *si=new SectionInfo(
8023 indexName,
8024 Doxygen::mainPage->name(),
8025 Doxygen::mainPage->title(),
8026 SectionInfo::Page);
8027 Doxygen::sectionDict.insert(indexName,si);
8028 Doxygen::mainPage->addSectionsToDefinition(root->anchors);
8029 }
8030 else
8031 {
8032 warn(root->fileName,root->startLine,
8033 "warning: found more than one \\mainpage comment block! Skipping this "
8034 "block."
8035 );
8036 }
8037
8038 rootNav->releaseEntry();
8039 }
8040 RECURSE_ENTRYTREE(findMainPage,rootNav);
8041}
8042
8043static void computePageRelations(EntryNav *rootNav)
8044{
8045 if ((rootNav->section()==Entry::PAGEDOC_SEC ||
8046 rootNav->section()==Entry::MAINPAGEDOC_SEC
8047 )
8048 && !rootNav->name().isEmpty()
8049 )
8050 {
8051 rootNav->loadEntry(g_storage);
8052 Entry *root = rootNav->entry();
8053
8054 PageDef *pd = root->section==Entry::PAGEDOC_SEC ?
8055 Doxygen::pageSDict->find(root->name) :
8056 Doxygen::mainPage;
8057 if (pd)
8058 {
8059 QListIterator<BaseInfo> bii(*root->extends);
8060 BaseInfo *bi;
8061 for (bii.toFirst();(bi=bii.current());++bii)
8062 {
8063 PageDef *subPd = Doxygen::pageSDict->find(bi->name);
8064 if (subPd)
8065 {
8066 pd->addInnerCompound(subPd);
8067 //printf("*** Added subpage relation: %s->%s\n",
8068 // pd->name().data(),subPd->name().data());
8069 }
8070 }
8071 }
8072
8073 rootNav->releaseEntry();
8074 }
8075 RECURSE_ENTRYTREE(computePageRelations,rootNav);
8076}
8077
8078static void checkPageRelations()
8079{
8080 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8081 PageDef *pd=0;
8082 for (pdi.toFirst();(pd=pdi.current());++pdi)
8083 {
8084 Definition *ppd = pd->getOuterScope();
8085 while (ppd)
8086 {
8087 if (ppd==pd)
8088 {
8089 err("warning: page defined at line %d of file %s with label %s is a subpage "
8090 "of itself! Please remove this cyclic dependency.\n",
8091 pd->docLine(),pd->docFile().data(),pd->name().data());
8092 exit(1);
8093 }
8094 ppd=ppd->getOuterScope();
8095 }
8096 }
8097}
8098
8099//----------------------------------------------------------------------------
8100
8101static void resolveUserReferences()
8102{
8103 QDictIterator<SectionInfo> sdi(Doxygen::sectionDict);
8104 SectionInfo *si;
8105 for (;(si=sdi.current());++sdi)
8106 {
8107 //printf("si->label=`%s' si->definition=%s si->fileName=`%s'\n",
8108 // si->label.data(),si->definition?si->definition->name().data():"<none>",
8109 // si->fileName.data());
8110 PageDef *pd=0;
8111
8112 // hack: the items of a todo/test/bug/deprecated list are all fragments from
8113 // different files, so the resulting section's all have the wrong file
8114 // name (not from the todo/test/bug/deprecated list, but from the file in
8115 // which they are defined). We correct this here by looking at the
8116 // generated section labels!
8117 QDictIterator<RefList> rli(*Doxygen::xrefLists);
8118 RefList *rl;
8119 for (rli.toFirst();(rl=rli.current());++rli)
8120 {
8121 QCString label="_"+rl->listName(); // "_todo", "_test", ...
8122 if (si->label.left(label.length())==label)
8123 {
8124 si->fileName=rl->listName();
8125 si->generated=TRUE;
8126 break;
8127 }
8128 }
8129
8130 //printf("start: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8131 if (!si->generated)
8132 {
8133 // if this section is in a page and the page is in a group, then we
8134 // have to adjust the link file name to point to the group.
8135 if (!si->fileName.isEmpty() &&
8136 (pd=Doxygen::pageSDict->find(si->fileName)) &&
8137 pd->getGroupDef())
8138 {
8139 si->fileName=pd->getGroupDef()->getOutputFileBase().copy();
8140 }
8141
8142 if (si->definition)
8143 {
8144 // TODO: there should be one function in Definition that returns
8145 // the file to link to, so we can avoid the following tests.
8146 GroupDef *gd=0;
8147 if (si->definition->definitionType()==Definition::TypeMember)
8148 {
8149 gd = ((MemberDef *)si->definition)->getGroupDef();
8150 }
8151
8152 if (gd)
8153 {
8154 si->fileName=gd->getOutputFileBase().copy();
8155 }
8156 else
8157 {
8158 //si->fileName=si->definition->getOutputFileBase().copy();
8159 //printf("Setting si->fileName to %s\n",si->fileName.data());
8160 }
8161 }
8162 }
8163 //printf("end: si->label=%s si->fileName=%s\n",si->label.data(),si->fileName.data());
8164 }
8165}
8166
8167
8168//----------------------------------------------------------------------------
8169// generate all separate documentation pages
8170
8171
8172static void generatePageDocs()
8173{
8174 //printf("documentedPages=%d real=%d\n",documentedPages,Doxygen::pageSDict->count());
8175 if (documentedPages==0) return;
8176 PageSDict::Iterator pdi(*Doxygen::pageSDict);
8177 PageDef *pd=0;
8178 for (pdi.toFirst();(pd=pdi.current());++pdi)
8179 {
8180 if (!pd->getGroupDef() && !pd->isReference())
8181 {
8182 msg("Generating docs for page %s...\n",pd->name().data());
8183 Doxygen::insideMainPage=TRUE;
8184 pd->writeDocumentation(*g_outputList);
8185 Doxygen::insideMainPage=FALSE;
8186 }
8187 }
8188}
8189
8190//----------------------------------------------------------------------------
8191// create a (sorted) list & dictionary of example pages
8192
8193static void buildExampleList(EntryNav *rootNav)
8194{
8195 if (rootNav->section()==Entry::EXAMPLE_SEC && !rootNav->name().isEmpty())
8196 {
8197 rootNav->loadEntry(g_storage);
8198 Entry *root = rootNav->entry();
8199
8200 if (Doxygen::exampleSDict->find(root->name))
8201 {
8202 warn(root->fileName,root->startLine,
8203 "warning: Example %s was already documented. Ignoring "
8204 "documentation found here.",
8205 root->name.data()
8206 );
8207 }
8208 else
8209 {
8210 PageDef *pd=new PageDef(root->fileName,root->startLine,
8211 root->name,root->brief+root->doc+root->inbodyDocs,root->args);
8212 pd->setFileName(convertNameToFile(pd->name()+"-example",FALSE,TRUE));
8213 pd->addSectionsToDefinition(root->anchors);
8214 //pi->addSections(root->anchors);
8215
8216 Doxygen::exampleSDict->inSort(root->name,pd);
8217 //we don't add example to groups
8218 //addExampleToGroups(root,pd);
8219 }
8220
8221 rootNav->releaseEntry();
8222 }
8223 RECURSE_ENTRYTREE(buildExampleList,rootNav);
8224}
8225
8226//----------------------------------------------------------------------------
8227// prints the Entry tree (for debugging)
8228
8229void printNavTree(EntryNav *rootNav,int indent)
8230{
8231 QCString indentStr;
8232 indentStr.fill(' ',indent);
8233 msg("%s%s (sec=0x%x)\n",
8234 indentStr.isEmpty()?"":indentStr.data(),
8235 rootNav->name().isEmpty()?"<empty>":rootNav->name().data(),
8236 rootNav->section());
8237 if (rootNav->children())
8238 {
8239 EntryNavListIterator eli(*rootNav->children());
8240 for (;eli.current();++eli) printNavTree(eli.current(),indent+2);
8241 }
8242}
8243
8244
8245//----------------------------------------------------------------------------
8246// generate the example documentation
8247
8248static void generateExampleDocs()
8249{
8250 g_outputList->disable(OutputGenerator::Man);
8251 PageSDict::Iterator pdi(*Doxygen::exampleSDict);
8252 PageDef *pd=0;
8253 for (pdi.toFirst();(pd=pdi.current());++pdi)
8254 {
8255 msg("Generating docs for example %s...\n",pd->name().data());
8256 resetCCodeParserState();
8257 QCString n=pd->getOutputFileBase();
8258 startFile(*g_outputList,n,n,pd->name());
8259 startTitle(*g_outputList,n);
8260 g_outputList->docify(pd->name());
8261 endTitle(*g_outputList,n,0);
8262 g_outputList->startContents();
8263 g_outputList->parseDoc(pd->docFile(), // file
8264 pd->docLine(), // startLine
8265 pd, // context
8266 0, // memberDef
8267 pd->documentation()+"\n\n\\include "+pd->name(), // docs
8268 TRUE, // index words
8269 TRUE, // is example
8270 pd->name()
8271 );
8272 g_outputList->endContents();
8273 endFile(*g_outputList);
8274 }
8275 g_outputList->enable(OutputGenerator::Man);
8276}
8277
8278//----------------------------------------------------------------------------
8279// generate module pages
8280
8281static void generateGroupDocs()
8282{
8283 GroupSDict::Iterator gli(*Doxygen::groupSDict);
8284 GroupDef *gd;
8285 for (gli.toFirst();(gd=gli.current());++gli)
8286 {
8287 if (!gd->isReference())
8288 {
8289 gd->writeDocumentation(*g_outputList);
8290 }
8291 }
8292}
8293
8294//----------------------------------------------------------------------------
8295
8296//static void generatePackageDocs()
8297//{
8298// writePackageIndex(*g_outputList);
8299//
8300// if (Doxygen::packageDict.count()>0)
8301// {
8302// PackageSDict::Iterator pdi(Doxygen::packageDict);
8303// PackageDef *pd;
8304// for (pdi.toFirst();(pd=pdi.current());++pdi)
8305// {
8306// pd->writeDocumentation(*g_outputList);
8307// }
8308// }
8309//}
8310
8311//----------------------------------------------------------------------------
8312// generate module pages
8313
8314static void generateNamespaceDocs()
8315{
8316 writeNamespaceIndex(*g_outputList);
8317
8318 NamespaceSDict::Iterator nli(*Doxygen::namespaceSDict);
8319 NamespaceDef *nd;
8320 // for each namespace...
8321 for (;(nd=nli.current());++nli)
8322 {
8323
8324 if (nd->isLinkableInProject())
8325 {
8326 msg("Generating docs for namespace %s\n",nd->name().data());
8327 nd->writeDocumentation(*g_outputList);
8328 }
8329
8330 // for each class in the namespace...
8331 ClassSDict::Iterator cli(*nd->getClassSDict());
8332 for ( ; cli.current() ; ++cli )
8333 {
8334 ClassDef *cd=cli.current();
8335 if ( ( cd->isLinkableInProject() &&
8336 cd->templateMaster()==0
8337 ) // skip external references, anonymous compounds and
8338 // template instances and nested classes
8339 && !cd->isHidden()
8340 )
8341 {
8342 msg("Generating docs for compound %s...\n",cd->name().data());
8343
8344 cd->writeDocumentation(*g_outputList);
8345 cd->writeMemberList(*g_outputList);
8346 }
8347 cd->writeDocumentationForInnerClasses(*g_outputList);
8348 }
8349 }
8350}
8351
8352#if defined(_WIN32)
8353static QCString fixSlashes(QCString &s)
8354{
8355 QCString result;
8356 uint i;
8357 for (i=0;i<s.length();i++)
8358 {
8359 switch(s.at(i))
8360 {
8361 case '/':
8362 case '\\':
8363 result+="\\\\";
8364 break;
8365 default:
8366 result+=s.at(i);
8367 }
8368 }
8369 return result;
8370}
8371#endif
8372
8373
8374//----------------------------------------------------------------------------
8375// generate files for the search engine
8376
8377//static void generateSearchIndex()
8378//{
8379// if (Config_getBool("SEARCHENGINE") && Config_getBool("GENERATE_HTML"))
8380// {
8381// // create search index
8382// QCString fileName;
8383// writeSearchButton(Config_getString("HTML_OUTPUT"));
8384//
8385//#if !defined(_WIN32)
8386// // create cgi script
8387// fileName = Config_getString("HTML_OUTPUT")+"/"+Config_getString("CGI_NAME");
8388// QFile f(fileName);
8389// if (f.open(IO_WriteOnly))
8390// {
8391// QTextStream t(&f);
8392// t << "#!/bin/sh" << endl
8393// << "DOXYSEARCH=" << Config_getString("BIN_ABSPATH") << "/doxysearch" << endl
8394// << "DOXYPATH=\"" << Config_getString("DOC_ABSPATH") << " ";
8395//
8396// QStrList &extDocPaths=Config_getList("EXT_DOC_PATHS");
8397// char *s= extDocPaths.first();
8398// while (s)
8399// {
8400// t << s << " ";
8401// s=extDocPaths.next();
8402// }
8403//
8404// t << "\"" << endl
8405// << "if [ -f $DOXYSEARCH ]" << endl
8406// << "then" << endl
8407// << " $DOXYSEARCH $DOXYPATH" << endl
8408// << "else" << endl
8409// << " echo \"Content-Type: text/html\"" << endl
8410// << " echo \"\"" << endl
8411// << " echo \"<h2>error: $DOXYSEARCH not found. Check cgi script!</h2>\"" << endl
8412// << "fi" << endl;
8413//
8414// f.close();
8415// struct stat stat_struct;
8416// stat(fileName,&stat_struct);
8417// chmod(fileName,stat_struct.st_mode|S_IXUSR|S_IXGRP|S_IXOTH);
8418// }
8419// else
8420// {
8421// err("error: Cannot open file %s for writing\n",fileName.data());
8422// }
8423//#else /* Windows platform */
8424// // create cgi program
8425// fileName = Config_getString("CGI_NAME").copy();
8426// if (fileName.right(4)==".cgi")
8427// fileName=fileName.left(fileName.length()-4);
8428// fileName+=".c";
8429// fileName.prepend(Config_getString("HTML_OUTPUT")+"/");
8430// QFile f(fileName);
8431// if (f.open(IO_WriteOnly))
8432// {
8433// QTextStream t(&f);
8434// t << "#include <stdio.h>" << endl;
8435// t << "#include <stdlib.h>" << endl;
8436// t << "#include <process.h>" << endl;
8437// t << endl;
8438// t << "const char *DOXYSEARCH = \"" <<
8439// fixSlashes(Config_getString("BIN_ABSPATH")) << "\\\\doxysearch.exe\";" << endl;
8440// t << "const char *DOXYPATH = \"" <<
8441// fixSlashes(Config_getString("DOC_ABSPATH")) << "\";" << endl;
8442// t << endl;
8443// t << "int main(void)" << endl;
8444// t << "{" << endl;
8445// t << " char buf[1024];" << endl;
8446// t << " sprintf(buf,\"%s %s\",DOXYSEARCH,DOXYPATH);" << endl;
8447// t << " if (system(buf))" << endl;
8448// t << " {" << endl;
8449// t << " printf(\"Content-Type: text/html\\n\\n\");" << endl;
8450// t << " printf(\"<h2>error: failed to execute %s</h2>\\n\",DOXYSEARCH);" << endl;
8451// t << " exit(1);" << endl;
8452// t << " }" << endl;
8453// t << " return 0;" << endl;
8454// t << "}" << endl;
8455// f.close();
8456// }
8457// else
8458// {
8459// err("error: Cannot open file %s for writing\n",fileName.data());
8460// }
8461//#endif /* !defined(_WIN32) */
8462//
8463// // create config file
8464// fileName = Config_getString("HTML_OUTPUT")+"/search.cfg";
8465// f.setName(fileName);
8466// if (f.open(IO_WriteOnly))
8467// {
8468// QTextStream t(&f);
8469// t << Config_getString("DOC_URL") << "/" << endl
8470// << Config_getString("CGI_URL") << "/" << Config_getString("CGI_NAME") << endl;
8471// f.close();
8472// }
8473// else
8474// {
8475// err("error: Cannot open file %s for writing\n",fileName.data());
8476// }
8477// //g_outputList->generateExternalIndex();
8478// g_outputList->pushGeneratorState();
8479// g_outputList->disableAllBut(OutputGenerator::Html);
8480// startFile(*g_outputList,"header"+Doxygen::htmlFileExtension,0,"Search Engine",TRUE);
8481// g_outputList->endPlainFile();
8482// g_outputList->startPlainFile("footer"+Doxygen::htmlFileExtension);
8483// endFile(*g_outputList,TRUE);
8484// g_outputList->popGeneratorState();
8485// }
8486//}
8487
8488//----------------------------------------------------------------------------
8489
8490static bool openOutputFile(const char *outFile,QFile &f)
8491{
8492 bool fileOpened=FALSE;
8493 bool writeToStdout=(outFile[0]=='-' && outFile[1]=='\0');
8494 if (writeToStdout) // write to stdout
8495 {
8496 fileOpened = f.open(IO_WriteOnly,stdout);
8497 }
8498 else // write to file
8499 {
8500 QFileInfo fi(outFile);
8501 if (fi.exists()) // create a backup
8502 {
8503 QDir dir=fi.dir();
8504 QFileInfo backup(fi.fileName()+".bak");
8505 if (backup.exists()) // remove existing backup
8506 dir.remove(backup.fileName());
8507 dir.rename(fi.fileName(),fi.fileName()+".bak");
8508 }
8509 f.setName(outFile);
8510 fileOpened = f.open(IO_WriteOnly|IO_Translate);
8511 }
8512 return fileOpened;
8513}
8514
8515/*! Generate a template version of the configuration file.
8516 * If the \a shortList parameter is TRUE a configuration file without
8517 * comments will be generated.
8518 */
8519static void generateConfigFile(const char *configFile,bool shortList,
8520 bool updateOnly=FALSE)
8521{
8522 QFile f;
8523 bool fileOpened=openOutputFile(configFile,f);
8524 bool writeToStdout=(configFile[0]=='-' && configFile[1]=='\0');
8525 if (fileOpened)
8526 {
8527 FTextStream t(&f);
8528 Config::instance()->writeTemplate(t,shortList,updateOnly);
8529 if (!writeToStdout)
8530 {
8531 if (!updateOnly)
8532 {
8533 msg("\n\nConfiguration file `%s' created.\n\n",configFile);
8534 msg("Now edit the configuration file and enter\n\n");
8535 if (strcmp(configFile,"Doxyfile") || strcmp(configFile,"doxyfile"))
8536 msg(" doxygen %s\n\n",configFile);
8537 else
8538 msg(" doxygen\n\n");
8539 msg("to generate the documentation for your project\n\n");
8540 }
8541 else
8542 {
8543 msg("\n\nConfiguration file `%s' updated.\n\n",configFile);
8544 }
8545 }
8546 }
8547 else
8548 {
8549 err("error: Cannot open file %s for writing\n",configFile);
8550 exit(1);
8551 }
8552}
8553
8554//----------------------------------------------------------------------------
8555// read and parse a tag file
8556
8557//static bool readLineFromFile(QFile &f,QCString &s)
8558//{
8559// char c=0;
8560// s.resize(0);
8561// while (!f.atEnd() && (c=f.getch())!='\n') s+=c;
8562// return f.atEnd();
8563//}
8564
8565//----------------------------------------------------------------------------
8566
8567static void readTagFile(Entry *root,const char *tl)
8568{
8569 QCString tagLine = tl;
8570 QCString fileName;
8571 QCString destName;
8572 int eqPos = tagLine.find('=');
8573 if (eqPos!=-1) // tag command contains a destination
8574 {
8575 fileName = tagLine.left(eqPos).stripWhiteSpace();
8576 destName = tagLine.right(tagLine.length()-eqPos-1).stripWhiteSpace();
8577 QFileInfo fi(fileName);
8578 Doxygen::tagDestinationDict.insert(fi.fileName(),new QCString(destName));
8579 //printf("insert tagDestination %s->%s\n",fi.fileName().data(),destName.data());
8580 }
8581 else
8582 {
8583 fileName = tagLine;
8584 }
8585
8586 QFileInfo fi(fileName);
8587 if (!fi.exists() || !fi.isFile())
8588 {
8589 err("error: Tag file `%s' does not exist or is not a file. Skipping it...\n",
8590 fileName.data());
8591 return;
8592 }
8593
8594 if (!destName.isEmpty())
8595 msg("Reading tag file `%s', location `%s'...\n",fileName.data(),destName.data());
8596 else
8597 msg("Reading tag file `%s'...\n",fileName.data());
8598
8599 parseTagFile(root,fi.absFilePath(),fi.fileName());
8600
8601}
8602
8603//----------------------------------------------------------------------------
8604static void copyFile(const QCString &src,const QCString &dest)
8605{
8606 QFile sf(src);
8607 if (sf.open(IO_ReadOnly))
8608 {
8609 QFileInfo fi(src);
8610 QFile df(dest);
8611 if (df.open(IO_WriteOnly))
8612 {
8613 char *buffer = new char[fi.size()];
8614 sf.readBlock(buffer,fi.size());
8615 df.writeBlock(buffer,fi.size());
8616 df.flush();
8617 delete[] buffer;
8618 }
8619 else
8620 {
8621 err("error: could not write to file %s\n",dest.data());
8622 }
8623 }
8624 else
8625 {
8626 err("error: could not open user specified file %s\n",src.data());
8627 }
8628}
8629
8630static void copyStyleSheet()
8631{
8632 QCString &htmlStyleSheet = Config_getString("HTML_STYLESHEET");
8633 if (!htmlStyleSheet.isEmpty())
8634 {
8635 QFileInfo fi(htmlStyleSheet);
8636 if (!fi.exists())
8637 {
8638 err("Style sheet '%s' specified by HTML_STYLESHEET does not exist!\n",htmlStyleSheet.data());
8639 htmlStyleSheet.resize(0); // revert to the default
8640 }
8641 else
8642 {
8643 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8644 copyFile(htmlStyleSheet,destFileName);
8645 }
8646 }
8647}
8648
8649static void copyLogo()
8650{
8651 QCString &projectLogo = Config_getString("PROJECT_LOGO");
8652 if (!projectLogo.isEmpty())
8653 {
8654 QFileInfo fi(projectLogo);
8655 if (!fi.exists())
8656 {
8657 err("Project logo '%s' specified by PROJECT_LOGO does not exist!\n",projectLogo.data());
8658 projectLogo.resize(0); // revert to the default
8659 }
8660 else
8661 {
8662 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8663 copyFile(projectLogo,destFileName);
8664 }
8665 }
8666}
8667
8668static void copyExtraFiles()
8669{
8670 QStrList files = Config_getList("HTML_EXTRA_FILES");
8671 uint i;
8672 for (i=0; i<files.count(); ++i)
8673 {
8674 QCString fileName(files.at(i));
8675
8676 if (!fileName.isEmpty())
8677 {
8678 QFileInfo fi(fileName);
8679 if (!fi.exists())
8680 {
8681 err("Extra HTML file '%s' specified in HTML_EXTRA_FILES does not exist!\n", fileName.data());
8682 }
8683 else
8684 {
8685 QCString destFileName = Config_getString("HTML_OUTPUT")+"/"+fi.fileName().data();
8686 Doxygen::indexList.addImageFile(fi.fileName().data());
8687 copyFile(fileName, destFileName);
8688 }
8689 }
8690 }
8691}
8692
8693//! parse the list of input files
8694static void parseFiles(Entry *root,EntryNav *rootNav)
8695{
8696#if 0
8697 void *cd = 0;
8698 QCString inpEncoding = Config_getString("INPUT_ENCODING");
8699 bool needsTranscoding = !inpEncoding.isEmpty();
8700 if (needsTranscoding)
8701 {
8702 if (!(cd = portable_iconv_open("UTF-8", inpEncoding)))
8703 {
8704 err("error: unsupported character enconding: '%s'",inpEncoding.data());
8705 exit(1);
8706 }
8707 }
8708#endif
8709
8710 QCString *s=g_inputFiles.first();
8711 while (s)
8712 {
8713 QCString fileName=*s;
8714 QCString extension;
8715 int ei = fileName.findRev('.');
8716 if (ei!=-1) extension=fileName.right(fileName.length()-ei);
8717 ParserInterface *parser = Doxygen::parserManager->getParser(extension);
8718
8719 QFileInfo fi(fileName);
8720 BufStr preBuf(fi.size()+4096);
8721
8722 if (Config_getBool("ENABLE_PREPROCESSING") &&
8723 parser->needsPreprocessing(extension))
8724 {
8725 BufStr inBuf(fi.size()+4096);
8726 msg("Preprocessing %s...\n",s->data());
8727 readInputFile(fileName,inBuf);
8728 preprocessFile(fileName,inBuf,preBuf);
8729 }
8730 else // no preprocessing
8731 {
8732 msg("Reading %s...\n",s->data());
8733 readInputFile(fileName,preBuf);
8734 }
8735
8736 BufStr convBuf(preBuf.curPos()+1024);
8737
8738 // convert multi-line C++ comments to C style comments
8739 convertCppComments(&preBuf,&convBuf,fileName);
8740
8741 convBuf.addChar('\0');
8742
8743 // use language parse to parse the file
8744 parser->parseInput(fileName,convBuf.data(),root);
8745
8746 // store the Entry tree in a file and create an index to
8747 // navigate/load entries
8748 bool ambig;
8749 FileDef *fd=findFileDef(Doxygen::inputNameDict,fileName,ambig);
8750 ASSERT(fd!=0);
8751 root->createNavigationIndex(rootNav,g_storage,fd);
8752
8753 s=g_inputFiles.next();
8754 }
8755}
8756
8757// resolves a path that may include symlinks, if a recursive symlink is
8758// found an empty string is returned.
8759static QCString resolveSymlink(QCString path)
8760{
8761 int sepPos=0;
8762 int oldPos=0;
8763 QFileInfo fi;
8764 QDict<void> nonSymlinks;
8765 QDict<void> known;
8766 QCString result = path;
8767 QCString oldPrefix = "/";
8768 do
8769 {
8770#ifdef WIN32
8771 // UNC path, skip server and share name
8772 if (sepPos==0 && (result.left(2)=="//" || result.left(2)=="\\\\"))
8773 sepPos = result.find('/',2);
8774 if (sepPos!=-1)
8775 sepPos = result.find('/',sepPos+1);
8776#else
8777 sepPos = result.find('/',sepPos+1);
8778#endif
8779 QCString prefix = sepPos==-1 ? result : result.left(sepPos);
8780 if (nonSymlinks.find(prefix)==0)
8781 {
8782 fi.setFile(prefix);
8783 if (fi.isSymLink())
8784 {
8785 QString target = fi.readLink();
8786 bool isRelative = QFileInfo(target).isRelative();
8787 if (isRelative)
8788 {
8789 target = QDir::cleanDirPath(oldPrefix+"/"+target.data());
8790 }
8791 if (sepPos!=-1)
8792 {
8793 if (fi.isDir() && target.length()>0 && target.at(target.length()-1)!='/')
8794 {
8795 target+='/';
8796 }
8797 target+=result.mid(sepPos);
8798 }
8799 result = QDir::cleanDirPath(target).data();
8800 sepPos = 0;
8801 if (known.find(result)) return QCString(); // recursive symlink!
8802 known.insert(result,(void*)0x8);
8803 if (isRelative)
8804 {
8805 sepPos = oldPos;
8806 }
8807 else // link to absolute path
8808 {
8809 sepPos = 0;
8810 oldPrefix = "/";
8811 }
8812 }
8813 else
8814 {
8815 nonSymlinks.insert(prefix,(void*)0x8);
8816 oldPrefix = prefix;
8817 }
8818 oldPos = sepPos;
8819 }
8820 }
8821 while (sepPos!=-1);
8822 return QDir::cleanDirPath(result).data();
8823}
8824
8825static QDict<void> g_pathsVisited(1009);
8826
8827//----------------------------------------------------------------------------
8828// Read all files matching at least one pattern in `patList' in the
8829// directory represented by `fi'.
8830// The directory is read iff the recusiveFlag is set.
8831// The contents of all files is append to the input string
8832
8833int readDir(QFileInfo *fi,
8834 FileNameList *fnList,
8835 FileNameDict *fnDict,
8836 StringDict *exclDict,
8837 QStrList *patList,
8838 QStrList *exclPatList,
8839 StringList *resultList,
8840 StringDict *resultDict,
8841 bool errorIfNotExist,
8842 bool recursive,
8843 QDict<void> *killDict
8844 )
8845{
8846 QString dirName = fi->absFilePath();
8847 if (fi->isSymLink())
8848 {
8849 dirName = resolveSymlink(dirName.data());
8850 if (dirName.isEmpty()) return 0; // recusive symlink
8851 if (g_pathsVisited.find(dirName)) return 0; // already visited path
8852 g_pathsVisited.insert(dirName,(void*)0x8);
8853 }
8854 QDir dir(dirName);
8855 dir.setFilter( QDir::Files | QDir::Dirs | QDir::Hidden );
8856 int totalSize=0;
8857 msg("Searching for files in directory %s\n", fi->absFilePath().data());
8858 //printf("killDict=%p count=%d\n",killDict,killDict->count());
8859
8860 const QFileInfoList *list = dir.entryInfoList();
8861 if (list)
8862 {
8863 QFileInfoListIterator it( *list );
8864 QFileInfo *cfi;
8865
8866 while ((cfi=it.current()))
8867 {
8868 if (exclDict==0 || exclDict->find(cfi->absFilePath())==0)
8869 { // file should not be excluded
8870 //printf("killDict->find(%s)\n",cfi->absFilePath().data());
8871 if (!cfi->exists() || !cfi->isReadable())
8872 {
8873 if (errorIfNotExist)
8874 {
8875 err("warning: source %s is not a readable file or directory... skipping.\n",cfi->absFilePath().data());
8876 }
8877 }
8878 else if (cfi->isFile() &&
8879 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
8880 (patList==0 || patternMatch(*cfi,patList)) &&
8881 !patternMatch(*cfi,exclPatList) &&
8882 (killDict==0 || killDict->find(cfi->absFilePath())==0)
8883 )
8884 {
8885 totalSize+=cfi->size()+cfi->absFilePath().length()+4;
8886 QCString name=convertToQCString(cfi->fileName());
8887 //printf("New file %s\n",name.data());
8888 if (fnDict)
8889 {
8890 FileDef *fd=new FileDef(cfi->dirPath()+"/",name);
8891 FileName *fn=0;
8892 if (!name.isEmpty() && (fn=(*fnDict)[name]))
8893 {
8894 fn->append(fd);
8895 }
8896 else
8897 {
8898 fn = new FileName(cfi->absFilePath(),name);
8899 fn->append(fd);
8900 if (fnList) fnList->inSort(fn);
8901 fnDict->insert(name,fn);
8902 }
8903 }
8904 QCString *rs=0;
8905 if (resultList || resultDict)
8906 {
8907 rs=new QCString(cfi->absFilePath());
8908 }
8909 if (resultList) resultList->append(rs);
8910 if (resultDict) resultDict->insert(cfi->absFilePath(),rs);
8911 if (killDict) killDict->insert(cfi->absFilePath(),(void *)0x8);
8912 }
8913 else if (recursive &&
8914 (!Config_getBool("EXCLUDE_SYMLINKS") || !cfi->isSymLink()) &&
8915 cfi->isDir() && cfi->fileName()!="." &&
8916 !patternMatch(*cfi,exclPatList) &&
8917 cfi->fileName()!="..")
8918 {
8919 cfi->setFile(cfi->absFilePath());
8920 totalSize+=readDir(cfi,fnList,fnDict,exclDict,
8921 patList,exclPatList,resultList,resultDict,errorIfNotExist,
8922 recursive,killDict);
8923 }
8924 }
8925 ++it;
8926 }
8927 }
8928 return totalSize;
8929}
8930
8931
8932//----------------------------------------------------------------------------
8933// read a file or all files in a directory and append their contents to the
8934// input string. The names of the files are appended to the `fiList' list.
8935
8936int readFileOrDirectory(const char *s,
8937 FileNameList *fnList,
8938 FileNameDict *fnDict,
8939 StringDict *exclDict,
8940 QStrList *patList,
8941 QStrList *exclPatList,
8942 StringList *resultList,
8943 StringDict *resultDict,
8944 bool recursive,
8945 bool errorIfNotExist,
8946 QDict<void> *killDict
8947 )
8948{
8949 //printf("killDict=%p count=%d\n",killDict,killDict->count());
8950 // strip trailing slashes
8951 if (s==0) return 0;
8952 QCString fs = s;
8953 char lc = fs.at(fs.length()-1);
8954 if (lc=='/' || lc=='\\') fs = fs.left(fs.length()-1);
8955
8956 QFileInfo fi(fs);
8957 //printf("readFileOrDirectory(%s)\n",s);
8958 int totalSize=0;
8959 {
8960 if (exclDict==0 || exclDict->find(fi.absFilePath())==0)
8961 {
8962 if (!fi.exists() || !fi.isReadable())
8963 {
8964 if (errorIfNotExist)
8965 {
8966 err("warning: source %s is not a readable file or directory... skipping.\n",s);
8967 }
8968 }
8969 else if (!Config_getBool("EXCLUDE_SYMLINKS") || !fi.isSymLink())
8970 {
8971 if (fi.isFile())
8972 {
8973 //printf("killDict->find(%s)\n",fi.absFilePath().data());
8974 if (killDict==0 || killDict->find(fi.absFilePath())==0)
8975 {
8976 totalSize+=fi.size()+fi.absFilePath().length()+4; //readFile(&fi,fiList,input);
8977 //fiList->inSort(new FileInfo(fi));
8978 QCString name=convertToQCString(fi.fileName());
8979 //printf("New file %s\n",name.data());
8980 if (fnDict)
8981 {
8982 FileDef *fd=new FileDef(fi.dirPath(TRUE)+"/",name);
8983 FileName *fn=0;
8984 if (!name.isEmpty() && (fn=(*fnDict)[name]))
8985 {
8986 fn->append(fd);
8987 }
8988 else
8989 {
8990 fn = new FileName(fi.absFilePath(),name);
8991 fn->append(fd);
8992 if (fnList) fnList->inSort(fn);
8993 fnDict->insert(name,fn);
8994 }
8995 }
8996 QCString *rs=0;
8997 if (resultList || resultDict)
8998 {
8999 rs=new QCString(fi.absFilePath());
9000 if (resultList) resultList->append(rs);
9001 if (resultDict) resultDict->insert(fi.absFilePath(),rs);
9002 }
9003
9004 if (killDict) killDict->insert(fi.absFilePath(),(void *)0x8);
9005 }
9006 }
9007 else if (fi.isDir()) // readable dir
9008 {
9009 totalSize+=readDir(&fi,fnList,fnDict,exclDict,patList,
9010 exclPatList,resultList,resultDict,errorIfNotExist,
9011 recursive,killDict);
9012 }
9013 }
9014 }
9015 }
9016 return totalSize;
9017}
9018
9019//----------------------------------------------------------------------------
9020
9021void readFormulaRepository()
9022{
9023 QFile f(Config_getString("HTML_OUTPUT")+"/formula.repository");
9024 if (f.open(IO_ReadOnly)) // open repository
9025 {
9026 msg("Reading formula repository...\n");
9027 QTextStream t(&f);
9028 QCString line;
9029 while (!t.eof())
9030 {
9031 line=t.readLine();
9032 int se=line.find(':'); // find name and text separator.
9033 if (se==-1)
9034 {
9035 err("warning: formula.repository is corrupted!\n");
9036 break;
9037 }
9038 else
9039 {
9040 QCString formName = line.left(se);
9041 QCString formText = line.right(line.length()-se-1);
9042 Formula *f=new Formula(formText);
9043 Doxygen::formulaList.append(f);
9044 Doxygen::formulaDict.insert(formText,f);
9045 Doxygen::formulaNameDict.insert(formName,f);
9046 }
9047 }
9048 }
9049}
9050
9051//----------------------------------------------------------------------------
9052
9053static void expandAliases()
9054{
9055 QDictIterator<QCString> adi(Doxygen::aliasDict);
9056 QCString *s;
9057 for (adi.toFirst();(s=adi.current());++adi)
9058 {
9059 *s = expandAlias(adi.currentKey(),*s);
9060 }
9061}
9062
9063//----------------------------------------------------------------------------
9064
9065static void escapeAliases()
9066{
9067 QDictIterator<QCString> adi(Doxygen::aliasDict);
9068 QCString *s;
9069 for (adi.toFirst();(s=adi.current());++adi)
9070 {
9071 QCString value=*s,newValue;
9072 int in,p=0;
9073 // for each \n in the alias command value
9074 while ((in=value.find("\\n",p))!=-1)
9075 {
9076 newValue+=value.mid(p,in-p);
9077 // expand \n's except if \n is part of a built-in command.
9078 if (value.mid(in,5)!="\\note" &&
9079 value.mid(in,5)!="\\name" &&
9080 value.mid(in,10)!="\\namespace" &&
9081 value.mid(in,14)!="\\nosubgrouping"
9082 )
9083 {
9084 newValue+="\\_linebr ";
9085 }
9086 else
9087 {
9088 newValue+="\\n";
9089 }
9090 p=in+2;
9091 }
9092 newValue+=value.mid(p,value.length()-p);
9093 *s=newValue;
9094 //printf("Alias %s has value %s\n",adi.currentKey().data(),s->data());
9095 }
9096}
9097
9098//----------------------------------------------------------------------------
9099
9100void readAliases()
9101{
9102 // add aliases to a dictionary
9103 Doxygen::aliasDict.setAutoDelete(TRUE);
9104 QStrList &aliasList = Config_getList("ALIASES");
9105 const char *s=aliasList.first();
9106 while (s)
9107 {
9108 if (Doxygen::aliasDict[s]==0)
9109 {
9110 QCString alias=s;
9111 int i=alias.find('=');
9112 if (i>0)
9113 {
9114 QCString name=alias.left(i).stripWhiteSpace();
9115 QCString value=alias.right(alias.length()-i-1);
9116 //printf("Alias: found name=`%s' value=`%s'\n",name.data(),value.data());
9117 if (!name.isEmpty())
9118 {
9119 QCString *dn=Doxygen::aliasDict[name];
9120 if (dn==0) // insert new alias
9121 {
9122 Doxygen::aliasDict.insert(name,new QCString(value));
9123 }
9124 else // overwrite previous alias
9125 {
9126 *dn=value;
9127 }
9128 }
9129 }
9130 }
9131 s=aliasList.next();
9132 }
9133 expandAliases();
9134 escapeAliases();
9135}
9136
9137//----------------------------------------------------------------------------
9138
9139static void dumpSymbol(FTextStream &t,Definition *d)
9140{
9141 QCString anchor;
9142 if (d->definitionType()==Definition::TypeMember)
9143 {
9144 MemberDef *md = (MemberDef *)d;
9145 anchor=":"+md->anchor();
9146 }
9147 QCString scope;
9148 if (d->getOuterScope() && d->getOuterScope()!=Doxygen::globalScope)
9149 {
9150 scope = d->getOuterScope()->getOutputFileBase()+Doxygen::htmlFileExtension;
9151 }
9152 t << "REPLACE INTO symbols (symbol_id,scope_id,name,file,line) VALUES('"
9153 << d->getOutputFileBase()+Doxygen::htmlFileExtension+anchor << "','"
9154 << scope << "','"
9155 << d->name() << "','"
9156 << d->getDefFileName() << "','"
9157 << d->getDefLine()
9158 << "');" << endl;
9159}
9160
9161static void dumpSymbolMap()
9162{
9163 QFile f("symbols.sql");
9164 if (f.open(IO_WriteOnly))
9165 {
9166 FTextStream t(&f);
9167 QDictIterator<DefinitionIntf> di(*Doxygen::symbolMap);
9168 DefinitionIntf *intf;
9169 for (;(intf=di.current());++di)
9170 {
9171 if (intf->definitionType()==DefinitionIntf::TypeSymbolList) // list of symbols
9172 {
9173 DefinitionListIterator dli(*(DefinitionList*)intf);
9174 Definition *d;
9175 // for each symbol
9176 for (dli.toFirst();(d=dli.current());++dli)
9177 {
9178 dumpSymbol(t,d);
9179 }
9180 }
9181 else // single symbol
9182 {
9183 Definition *d = (Definition *)intf;
9184 if (d!=Doxygen::globalScope) dumpSymbol(t,d);
9185 }
9186 }
9187 }
9188}
9189
9190//----------------------------------------------------------------------------
9191
9192void dumpConfigAsXML()
9193{
9194 QFile f("config.xml");
9195 if (f.open(IO_WriteOnly))
9196 {
9197 FTextStream t(&f);
9198 Config::instance()->writeXML(t);
9199 }
9200}
9201
9202//----------------------------------------------------------------------------
9203// print the usage of doxygen
9204
9205static void usage(const char *name)
9206{
9207 msg("Doxygen version %s\nCopyright Dimitri van Heesch 1997-2011\n\n",versionString);
9208 msg("You can use doxygen in a number of ways:\n\n");
9209 msg("1) Use doxygen to generate a template configuration file:\n");
9210 msg(" %s [-s] -g [configName]\n\n",name);
9211 msg(" If - is used for configName doxygen will write to standard output.\n\n");
9212 msg("2) Use doxygen to update an old configuration file:\n");
9213 msg(" %s [-s] -u [configName]\n\n",name);
9214 msg("3) Use doxygen to generate documentation using an existing ");
9215 msg("configuration file:\n");
9216 msg(" %s [configName]\n\n",name);
9217 msg(" If - is used for configName doxygen will read from standard input.\n\n");
9218 msg("4) Use doxygen to generate a template file controlling the layout of the\n");
9219 msg(" generated documentation:\n");
9220 msg(" %s -l layoutFileName.xml\n\n",name);
9221 msg("5) Use doxygen to generate a template style sheet file for RTF, HTML or Latex.\n");
9222 msg(" RTF: %s -w rtf styleSheetFile\n",name);
9223 msg(" HTML: %s -w html headerFile footerFile styleSheetFile [configFile]\n",name);
9224 msg(" LaTeX: %s -w latex headerFile footerFile styleSheetFile [configFile]\n\n",name);
9225 msg("6) Use doxygen to generate an rtf extensions file\n");
9226 msg(" RTF: %s -e rtf extensionsFile\n\n",name);
9227 msg("If -s is specified the comments in the config file will be omitted.\n");
9228 msg("If configName is omitted `Doxyfile' will be used as a default.\n\n");
9229 exit(1);
9230}
9231
9232//----------------------------------------------------------------------------
9233// read the argument of option `c' from the comment argument list and
9234// update the option index `optind'.
9235
9236static const char *getArg(int argc,char **argv,int &optind)
9237{
9238 char *s=0;
9239 if (strlen(&argv[optind][2])>0)
9240 s=&argv[optind][2];
9241 else if (optind+1<argc && argv[optind+1][0]!='-')
9242 s=argv[++optind];
9243 return s;
9244}
9245
9246//----------------------------------------------------------------------------
9247
9248extern void commentScanTest();
9249
9250void initDoxygen()
9251{
9252 setlocale(LC_ALL,"");
9253 setlocale(LC_CTYPE,"C"); // to get isspace(0xA0)==0, needed for UTF-8
9254 setlocale(LC_NUMERIC,"C");
9255
9256 //Doxygen::symbolMap->setAutoDelete(TRUE);
9257
9258 Doxygen::runningTime.start();
9259 initPreprocessor();
9260
9261 Doxygen::parserManager = new ParserManager;
9262 Doxygen::parserManager->registerParser("c", new CLanguageScanner, TRUE);
9263 Doxygen::parserManager->registerParser("python", new PythonLanguageScanner);
9264 Doxygen::parserManager->registerParser("fortran", new FortranLanguageScanner);
9265 Doxygen::parserManager->registerParser("vhdl", new VHDLLanguageScanner);
9266 Doxygen::parserManager->registerParser("dbusxml", new DBusXMLScanner);
9267
9268 // register any additional parsers here...
9269
9270 initDefaultExtensionMapping();
9271 initClassMemberIndices();
9272 initNamespaceMemberIndices();
9273 initFileMemberIndices();
9274
9275 Doxygen::symbolMap = new QDict<DefinitionIntf>(1000);
9276 Doxygen::inputNameList = new FileNameList;
9277 Doxygen::inputNameList->setAutoDelete(TRUE);
9278 Doxygen::memberNameSDict = new MemberNameSDict(10000);
9279 Doxygen::memberNameSDict->setAutoDelete(TRUE);
9280 Doxygen::functionNameSDict = new MemberNameSDict(10000);
9281 Doxygen::functionNameSDict->setAutoDelete(TRUE);
9282 Doxygen::groupSDict = new GroupSDict(17);
9283 Doxygen::groupSDict->setAutoDelete(TRUE);
9284 Doxygen::globalScope = new NamespaceDef("<globalScope>",1,"<globalScope>");
9285 Doxygen::namespaceSDict = new NamespaceSDict(20);
9286 Doxygen::namespaceSDict->setAutoDelete(TRUE);
9287 Doxygen::classSDict = new ClassSDict(1009);
9288 Doxygen::classSDict->setAutoDelete(TRUE);
9289 Doxygen::hiddenClasses = new ClassSDict(257);
9290 Doxygen::hiddenClasses->setAutoDelete(TRUE);
9291 Doxygen::directories = new DirSDict(17);
9292 Doxygen::directories->setAutoDelete(TRUE);
9293 Doxygen::pageSDict = new PageSDict(1009); // all doc pages
9294 Doxygen::pageSDict->setAutoDelete(TRUE);
9295 Doxygen::exampleSDict = new PageSDict(1009); // all examples
9296 Doxygen::exampleSDict->setAutoDelete(TRUE);
9297 Doxygen::inputNameDict = new FileNameDict(10007);
9298 Doxygen::includeNameDict = new FileNameDict(10007);
9299 Doxygen::exampleNameDict = new FileNameDict(1009);
9300 Doxygen::exampleNameDict->setAutoDelete(TRUE);
9301 Doxygen::imageNameDict = new FileNameDict(257);
9302 Doxygen::dotFileNameDict = new FileNameDict(257);
9303 Doxygen::mscFileNameDict = new FileNameDict(257);
9304 Doxygen::sectionDict.setAutoDelete(TRUE);
9305 Doxygen::memGrpInfoDict.setAutoDelete(TRUE);
9306 Doxygen::tagDestinationDict.setAutoDelete(TRUE);
9307 Doxygen::lookupCache.setAutoDelete(TRUE);
9308 Doxygen::dirRelations.setAutoDelete(TRUE);
9309}
9310
9311void cleanUpDoxygen()
9312{
9313 delete Doxygen::inputNameDict;
9314 delete Doxygen::includeNameDict;
9315 delete Doxygen::exampleNameDict;
9316 delete Doxygen::imageNameDict;
9317 delete Doxygen::dotFileNameDict;
9318 delete Doxygen::mscFileNameDict;
9319 delete Doxygen::mainPage;
9320 delete Doxygen::pageSDict;
9321 delete Doxygen::exampleSDict;
9322 delete Doxygen::globalScope;
9323 delete Doxygen::xrefLists;
9324 delete Doxygen::parserManager;
9325 cleanUpPreprocessor();
9326 delete theTranslator;
9327 delete g_outputList;
9328 Mappers::freeMappers();
9329 codeFreeScanner();
9330
9331 if (Doxygen::symbolMap)
9332 {
9333 // iterate through Doxygen::symbolMap and delete all
9334 // DefinitionList objects, since they have no owner
9335 QDictIterator<DefinitionIntf> dli(*Doxygen::symbolMap);
9336 DefinitionIntf *di;
9337 for (dli.toFirst();(di=dli.current());)
9338 {
9339 if (di->definitionType()==DefinitionIntf::TypeSymbolList)
9340 {
9341 DefinitionIntf *tmp = Doxygen::symbolMap->take(dli.currentKey());
9342 delete (DefinitionList *)tmp;
9343 }
9344 else
9345 {
9346 ++dli;
9347 }
9348 }
9349 }
9350
9351 delete Doxygen::inputNameList;
9352 delete Doxygen::memberNameSDict;
9353 delete Doxygen::functionNameSDict;
9354 delete Doxygen::groupSDict;
9355 delete Doxygen::classSDict;
9356 delete Doxygen::hiddenClasses;
9357 delete Doxygen::namespaceSDict;
9358 delete Doxygen::directories;
9359
9360 //delete Doxygen::symbolMap; <- we cannot do this unless all static lists
9361 // (such as Doxygen::namespaceSDict)
9362 // with objects based on Definition are made
9363 // dynamic first
9364}
9365
9366void readConfiguration(int argc, char **argv)
9367{
9368 /**************************************************************************
9369 * Handle arguments *
9370 **************************************************************************/
9371
9372 int optind=1;
9373 const char *configName=0;
9374 const char *layoutName=0;
9375 const char *debugLabel;
9376 const char *formatName;
9377 bool genConfig=FALSE;
9378 bool shortList=FALSE;
9379 bool updateConfig=FALSE;
9380 bool genLayout=FALSE;
9381 while (optind<argc && argv[optind][0]=='-' &&
9382 (isalpha(argv[optind][1]) || argv[optind][1]=='?' ||
9383 argv[optind][1]=='-')
9384 )
9385 {
9386 switch(argv[optind][1])
9387 {
9388 case 'g':
9389 genConfig=TRUE;
9390 configName=getArg(argc,argv,optind);
9391 if (strcmp(argv[optind+1],"-")==0)
9392 { configName="-"; optind++; }
9393 if (!configName)
9394 { configName="Doxyfile"; }
9395 break;
9396 case 'l':
9397 genLayout=TRUE;
9398 layoutName=getArg(argc,argv,optind);
9399 if (!layoutName)
9400 { layoutName="DoxygenLayout.xml"; }
9401 break;
9402 case 'd':
9403 debugLabel=getArg(argc,argv,optind);
9404 Debug::setFlag(debugLabel);
9405 break;
9406 case 's':
9407 shortList=TRUE;
9408 break;
9409 case 'u':
9410 updateConfig=TRUE;
9411 break;
9412 case 'e':
9413 formatName=getArg(argc,argv,optind);
9414 if (!formatName)
9415 {
9416 err("error: option -e is missing format specifier rtf.\n");
9417 cleanUpDoxygen();
9418 exit(1);
9419 }
9420 if (stricmp(formatName,"rtf")==0)
9421 {
9422 if (optind+1>=argc)
9423 {
9424 err("error: option \"-e rtf\" is missing an extensions file name\n");
9425 cleanUpDoxygen();
9426 exit(1);
9427 }
9428 QFile f;
9429 if (openOutputFile(argv[optind+1],f))
9430 {
9431 RTFGenerator::writeExtensionsFile(f);
9432 }
9433 cleanUpDoxygen();
9434 exit(1);
9435 }
9436 err("error: option \"-e\" has invalid format specifier.\n");
9437 cleanUpDoxygen();
9438 exit(1);
9439 break;
9440 case 'w':
9441 formatName=getArg(argc,argv,optind);
9442 if (!formatName)
9443 {
9444 err("error: option -w is missing format specifier rtf, html or latex\n");
9445 cleanUpDoxygen();
9446 exit(1);
9447 }
9448 if (stricmp(formatName,"rtf")==0)
9449 {
9450 if (optind+1>=argc)
9451 {
9452 err("error: option \"-w rtf\" is missing a style sheet file name\n");
9453 cleanUpDoxygen();
9454 exit(1);
9455 }
9456 QFile f;
9457 if (openOutputFile(argv[optind+1],f))
9458 {
9459 RTFGenerator::writeStyleSheetFile(f);
9460 }
9461 cleanUpDoxygen();
9462 exit(1);
9463 }
9464 else if (stricmp(formatName,"html")==0)
9465 {
9466 if (optind+4<argc || QFileInfo("Doxyfile").exists())
9467 {
9468 QCString df = optind+4<argc ? argv[optind+4] : QCString("Doxyfile");
9469 if (!Config::instance()->parse(df))
9470 {
9471 err("error opening or reading configuration file %s!\n",argv[optind+4]);
9472 cleanUpDoxygen();
9473 exit(1);
9474 }
9475 Config::instance()->substituteEnvironmentVars();
9476 Config::instance()->convertStrToVal();
9477 // avoid bootstrapping issues when the config file already
9478 // refers to the files that we are supposed to parse.
9479 Config_getString("HTML_HEADER")="";
9480 Config_getString("HTML_FOOTER")="";
9481 Config::instance()->check();
9482 }
9483 else
9484 {
9485 Config::instance()->init();
9486 }
9487 if (optind+3>=argc)
9488 {
9489 err("error: option \"-w html\" does not have enough arguments\n");
9490 cleanUpDoxygen();
9491 exit(1);
9492 }
9493
9494 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
9495 if (!setTranslator(outputLanguage))
9496 {
9497 err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
9498 }
9499
9500 QFile f;
9501 if (openOutputFile(argv[optind+1],f))
9502 {
9503 HtmlGenerator::writeHeaderFile(f, argv[optind+3]);
9504 }
9505 f.close();
9506 if (openOutputFile(argv[optind+2],f))
9507 {
9508 HtmlGenerator::writeFooterFile(f);
9509 }
9510 f.close();
9511 if (openOutputFile(argv[optind+3],f))
9512 {
9513 HtmlGenerator::writeStyleSheetFile(f);
9514 }
9515 cleanUpDoxygen();
9516 exit(0);
9517 }
9518 else if (stricmp(formatName,"latex")==0)
9519 {
9520 if (optind+4<argc) // use config file to get settings
9521 {
9522 if (!Config::instance()->parse(argv[optind+4]))
9523 {
9524 err("error opening or reading configuration file %s!\n",argv[optind+4]);
9525 exit(1);
9526 }
9527 Config::instance()->substituteEnvironmentVars();
9528 Config::instance()->convertStrToVal();
9529 Config_getString("LATEX_HEADER")="";
9530 Config::instance()->check();
9531 }
9532 else // use default config
9533 {
9534 Config::instance()->init();
9535 }
9536 if (optind+3>=argc)
9537 {
9538 err("error: option \"-w latex\" does not have enough arguments\n");
9539 cleanUpDoxygen();
9540 exit(1);
9541 }
9542
9543 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
9544 if (!setTranslator(outputLanguage))
9545 {
9546 err("warning: Output language %s not supported! Using English instead.\n", outputLanguage.data());
9547 }
9548
9549 QFile f;
9550 if (openOutputFile(argv[optind+1],f))
9551 {
9552 LatexGenerator::writeHeaderFile(f);
9553 }
9554 f.close();
9555 if (openOutputFile(argv[optind+2],f))
9556 {
9557 LatexGenerator::writeFooterFile(f);
9558 }
9559 f.close();
9560 if (openOutputFile(argv[optind+3],f))
9561 {
9562 LatexGenerator::writeStyleSheetFile(f);
9563 }
9564 cleanUpDoxygen();
9565 exit(0);
9566 }
9567 else
9568 {
9569 err("error: Illegal format specifier %s: should be one of rtf, html, or latex\n",formatName);
9570 cleanUpDoxygen();
9571 exit(1);
9572 }
9573 break;
9574 case 'm':
9575 g_dumpSymbolMap = TRUE;
9576 break;
9577 case 'x':
9578 g_dumpConfigAsXML = TRUE;
9579 break;
9580 case '-':
9581 if (strcmp(&argv[optind][2],"help")==0)
9582 {
9583 usage(argv[0]);
9584 }
9585 else if (strcmp(&argv[optind][2],"version")==0)
9586 {
9587 msg("%s\n",versionString);
9588 cleanUpDoxygen();
9589 exit(0);
9590 }
9591 break;
9592 case 'b':
9593 setvbuf(stdout,NULL,_IONBF,0);
9594 Doxygen::outputToWizard=TRUE;
9595 break;
9596 case 'h':
9597 case '?':
9598 usage(argv[0]);
9599 break;
9600 default:
9601 err("Unknown option -%c\n",argv[optind][1]);
9602 usage(argv[0]);
9603 }
9604 optind++;
9605 }
9606
9607 /**************************************************************************
9608 * Parse or generate the config file *
9609 **************************************************************************/
9610
9611 Config::instance()->init();
9612
9613 if (genConfig)
9614 {
9615 if (g_dumpConfigAsXML)
9616 {
9617 checkConfiguration();
9618 generateConfigFile(configName,shortList);
9619 dumpConfigAsXML();
9620 exit(0);
9621 }
9622 else
9623 {
9624 generateConfigFile(configName,shortList);
9625 }
9626 cleanUpDoxygen();
9627 exit(0);
9628 }
9629 if (genLayout)
9630 {
9631 writeDefaultLayoutFile(layoutName);
9632 cleanUpDoxygen();
9633 exit(0);
9634 }
9635
9636 QFileInfo configFileInfo1("Doxyfile"),configFileInfo2("doxyfile");
9637 if (optind>=argc)
9638 {
9639 if (configFileInfo1.exists())
9640 {
9641 configName="Doxyfile";
9642 }
9643 else if (configFileInfo2.exists())
9644 {
9645 configName="doxyfile";
9646 }
9647 else
9648 {
9649 err("Doxyfile not found and no input file specified!\n");
9650 usage(argv[0]);
9651 }
9652 }
9653 else
9654 {
9655 QFileInfo fi(argv[optind]);
9656 if (fi.exists() || strcmp(argv[optind],"-")==0)
9657 {
9658 configName=argv[optind];
9659 }
9660 else
9661 {
9662 err("error: configuration file %s not found!\n",argv[optind]);
9663 usage(argv[0]);
9664 }
9665 }
9666
9667
9668 if (!Config::instance()->parse(configName))
9669 {
9670 err("error: could not open or read configuration file %s!\n",configName);
9671 cleanUpDoxygen();
9672 exit(1);
9673 }
9674
9675 if (updateConfig)
9676 {
9677 generateConfigFile(configName,shortList,TRUE);
9678 cleanUpDoxygen();
9679 exit(0);
9680 }
9681
9682 /* Perlmod wants to know the path to the config file.*/
9683 QFileInfo configFileInfo(configName);
9684 setPerlModDoxyfile(configFileInfo.absFilePath().data());
9685
9686}
9687
9688/** check and resolve config options */
9689void checkConfiguration()
9690{
9691
9692 Config::instance()->substituteEnvironmentVars();
9693 Config::instance()->convertStrToVal();
9694 Config::instance()->check();
9695
9696 initWarningFormat();
9697}
9698
9699/** adjust globals that depend on configuration settings. */
9700void adjustConfiguration()
9701{
9702 QCString outputLanguage=Config_getEnum("OUTPUT_LANGUAGE");
9703 if (!setTranslator(outputLanguage))
9704 {
9705 err("warning: Output language %s not supported! Using English instead.\n",
9706 outputLanguage.data());
9707 }
9708 QStrList &includePath = Config_getList("INCLUDE_PATH");
9709 char *s=includePath.first();
9710 while (s)
9711 {
9712 QFileInfo fi(s);
9713 addSearchDir(fi.absFilePath());
9714 s=includePath.next();
9715 }
9716
9717 /* Set the global html file extension. */
9718 Doxygen::htmlFileExtension = Config_getString("HTML_FILE_EXTENSION");
9719
9720
9721 Doxygen::xrefLists->setAutoDelete(TRUE);
9722
9723 Doxygen::parseSourcesNeeded = Config_getBool("CALL_GRAPH") ||
9724 Config_getBool("CALLER_GRAPH") ||
9725 Config_getBool("REFERENCES_RELATION") ||
9726 Config_getBool("REFERENCED_BY_RELATION");
9727
9728 /**************************************************************************
9729 * Add custom extension mappings
9730 **************************************************************************/
9731
9732 QStrList &extMaps = Config_getList("EXTENSION_MAPPING");
9733 char *mapping = extMaps.first();
9734 while (mapping)
9735 {
9736 QCString mapStr = mapping;
9737 int i;
9738 if ((i=mapStr.find('='))!=-1)
9739 {
9740 QCString ext=mapStr.left(i).stripWhiteSpace().lower();
9741 QCString language=mapStr.mid(i+1).stripWhiteSpace().lower();
9742 if (!updateLanguageMapping(ext,language))
9743 {
9744 err("Failed to map file extension '%s' to unsupported language '%s'.\n"
9745 "Check the EXTENSION_MAPPING setting in the config file.\n",
9746 ext.data(),language.data());
9747 }
9748 else
9749 {
9750 msg("Adding custom extension mapping: .%s will be treated as language %s\n",
9751 ext.data(),language.data());
9752 }
9753 }
9754 mapping = extMaps.next();
9755 }
9756
9757
9758 // add predefined macro name to a dictionary
9759 QStrList &expandAsDefinedList =Config_getList("EXPAND_AS_DEFINED");
9760 s=expandAsDefinedList.first();
9761 while (s)
9762 {
9763 if (Doxygen::expandAsDefinedDict[s]==0)
9764 {
9765 Doxygen::expandAsDefinedDict.insert(s,(void *)666);
9766 }
9767 s=expandAsDefinedList.next();
9768 }
9769
9770 // read aliases and store them in a dictionary
9771 readAliases();
9772
9773 // store number of spaces in a tab into Doxygen::spaces
9774 int &tabSize = Config_getInt("TAB_SIZE");
9775 Doxygen::spaces.resize(tabSize+1);
9776 int sp;for (sp=0;sp<tabSize;sp++) Doxygen::spaces.at(sp)=' ';
9777 Doxygen::spaces.at(tabSize)='\0';
9778}
9779
9780#ifdef HAS_SIGNALS
9781static void stopDoxygen(int)
9782{
9783 QDir thisDir;
9784 msg("Cleaning up...\n");
9785 if (!Doxygen::entryDBFileName.isEmpty())
9786 {
9787 thisDir.remove(Doxygen::entryDBFileName);
9788 }
9789 if (!Doxygen::objDBFileName.isEmpty())
9790 {
9791 thisDir.remove(Doxygen::objDBFileName);
9792 }
9793 exit(1);
9794}
9795#endif
9796
9797static void exitDoxygen()
9798{
9799 if (!g_successfulRun) // premature exit
9800 {
9801 QDir thisDir;
9802 msg("Exiting...\n");
9803 if (!Doxygen::entryDBFileName.isEmpty())
9804 {
9805 thisDir.remove(Doxygen::entryDBFileName);
9806 }
9807 if (!Doxygen::objDBFileName.isEmpty())
9808 {
9809 thisDir.remove(Doxygen::objDBFileName);
9810 }
9811 }
9812}
9813
9814static QCString createOutputDirectory(const QCString &baseDirName,
9815 const char *formatDirOption,
9816 const char *defaultDirName)
9817{
9818 // Note the & on the next line, we modify the formatDirOption!
9819 QCString &formatDirName = Config_getString(formatDirOption);
9820 if (formatDirName.isEmpty())
9821 {
9822 formatDirName = baseDirName + defaultDirName;
9823 }
9824 else if (formatDirName[0]!='/' && (formatDirName.length()==1 || formatDirName[1]!=':'))
9825 {
9826 formatDirName.prepend(baseDirName+'/');
9827 }
9828 QDir formatDir(formatDirName);
9829 if (!formatDir.exists() && !formatDir.mkdir(formatDirName))
9830 {
9831 err("Could not create output directory %s\n", formatDirName.data());
9832 cleanUpDoxygen();
9833 exit(1);
9834 }
9835 return formatDirName;
9836}
9837
9838static QCString getQchFileName()
9839{
9840 QCString const & qchFile = Config_getString("QCH_FILE");
9841 if (!qchFile.isEmpty())
9842 {
9843 return qchFile;
9844 }
9845
9846 QCString const & projectName = Config_getString("PROJECT_NAME");
9847 QCString const & versionText = Config_getString("PROJECT_NUMBER");
9848
9849 return QCString("../qch/")
9850 + (projectName.isEmpty() ? QCString("index") : projectName)
9851 + (versionText.isEmpty() ? QCString("") : QCString("-") + versionText)
9852 + QCString(".qch");
9853}
9854
9855void searchInputFiles(StringList &inputFiles)
9856{
9857 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
9858 bool alwaysRecursive = Config_getBool("RECURSIVE");
9859 StringDict excludeNameDict(1009);
9860 excludeNameDict.setAutoDelete(TRUE);
9861
9862 // gather names of all files in the include path
9863 msg("Searching for include files...\n");
9864 QStrList &includePathList = Config_getList("INCLUDE_PATH");
9865 char *s=includePathList.first();
9866 while (s)
9867 {
9868 QStrList &pl = Config_getList("INCLUDE_FILE_PATTERNS");
9869 if (pl.count()==0)
9870 {
9871 pl = Config_getList("FILE_PATTERNS");
9872 }
9873 readFileOrDirectory(s,0,Doxygen::includeNameDict,0,&pl,
9874 &exclPatterns,0,0,
9875 alwaysRecursive);
9876 s=includePathList.next();
9877 }
9878
9879 msg("Searching for example files...\n");
9880 QStrList &examplePathList = Config_getList("EXAMPLE_PATH");
9881 s=examplePathList.first();
9882 while (s)
9883 {
9884 readFileOrDirectory(s,0,Doxygen::exampleNameDict,0,
9885 &Config_getList("EXAMPLE_PATTERNS"),
9886 0,0,0,
9887 (alwaysRecursive || Config_getBool("EXAMPLE_RECURSIVE")));
9888 s=examplePathList.next();
9889 }
9890
9891 msg("Searching for images...\n");
9892 QStrList &imagePathList=Config_getList("IMAGE_PATH");
9893 s=imagePathList.first();
9894 while (s)
9895 {
9896 readFileOrDirectory(s,0,Doxygen::imageNameDict,0,0,
9897 0,0,0,
9898 alwaysRecursive);
9899 s=imagePathList.next();
9900 }
9901
9902 msg("Searching for dot files...\n");
9903 QStrList &dotFileList=Config_getList("DOTFILE_DIRS");
9904 s=dotFileList.first();
9905 while (s)
9906 {
9907 readFileOrDirectory(s,0,Doxygen::dotFileNameDict,0,0,
9908 0,0,0,
9909 alwaysRecursive);
9910 s=dotFileList.next();
9911 }
9912
9913 msg("Searching for msc files...\n");
9914 QStrList &mscFileList=Config_getList("MSCFILE_DIRS");
9915 s=mscFileList.first();
9916 while (s)
9917 {
9918 readFileOrDirectory(s,0,Doxygen::mscFileNameDict,0,0,
9919 0,0,0,
9920 alwaysRecursive);
9921 s=dotFileList.next();
9922 }
9923
9924
9925 msg("Searching for files to exclude\n");
9926 QStrList &excludeList = Config_getList("EXCLUDE");
9927 s=excludeList.first();
9928 while (s)
9929 {
9930 readFileOrDirectory(s,0,0,0,&Config_getList("FILE_PATTERNS"),
9931 0,0,&excludeNameDict,
9932 alwaysRecursive,
9933 FALSE);
9934 s=excludeList.next();
9935 }
9936
9937 /**************************************************************************
9938 * Determine Input Files *
9939 **************************************************************************/
9940
9941 msg("Searching for files to process...\n");
9942 QDict<void> *killDict = new QDict<void>(10007);
9943 int inputSize=0;
9944 QStrList &inputList=Config_getList("INPUT");
9945 inputFiles.setAutoDelete(TRUE);
9946 s=inputList.first();
9947 while (s)
9948 {
9949 QCString path=s;
9950 uint l = path.length();
9951 // strip trailing slashes
9952 if (path.at(l-1)=='\\' || path.at(l-1)=='/') path=path.left(l-1);
9953
9954 inputSize+=readFileOrDirectory(
9955 path,
9956 Doxygen::inputNameList,
9957 Doxygen::inputNameDict,
9958 &excludeNameDict,
9959 &Config_getList("FILE_PATTERNS"),
9960 &exclPatterns,
9961 &inputFiles,0,
9962 alwaysRecursive,
9963 TRUE,
9964 killDict);
9965 s=inputList.next();
9966 }
9967 delete killDict;
9968}
9969
9970
9971void parseInput()
9972{
9973 atexit(exitDoxygen);
9974
9975
9976 /**************************************************************************
9977 * Make sure the output directory exists
9978 **************************************************************************/
9979 QCString &outputDirectory = Config_getString("OUTPUT_DIRECTORY");
9980 if (outputDirectory.isEmpty())
9981 {
9982 outputDirectory=QDir::currentDirPath();
9983 }
9984 else
9985 {
9986 QDir dir(outputDirectory);
9987 if (!dir.exists())
9988 {
9989 dir.setPath(QDir::currentDirPath());
9990 if (!dir.mkdir(outputDirectory))
9991 {
9992 err("error: tag OUTPUT_DIRECTORY: Output directory `%s' does not "
9993 "exist and cannot be created\n",outputDirectory.data());
9994 cleanUpDoxygen();
9995 exit(1);
9996 }
9997 else if (!Config_getBool("QUIET"))
9998 {
9999err("Notice: Output directory `%s' does not exist. "
10000 "I have created it for you.\n", outputDirectory.data());
10001 }
10002 dir.cd(outputDirectory);
10003 }
10004 outputDirectory=dir.absPath();
10005 }
10006
10007 /**************************************************************************
10008 * Initialize global lists and dictionaries
10009 **************************************************************************/
10010
10011 int cacheSize = Config_getInt("SYMBOL_CACHE_SIZE");
10012 if (cacheSize<0) cacheSize=0;
10013 if (cacheSize>9) cacheSize=9;
10014 Doxygen::symbolCache = new ObjCache(16+cacheSize); // 16 -> room for 65536 elements,
10015 // ~2.0 MByte "overhead"
10016 Doxygen::symbolStorage = new Store;
10017
10018#ifdef HAS_SIGNALS
10019 signal(SIGINT, stopDoxygen);
10020#endif
10021
10022 uint pid = portable_pid();
10023 Doxygen::objDBFileName.sprintf("doxygen_objdb_%d.tmp",pid);
10024 Doxygen::objDBFileName.prepend(outputDirectory+"/");
10025 Doxygen::entryDBFileName.sprintf("doxygen_entrydb_%d.tmp",pid);
10026 Doxygen::entryDBFileName.prepend(outputDirectory+"/");
10027
10028 if (Doxygen::symbolStorage->open(Doxygen::objDBFileName)==-1)
10029 {
10030 err("Failed to open temporary file %s\n",Doxygen::objDBFileName.data());
10031 exit(1);
10032 }
10033
10034
10035 /**************************************************************************
10036 * Initialize some global constants
10037 **************************************************************************/
10038
10039 g_compoundKeywordDict.insert("template class",(void *)8);
10040 g_compoundKeywordDict.insert("template struct",(void *)8);
10041 g_compoundKeywordDict.insert("class",(void *)8);
10042 g_compoundKeywordDict.insert("struct",(void *)8);
10043 g_compoundKeywordDict.insert("union",(void *)8);
10044 g_compoundKeywordDict.insert("interface",(void *)8);
10045 g_compoundKeywordDict.insert("exception",(void *)8);
10046
10047
10048 /**************************************************************************
10049 * Check/create output directorties *
10050 **************************************************************************/
10051
10052 QCString htmlOutput;
10053 bool &generateHtml = Config_getBool("GENERATE_HTML");
10054 if (generateHtml)
10055 htmlOutput = createOutputDirectory(outputDirectory,"HTML_OUTPUT","/html");
10056
10057 QCString xmlOutput;
10058 bool &generateXml = Config_getBool("GENERATE_XML");
10059 if (generateXml)
10060 xmlOutput = createOutputDirectory(outputDirectory,"XML_OUTPUT","/xml");
10061
10062 QCString latexOutput;
10063 bool &generateLatex = Config_getBool("GENERATE_LATEX");
10064 if (generateLatex)
10065 latexOutput = createOutputDirectory(outputDirectory,"LATEX_OUTPUT","/latex");
10066
10067 QCString rtfOutput;
10068 bool &generateRtf = Config_getBool("GENERATE_RTF");
10069 if (generateRtf)
10070 rtfOutput = createOutputDirectory(outputDirectory,"RTF_OUTPUT","/rtf");
10071
10072 QCString manOutput;
10073 bool &generateMan = Config_getBool("GENERATE_MAN");
10074 if (generateMan)
10075 manOutput = createOutputDirectory(outputDirectory,"MAN_OUTPUT","/man");
10076
10077
10078 if (Config_getBool("HAVE_DOT"))
10079 {
10080 QCString curFontPath = Config_getString("DOT_FONTPATH");
10081 if (curFontPath.isEmpty())
10082 {
10083 portable_getenv("DOTFONTPATH");
10084 QCString newFontPath = ".";
10085 if (!curFontPath.isEmpty())
10086 {
10087 newFontPath+=portable_pathListSeparator();
10088 newFontPath+=curFontPath;
10089 }
10090 portable_setenv("DOTFONTPATH",newFontPath);
10091 }
10092 else
10093 {
10094 portable_setenv("DOTFONTPATH",curFontPath);
10095 }
10096 }
10097
10098
10099
10100 /**************************************************************************
10101 * Handle layout file *
10102 **************************************************************************/
10103
10104 LayoutDocManager::instance().init();
10105 QCString layoutFileName = Config_getString("LAYOUT_FILE");
10106 bool defaultLayoutUsed = FALSE;
10107 if (layoutFileName.isEmpty())
10108 {
10109 layoutFileName = "DoxygenLayout.xml";
10110 defaultLayoutUsed = TRUE;
10111 }
10112
10113 QFile layoutFile(layoutFileName);
10114 if (layoutFile.open(IO_ReadOnly))
10115 {
10116 msg("Parsing layout file %s...\n",layoutFileName.data());
10117 QTextStream t(&layoutFile);
10118 t.setEncoding(QTextStream::Latin1);
10119 LayoutDocManager::instance().parse(t);
10120 }
10121 else if (!defaultLayoutUsed)
10122 {
10123 err("warning: failed to open layout file '%s' for reading!\n",layoutFileName.data());
10124 }
10125
10126 /**************************************************************************
10127 * Read and preprocess input *
10128 **************************************************************************/
10129
10130 // prevent search in the output directories
10131 QStrList &exclPatterns = Config_getList("EXCLUDE_PATTERNS");
10132 if (generateHtml) exclPatterns.append(htmlOutput);
10133 if (generateXml) exclPatterns.append(xmlOutput);
10134 if (generateLatex) exclPatterns.append(latexOutput);
10135 if (generateRtf) exclPatterns.append(rtfOutput);
10136 if (generateMan) exclPatterns.append(manOutput);
10137
10138
10139 searchInputFiles(g_inputFiles);
10140
10141 // Notice: the order of the function calls below is very important!
10142
10143 if (Config_getBool("GENERATE_HTML"))
10144 {
10145 readFormulaRepository();
10146 }
10147
10148 /**************************************************************************
10149 * Handle Tag Files *
10150 **************************************************************************/
10151
10152 g_storage = new FileStorage;
10153 g_storage->setName(Doxygen::entryDBFileName);
10154 if (!g_storage->open(IO_WriteOnly))
10155 {
10156 err("Failed to create temporary storage file %s\n",
10157 Doxygen::entryDBFileName.data());
10158 exit(1);
10159 }
10160 Entry *root=new Entry;
10161 EntryNav *rootNav = new EntryNav(0,root);
10162 rootNav->setEntry(root);
10163 msg("Reading and parsing tag files\n");
10164
10165 QStrList &tagFileList = Config_getList("TAGFILES");
10166 char *s=tagFileList.first();
10167 while (s)
10168 {
10169 readTagFile(root,s);
10170 root->createNavigationIndex(rootNav,g_storage,0);
10171 s=tagFileList.next();
10172 }
10173
10174 /**************************************************************************
10175 * Parse source files *
10176 **************************************************************************/
10177
10178 parseFiles(root,rootNav);
10179 g_storage->close();
10180 if (!g_storage->open(IO_ReadOnly))
10181 {
10182 err("Failed to open temporary storage file %s for reading",
10183 Doxygen::entryDBFileName.data());
10184 exit(1);
10185 }
10186
10187 //printNavTree(rootNav,0);
10188
10189 // we are done with input scanning now, so free up the buffers used by flex
10190 // (can be around 4MB)
10191 preFreeScanner();
10192 scanFreeScanner();
10193 pyscanFreeScanner();
10194
10195 //delete rootNav;
10196 //g_storage.close();
10197 //exit(1);
10198
10199 /**************************************************************************
10200 * Gather information *
10201 **************************************************************************/
10202
10203 msg("Building group list...\n");
10204 buildGroupList(rootNav);
10205 organizeSubGroups(rootNav);
10206
10207 msg("Building directory list...\n");
10208 buildDirectories();
10209 findDirDocumentation(rootNav);
10210
10211 if (Config_getBool("BUILTIN_STL_SUPPORT"))
10212 {
10213 addSTLClasses(rootNav);
10214 }
10215
10216 msg("Building namespace list...\n");
10217 buildNamespaceList(rootNav);
10218 findUsingDirectives(rootNav);
10219
10220 msg("Building file list...\n");
10221 buildFileList(rootNav);
10222 //generateFileTree();
10223
10224 msg("Building class list...\n");
10225 buildClassList(rootNav);
10226
10227 msg("Associating documentation with classes...\n");
10228 buildClassDocList(rootNav);
10229
10230 // build list of using declarations here (global list)
10231 buildListOfUsingDecls(rootNav);
10232
10233 msg("Computing nesting relations for classes...\n");
10234 resolveClassNestingRelations();
10235 distributeClassGroupRelations();
10236
10237 // calling buildClassList may result in cached relations that
10238 // become invalid after resolveClassNestingRelations(), that's why
10239 // we need to clear the cache here
10240 Doxygen::lookupCache.clear();
10241 // we don't need the list of using declaration anymore
10242 g_usingDeclarations.clear();
10243
10244 msg("Building example list...\n");
10245 buildExampleList(rootNav);
10246
10247 msg("Searching for enumerations...\n");
10248 findEnums(rootNav);
10249
10250 // Since buildVarList calls isVarWithConstructor
10251 // and this calls getResolvedClass we need to process
10252 // typedefs first so the relations between classes via typedefs
10253 // are properly resolved. See bug 536385 for an example.
10254 msg("Searching for documented typedefs...\n");
10255 buildTypedefList(rootNav);
10256
10257 msg("Searching for members imported via using declarations...\n");
10258 findUsingDeclImports(rootNav);
10259 // this should be after buildTypedefList in order to properly import
10260 // used typedefs
10261 findUsingDeclarations(rootNav);
10262
10263 msg("Searching for included using directives...\n");
10264 findIncludedUsingDirectives();
10265
10266 msg("Searching for documented variables...\n");
10267 buildVarList(rootNav);
10268
10269 msg("Building member list...\n"); // using class info only !
10270 buildFunctionList(rootNav);
10271
10272 msg("Searching for friends...\n");
10273 findFriends();
10274
10275 msg("Searching for documented defines...\n");
10276 findDefineDocumentation(rootNav);
10277
10278 findClassEntries(rootNav);
10279 msg("Computing class inheritance relations...\n");
10280 findInheritedTemplateInstances();
10281 msg("Computing class usage relations...\n");
10282 findUsedTemplateInstances();
10283
10284 msg("Flushing cached template relations that have become invalid...\n");
10285 flushCachedTemplateRelations();
10286
10287 msg("Creating members for template instances...\n");
10288 createTemplateInstanceMembers();
10289
10290 msg("Computing class relations...\n");
10291 computeTemplateClassRelations();
10292 flushUnresolvedRelations();
10293
10294 computeClassRelations();
10295
10296 if (Config_getBool("OPTIMIZE_OUTPUT_VHDL"))
10297 VhdlDocGen::computeVhdlComponentRelations();
10298
10299 g_classEntries.clear();
10300
10301 msg("Add enum values to enums...\n");
10302 addEnumValuesToEnums(rootNav);
10303 findEnumDocumentation(rootNav);
10304
10305 msg("Searching for member function documentation...\n");
10306 findObjCMethodDefinitions(rootNav);
10307 findMemberDocumentation(rootNav); // may introduce new members !
10308
10309 transferRelatedFunctionDocumentation();
10310 transferFunctionDocumentation();
10311
10312 msg("Building page list...\n");
10313 buildPageList(rootNav);
10314
10315 msg("Search for main page...\n");
10316 findMainPage(rootNav);
10317
10318 msg("Computing page relations...\n");
10319 computePageRelations(rootNav);
10320 checkPageRelations();
10321
10322 msg("Determining the scope of groups...\n");
10323 findGroupScope(rootNav);
10324
10325 msg("Sorting lists...\n");
10326 Doxygen::memberNameSDict->sort();
10327 Doxygen::functionNameSDict->sort();
10328 Doxygen::hiddenClasses->sort();
10329 Doxygen::classSDict->sort();
10330
10331 msg("Freeing entry tree\n");
10332 delete rootNav;
10333 g_storage->close();
10334 delete g_storage;
10335 g_storage=0;
10336
10337 QDir thisDir;
10338 thisDir.remove(Doxygen::entryDBFileName);
10339
10340 msg("Determining which enums are documented\n");
10341 findDocumentedEnumValues();
10342
10343 msg("Computing member relations...\n");
10344 computeMemberRelations();
10345
10346 msg("Building full member lists recursively...\n");
10347 buildCompleteMemberLists();
10348
10349 msg("Adding members to member groups.\n");
10350 addMembersToMemberGroup();
10351
10352 if (Config_getBool("DISTRIBUTE_GROUP_DOC"))
10353 {
10354 msg("Distributing member group documentation.\n");
10355 distributeMemberGroupDocumentation();
10356 }
10357
10358 msg("Computing member references...\n");
10359 computeMemberReferences();
10360
10361 if (Config_getBool("INHERIT_DOCS"))
10362 {
10363 msg("Inheriting documentation...\n");
10364 inheritDocumentation();
10365 }
10366
10367 // compute the shortest possible names of all files
10368 // without loosing the uniqueness of the file names.
10369 msg("Generating disk names...\n");
10370 Doxygen::inputNameList->generateDiskNames();
10371
10372 msg("Adding source references...\n");
10373 addSourceReferences();
10374
10375 msg("Adding xrefitems...\n");
10376 addListReferences();
10377 generateXRefPages();
10378
10379 msg("Sorting member lists...\n");
10380 sortMemberLists();
10381
10382 if (Config_getBool("SHOW_DIRECTORIES") && Config_getBool("DIRECTORY_GRAPH"))
10383 {
10384 msg("Computing dependencies between directories...\n");
10385 computeDirDependencies();
10386 }
10387
10388 msg("Counting data structures...\n");
10389 countDataStructures();
10390
10391 msg("Resolving user defined references...\n");
10392 resolveUserReferences();
10393
10394 msg("Finding anchors and sections in the documentation...\n");
10395 findSectionsInDocumentation();
10396
10397 transferFunctionReferences();
10398
10399 msg("Combining using relations...\n");
10400 combineUsingRelations();
10401
10402 msg("Adding members to index pages...\n");
10403 addMembersToIndex();
10404}
10405
10406void generateOutput()
10407{
10408 /**************************************************************************
10409 * Initialize output generators *
10410 **************************************************************************/
10411
10412 //// dump all symbols
10413 //SDict<DefinitionList>::Iterator sdi(Doxygen::symbolMap);
10414 //DefinitionList *dl;
10415 //for (sdi.toFirst();(dl=sdi.current());++sdi)
10416 //{
10417 // DefinitionListIterator dli(*dl);
10418 // Definition *d;
10419 // printf("Symbol: ");
10420 // for (dli.toFirst();(d=dli.current());++dli)
10421 // {
10422 // printf("%s ",d->qualifiedName().data());
10423 // }
10424 // printf("\n");
10425 //}
10426 if (g_dumpSymbolMap)
10427 {
10428 dumpSymbolMap();
10429 exit(0);
10430 }
10431
10432 initDocParser();
10433
10434 g_outputList = new OutputList(TRUE);
10435 if (Config_getBool("GENERATE_HTML"))
10436 {
10437 g_outputList->add(new HtmlGenerator);
10438 HtmlGenerator::init();
10439
10440 bool generateHtmlHelp = Config_getBool("GENERATE_HTMLHELP");
10441 bool generateEclipseHelp = Config_getBool("GENERATE_ECLIPSEHELP");
10442 bool generateQhp = Config_getBool("GENERATE_QHP");
10443 bool generateTreeView = Config_getBool("GENERATE_TREEVIEW");
10444 bool generateDocSet = Config_getBool("GENERATE_DOCSET");
10445 if (generateEclipseHelp) Doxygen::indexList.addIndex(new EclipseHelp);
10446 if (generateHtmlHelp) Doxygen::indexList.addIndex(new HtmlHelp);
10447 if (generateQhp) Doxygen::indexList.addIndex(new Qhp);
10448 if (generateTreeView) Doxygen::indexList.addIndex(new FTVHelp(TRUE));
10449 if (generateDocSet) Doxygen::indexList.addIndex(new DocSets);
10450 Doxygen::indexList.initialize();
10451 HtmlGenerator::writeTabData();
10452
10453#if 0
10454 if (Config_getBool("GENERATE_INDEXLOG")) Doxygen::indexList.addIndex(new IndexLog);
10455#endif
10456 //if (Config_getBool("HTML_DYNAMIC_SECTIONS")) HtmlGenerator::generateSectionImages();
10457 copyStyleSheet();
10458 copyLogo();
10459 copyExtraFiles();
10460 if (!generateTreeView && Config_getBool("USE_INLINE_TREES"))
10461 {
10462 FTVHelp::generateTreeViewImages();
10463 }
10464 }
10465 if (Config_getBool("GENERATE_LATEX"))
10466 {
10467 g_outputList->add(new LatexGenerator);
10468 LatexGenerator::init();
10469 }
10470 if (Config_getBool("GENERATE_MAN"))
10471 {
10472 g_outputList->add(new ManGenerator);
10473 ManGenerator::init();
10474 }
10475 if (Config_getBool("GENERATE_RTF"))
10476 {
10477 g_outputList->add(new RTFGenerator);
10478 RTFGenerator::init();
10479 }
10480
10481 if (Config_getBool("USE_HTAGS"))
10482 {
10483 Htags::useHtags = TRUE;
10484 QCString htmldir = Config_getString("HTML_OUTPUT");
10485 if (!Htags::execute(htmldir))
10486 err("error: USE_HTAGS is YES but htags(1) failed. \n");
10487 if (!Htags::loadFilemap(htmldir))
10488 err("error: htags(1) ended normally but failed to load the filemap. \n");
10489 }
10490
10491 /**************************************************************************
10492 * Generate documentation *
10493 **************************************************************************/
10494
10495 QFile *tag=0;
10496 QCString &generateTagFile = Config_getString("GENERATE_TAGFILE");
10497 if (!generateTagFile.isEmpty())
10498 {
10499 tag=new QFile(generateTagFile);
10500 if (!tag->open(IO_WriteOnly))
10501 {
10502 err("error: cannot open tag file %s for writing\n",
10503 generateTagFile.data()
10504 );
10505 cleanUpDoxygen();
10506 exit(1);
10507 }
10508 Doxygen::tagFile.setDevice(tag);
10509 Doxygen::tagFile << "<?xml version='1.0' encoding='ISO-8859-1' standalone='yes' ?>" << endl;
10510 Doxygen::tagFile << "<tagfile>" << endl;
10511 }
10512
10513 if (Config_getBool("GENERATE_HTML")) writeDoxFont(Config_getString("HTML_OUTPUT"));
10514 if (Config_getBool("GENERATE_LATEX")) writeDoxFont(Config_getString("LATEX_OUTPUT"));
10515 if (Config_getBool("GENERATE_RTF")) writeDoxFont(Config_getString("RTF_OUTPUT"));
10516
10517 msg("Generating style sheet...\n");
10518 //printf("writing style info\n");
10519 QCString genString =
10520 theTranslator->trGeneratedAt(dateToString(TRUE),Config_getString("PROJECT_NAME"));
10521 g_outputList->writeStyleInfo(0); // write first part
10522 g_outputList->disableAllBut(OutputGenerator::Latex);
10523 g_outputList->parseText(genString);
10524 g_outputList->writeStyleInfo(1); // write second part
10525 //parseText(*g_outputList,theTranslator->trWrittenBy());
10526 g_outputList->writeStyleInfo(2); // write third part
10527 g_outputList->parseText(genString);
10528 g_outputList->writeStyleInfo(3); // write fourth part
10529 //parseText(*g_outputList,theTranslator->trWrittenBy());
10530 g_outputList->writeStyleInfo(4); // write last part
10531 g_outputList->enableAll();
10532
10533 static bool searchEngine = Config_getBool("SEARCHENGINE");
10534 static bool serverBasedSearch = Config_getBool("SERVER_BASED_SEARCH");
10535
10536 // generate search indices (need to do this before writing other HTML
10537 // pages as these contain a drop down menu with options depending on
10538 // what categories we find in this function.
10539 if (Config_getBool("GENERATE_HTML") && searchEngine)
10540 {
10541 msg("Generating search indices...\n");
10542 QCString searchDirName = Config_getString("HTML_OUTPUT")+"/search";
10543 QDir searchDir(searchDirName);
10544 if (!searchDir.exists() && !searchDir.mkdir(searchDirName))
10545 {
10546 err("error: Could not create search results directory '%s' $PWD='%s'\n",
10547 searchDirName.data(),QDir::currentDirPath().data());
10548 exit(1);
10549 }
10550 HtmlGenerator::writeSearchData(searchDirName);
10551 if (!serverBasedSearch) // client side search index
10552 {
10553 writeJavascriptSearchIndex();
10554 }
10555 }
10556
10557 //statistics();
10558
10559 // count the number of documented elements in the lists we have built.
10560 // If the result is 0 we do not generate the lists and omit the
10561 // corresponding links in the index.
10562 msg("Generating index page...\n");
10563 writeIndex(*g_outputList);
10564
10565 msg("Generating page index...\n");
10566 writePageIndex(*g_outputList);
10567
10568 msg("Generating example documentation...\n");
10569 generateExampleDocs();
10570
10571 msg("Generating file sources...\n");
10572 if (!Htags::useHtags)
10573 {
10574 generateFileSources();
10575 }
10576
10577 msg("Generating file documentation...\n");
10578 generateFileDocs();
10579
10580 msg("Generating page documentation...\n");
10581 generatePageDocs();
10582
10583 msg("Generating group documentation...\n");
10584 generateGroupDocs();
10585
10586 msg("Generating group index...\n");
10587 writeGroupIndex(*g_outputList);
10588
10589 msg("Generating class documentation...\n");
10590 generateClassDocs();
10591
10592 if (Config_getBool("HAVE_DOT") && Config_getBool("GRAPHICAL_HIERARCHY"))
10593 {
10594 msg("Generating graphical class hierarchy...\n");
10595 writeGraphicalClassHierarchy(*g_outputList);
10596 }
10597
10598 msg("Generating namespace index...\n");
10599 generateNamespaceDocs();
10600
10601 msg("Generating namespace member index...\n");
10602 writeNamespaceMemberIndex(*g_outputList);
10603
10604 if (Config_getBool("GENERATE_LEGEND"))
10605 {
10606 msg("Generating graph info page...\n");
10607 writeGraphInfo(*g_outputList);
10608 }
10609
10610 if (Config_getBool("SHOW_DIRECTORIES"))
10611 {
10612 msg("Generating directory documentation...\n");
10613 generateDirDocs(*g_outputList);
10614 }
10615
10616 msg("Generating file index...\n");
10617 writeFileIndex(*g_outputList);
10618
10619 if (Config_getBool("SHOW_DIRECTORIES"))
10620 {
10621 msg("Generating directory index...\n");
10622 writeDirIndex(*g_outputList);
10623 }
10624
10625 msg("Generating example index...\n");
10626 writeExampleIndex(*g_outputList);
10627
10628 msg("Generating file member index...\n");
10629 writeFileMemberIndex(*g_outputList);
10630
10631
10632 //writeDirDependencyGraph(Config_getString("HTML_OUTPUT"));
10633
10634 if (Doxygen::formulaList.count()>0 && Config_getBool("GENERATE_HTML")
10635 && !Config_getBool("USE_MATHJAX"))
10636 {
10637 msg("Generating bitmaps for formulas in HTML...\n");
10638 Doxygen::formulaList.generateBitmaps(Config_getString("HTML_OUTPUT"));
10639 }
10640
10641 //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_HTMLHELP"))
10642 //{
10643 // HtmlHelp::getInstance()->finalize();
10644 //}
10645 //if (Config_getBool("GENERATE_HTML") && Config_getBool("GENERATE_TREEVIEW"))
10646 //{
10647 // FTVHelp::getInstance()->finalize();
10648 //}
10649
10650 msg("finalizing index lists...\n");
10651 Doxygen::indexList.finalize();
10652
10653 if (!Config_getString("GENERATE_TAGFILE").isEmpty())
10654 {
10655 Doxygen::tagFile << "</tagfile>" << endl;
10656 delete tag;
10657 }
10658
10659 if (Config_getBool("DOT_CLEANUP"))
10660 {
10661 if (Config_getBool("GENERATE_HTML"))
10662 removeDoxFont(Config_getString("HTML_OUTPUT"));
10663 if (Config_getBool("GENERATE_RTF"))
10664 removeDoxFont(Config_getString("RTF_OUTPUT"));
10665 if (Config_getBool("GENERATE_LATEX"))
10666 removeDoxFont(Config_getString("LATEX_OUTPUT"));
10667 }
10668
10669 if (Config_getBool("GENERATE_XML"))
10670 {
10671 msg("Generating XML output...\n");
10672 generateXML();
10673 }
10674 if (Config_getBool("GENERATE_AUTOGEN_DEF"))
10675 {
10676 msg("Generating AutoGen DEF output...\n");
10677 generateDEF();
10678 }
10679 if (Config_getBool("GENERATE_PERLMOD"))
10680 {
10681 msg("Generating Perl module output...\n");
10682 generatePerlMod();
10683 }
10684 if (Config_getBool("GENERATE_HTML") && searchEngine && serverBasedSearch)
10685 {
10686 msg("Generating search index\n");
10687 HtmlGenerator::writeSearchPage();
10688 Doxygen::searchIndex->write(Config_getString("HTML_OUTPUT")+"/search/search.idx");
10689 }
10690
10691 if (Config_getBool("GENERATE_RTF"))
10692 {
10693 msg("Combining RTF output...\n");
10694 if (!RTFGenerator::preProcessFileInplace(Config_getString("RTF_OUTPUT"),"refman.rtf"))
10695 {
10696 err("An error occurred during post-processing the RTF files!\n");
10697 }
10698 }
10699
10700 if (Config_getBool("HAVE_DOT"))
10701 {
10702 DotManager::instance()->run();
10703 }
10704
10705 if (Config_getBool("GENERATE_HTML") &&
10706 Config_getBool("GENERATE_HTMLHELP") &&
10707 !Config_getString("HHC_LOCATION").isEmpty())
10708 {
10709 msg("Running html help compiler...\n");
10710 QString oldDir = QDir::currentDirPath();
10711 QDir::setCurrent(Config_getString("HTML_OUTPUT"));
10712 portable_sysTimerStart();
10713 if (portable_system(Config_getString("HHC_LOCATION"), "index.hhp", FALSE))
10714 {
10715 err("error: failed to run html help compiler on index.hhp\n");
10716 }
10717 portable_sysTimerStop();
10718 QDir::setCurrent(oldDir);
10719 }
10720 if ( Config_getBool("GENERATE_HTML") &&
10721 Config_getBool("GENERATE_QHP") &&
10722 !Config_getString("QHG_LOCATION").isEmpty())
10723 {
10724 msg("Running qhelpgenerator...\n");
10725 QCString const qhpFileName = Qhp::getQhpFileName();
10726 QCString const qchFileName = getQchFileName();
10727
10728 QCString const args = QCString().sprintf("%s -o \"%s\"", qhpFileName.data(), qchFileName.data());
10729 QString const oldDir = QDir::currentDirPath();
10730 QDir::setCurrent(Config_getString("HTML_OUTPUT"));
10731 portable_sysTimerStart();
10732 if (portable_system(Config_getString("QHG_LOCATION"), args.data(), FALSE))
10733 {
10734 err("error: failed to run qhelpgenerator on index.qhp\n");
10735 }
10736 portable_sysTimerStop();
10737 QDir::setCurrent(oldDir);
10738 }
10739
10740
10741 if (Debug::isFlagSet(Debug::Time))
10742 {
10743 msg("Total elapsed time: %.3f seconds\n(of which %.3f seconds waiting for external tools to finish)\n",
10744 ((double)Doxygen::runningTime.elapsed())/1000.0,
10745 portable_getSysElapsedTime()
10746 );
10747 }
10748 else
10749 {
10750 msg("finished...\n");
10751 }
10752
10753 /**************************************************************************
10754 * Start cleaning up *
10755 **************************************************************************/
10756
10757 //Doxygen::symbolCache->printStats();
10758 //Doxygen::symbolStorage->printStats();
10759 cleanUpDoxygen();
10760
10761 finializeDocParser();
10762 Doxygen::symbolStorage->close();
10763 QDir thisDir;
10764 thisDir.remove(Doxygen::objDBFileName);
10765 Config::deleteInstance();
10766 QTextCodec::deleteAllCodecs();
10767 delete Doxygen::symbolCache;
10768 delete Doxygen::symbolMap;
10769 delete Doxygen::symbolStorage;
10770 g_successfulRun=TRUE;
10771}
10772
10773

Archive Download this file

Revision: 1322