Chameleon

Chameleon Svn Source Tree

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

Source at commit 1322 created 9 years 5 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(